공유 라이브러리에서 __attribute__((constructor))
으로 전역/정적 변수를 초기화 할 때 특정 변수가 두 번 초기화되는 것으로 보이는 문제가 발생합니다.공유 라이브러리에서 __attribute __ ((constructor))와의 전역/정적 변수 초기화 문제
shared.cpp
struct MyStruct
{
MyStruct(int s = 1)
: s(s) {
printf("%s, this: %p, s=%d\n", __func__, this, s);
}
~MyStruct() {
printf("%s, this: %p, s=%d\n", __func__, this, s);
}
int s;
};
MyStruct* s1 = nullptr;
std::unique_ptr<MyStruct> s2 = nullptr;
std::unique_ptr<MyStruct> s3;
MyStruct s4;
void onLoad() __attribute__((constructor));
void onLoad()
{
s1 = new MyStruct;
s2 = std::make_unique<MyStruct>();
s3 = std::make_unique<MyStruct>();
s4 = MyStruct(2);
printf("&s1: %p, &s2: %p, &s3: %p\n", &s1, &s2, &s3);
printf("s1: %p, s2: %p, s3: %p\n", s1, s2.get(), s3.get());
printf("s4: %p, s4.s: %d\n", &s4, s4.s);
}
extern "C" void foo()
{
printf("&s1: %p, &s2: %p, &s3: %p\n", &s1, &s2, &s3);
printf("s1: %p, s2: %p, s3: %p\n", s1, s2.get(), s3.get());
printf("s4: %p, s4.s: %d\n", &s4, s4.s);
}
MAIN.CPP
#include <cstdio>
#include <dlfcn.h>
using Foo = void(*)(void);
int main()
{
printf("Calling dlopen...\n");
void* h = dlopen("./libshared.so", RTLD_NOW | RTLD_GLOBAL);
Foo f = reinterpret_cast<Foo>(dlsym(h, "foo"));
printf("\nCalling foo()...\n");
f();
return 0;
}
$ g++ -fPIC -shared -std=c++14 shared.cpp -o libshared.so
$ g++ -std=c++14 -o main main.cpp -ldl
컴파일 : 아래
는 코드 조각입니다
출력 : s1
와 s3
의 값은 예상되는
Calling dlopen...
MyStruct, this: 0x121b200, s=1
MyStruct, this: 0x121b220, s=1
MyStruct, this: 0x121b240, s=1
MyStruct, this: 0x7ffc19736910, s=2
~MyStruct, this: 0x7ffc19736910, s=2
&s1: 0x7fb1fe487190, &s2: 0x7fb1fe487198, &s3: 0x7fb1fe4871a0
s1: 0x121b200, s2: 0x121b220, s3: 0x121b240
s4: 0x7fb1fe4871a8, s4.s: 2
MyStruct, this: 0x7fb1fe4871a8, s=1
Calling foo()...
&s1: 0x7fb1fe487190, &s2: 0x7fb1fe487198, &s3: 0x7fb1fe4871a0
s1: 0x121b200, s2: (nil), s3: 0x121b240
s4: 0x7fb1fe4871a8, s4.s: 1
~MyStruct, this: 0x7fb1fe4871a8, s=1
~MyStruct, this: 0x121b240, s=1
.
그러나 s2
및 s4
은 이상한 행동을 보입니다.
s2.get()
하면0x121b220
수 있지만foo()
에서 그것은nullptr
된다한다;s4
의 값은onLoad()
에s4.s: 2
로 인쇄되어 있지만, 생성자가 기본 값s=1
불려 그 후, 다음에foo()
그 값은s=1
입니다.
변수를 익명 네임 스페이스에 넣는 것은 동일한 결과를 가져옵니다.
s2
과 s4
의 문제점은 무엇입니까?
내 OS : 우분투 16.04.2, GCC : 5.4.0
아무 것도 "초기화되지 않았습니다"라는 두 가지 증거가 보이지 않습니다 –
ctor/dtor 호출 시퀀스는'onLoad()'가 호출되기 전에's4'가 생성 된 적이없는 것처럼 보이지만 이후에 생성됩니다. 처음 세 개의 ctor 호출은 힙 할당에서 가져온 것입니다. 네 번째는 임시 MyStruct (2)이고 다음의 dtor 호출은 일시적으로 삭제됩니다. 's4'에 대한 기본 ctor 호출은 없으며 마지막'printf()'까지입니다. 참 이상합니다. 그것은 아마도 s4.s가 1이되는 이유 일 것입니다. – cdhowie
@BoundaryImposition 그래, 그래서 내가 말하는 것 같아. * 난 잘 모르겠다. 예를 들어's4'는 두 번 구성되어 있거나 구성하기 전에 사용 된 것입니다. 그러면 구성됩니다. – Mine