本文介绍了共享库中带有__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 =新的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> 使用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(); 返回0; } 已编译 $ g ++ -fPIC -shared -std = c ++ 14 shared.cpp -o libshared.so $ g ++ -std = c ++ 14 -o main main.cpp -ldl 输出: 正在调用dlopen ... MyStruct,这个:0x121b200,s = 1 MyStruct,这个:0x121b220,s = 1 MyStruct,这个:0x121b240,s = 1 MyStruct,这:0x7ffc19736910,s = 2 〜MyStruct,这:0x7ffc19736910,s = 2 & s1:0x7fb1fe487190,& s2:0x7fb1fe487198,& s1:0x7a s1:0x121b200,s2:0x121b220,s3:0x121b240 s4:0x7fb1fe4871a8,s4.s:2 MyStruct,this:0x7fb1fe4871a8,s = 1 调用foo()... & s1:0x7fb1fe487190,& s2:0x7fb1fe487198,& s3:0x7fb1fe4871a0 s1:0x121b200,s2:(nil),s3:0x121b240 s4 0x7fb1fe4871a8,s4.s:1 〜MyStruct,这:0x7fb1fe4871a8,s = 1 〜MyStruct,这:0x121b240,s = 1 s1 和 但是 s2 和 s4 表现很奇怪。 s2.get()应该为 0x121b220 ,但是在 foo()中,它变为 nullptr ; s4 的值显示为 s4.s:2 onLoad()中的code>,但是之后使用默认值 s = 1 调用其构造函数,然后在 foo()中,其值为 s = 1 。 将变量放入匿名名称空间中会得到相同的结果。 s2怎么了和 s4 ? 我的操作系统:Ubuntu 16.04.2,GCC:5.4.0 解决方案根据此GCC错误报告和此后续文档tch ,看来您看到的是GCC中未指定的行为(不是bug)。 但是,顺序未指定使用静态存储持续时间的C ++对象的构造函数以及用属性 constructor 装饰的函数的构造函数。在混合声明中,属性 init_priority 可用于施加特定顺序。 在这种情况下,似乎避免了段错误,因为分配给未初始化的 std :: unique_ptr 可能导致 delete 为未初始化的指针成员调用。根据C ++规范,GCC的未指定行为会转换为未定义的行为(在这种情况下),因为它是从未初始化的变量读取的未定义的行为(未初始化的未签名字符除外)。 无论如何,要纠正此问题,您确实需要使用 __ attribute((init_priority))在构造函数之前命令初始化静态声明的对象。 I meet an issue with global/static variables' initialization with __attribute__((constructor)) in shared library, that certain variables seem to be initialized twice.Below are code snippets:shared.cppstruct 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;}Compiled with$ g++ -fPIC -shared -std=c++14 shared.cpp -o libshared.so$ g++ -std=c++14 -o main main.cpp -ldlThe output:Calling dlopen...MyStruct, this: 0x121b200, s=1MyStruct, this: 0x121b220, s=1MyStruct, this: 0x121b240, s=1MyStruct, this: 0x7ffc19736910, s=2~MyStruct, this: 0x7ffc19736910, s=2&s1: 0x7fb1fe487190, &s2: 0x7fb1fe487198, &s3: 0x7fb1fe4871a0s1: 0x121b200, s2: 0x121b220, s3: 0x121b240s4: 0x7fb1fe4871a8, s4.s: 2MyStruct, this: 0x7fb1fe4871a8, s=1Calling foo()...&s1: 0x7fb1fe487190, &s2: 0x7fb1fe487198, &s3: 0x7fb1fe4871a0s1: 0x121b200, s2: (nil), s3: 0x121b240s4: 0x7fb1fe4871a8, s4.s: 1~MyStruct, this: 0x7fb1fe4871a8, s=1~MyStruct, this: 0x121b240, s=1The value of s1 and s3 are expected.But s2 and s4 behave weird.s2.get() should be 0x121b220, but in foo() it becomes nullptr;s4's value is printed as s4.s: 2 in onLoad(), but after that its constructor is called with default value s=1, then in foo() its value is s=1.Putting the variables in anonymous namespace has the same result.What's wrong with s2 and s4?My OS: Ubuntu 16.04.2, GCC: 5.4.0 解决方案 As per the discussion on this GCC bug report and this follow-up doc patch it seems that what you're seeing is unspecified behavior in GCC (not a bug). 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, attribute init_priority can be used to impose a specific ordering.It seems in this case that a segfault was narrowly avoided, as assigning to an uninitialized std::unique_ptr could cause delete to be invoked for an uninitialized pointer member. GCC's unspecified behavior translates into undefined behavior (in this particular case) according to the C++ specification, because it's undefined behavior to read from an uninitialized variable (except for an uninitialized unsigned char).Anyway, to correct this problem you do indeed need to use __attribute((init_priority)) to order initialization of your statically-declared objects before the constructor function. 这篇关于共享库中带有__attribute __((constructor))的全局/静态变量初始化问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-12 19:06