Global/Static variables initialization issue with __attribute__((constructor)) in shared library
我在共享库中使用
以下是代码片段:
shared.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | struct MyStruct { MyStruct(int s = 1) : s(s) { printf("%s, this: %p, s=%d ", __func__, this, s); } ~MyStruct() { printf("%s, this: %p, s=%d ", __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 ", &s1, &s2, &s3); printf("s1: %p, s2: %p, s3: %p ", s1, s2.get(), s3.get()); printf("s4: %p, s4.s: %d ", &s4, s4.s); } extern"C" void foo() { printf("&s1: %p, &s2: %p, &s3: %p ", &s1, &s2, &s3); printf("s1: %p, s2: %p, s3: %p ", s1, s2.get(), s3.get()); printf("s4: %p, s4.s: %d ", &s4, s4.s); } |
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <cstdio> #include <dlfcn.h> using Foo = void(*)(void); int main() { printf("Calling dlopen... "); void* h = dlopen("./libshared.so", RTLD_NOW | RTLD_GLOBAL); Foo f = reinterpret_cast<Foo>(dlsym(h,"foo")); printf(" Calling foo()... "); f(); return 0; } |
编译与
1 2 | $ g++ -fPIC -shared -std=c++14 shared.cpp -o libshared.so $ g++ -std=c++14 -o main main.cpp -ldl |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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.get() 应该是0x121b220 ,但是在foo() 中它变成nullptr ; -
s4 的值在onLoad() 中显示为s4.s: 2 ,但是在调用其构造函数后,其默认值为s=1 ,然后在foo() 中其值为s=1 。
将变量放入匿名名称空间具有相同的结果。
我的操作系统:Ubuntu 16.04.2,GCC:5.4.0
根据有关此GCC错误报告和此后续文档补丁的讨论,您似乎看到的是GCC中未指定的行为(不是错误)。
However, the order in which constructors for C++ objects with static storage duration and functions decorated with attribute
constructor are invoked is unspecified. In mixed declarations, attributeinit_priority can be used to impose a specific ordering.
在这种情况下,似乎可以避免分段错误,因为分配给未初始化的
无论如何,要纠正此问题,您确实确实需要使用