dlclose()不调用全局对象的击振子
题
plugin1.cpp:
#include <iostream>
static class TestStatic {
public:
TestStatic() {
std::cout << "TestStatic create" << std::endl;
}
~TestStatic() {
std::cout << "TestStatic destroy" << std::endl;
}
} test_static;
host.cpp
#include <dlfcn.h>
#include <iostream>
int main(int argc,char *argv[]) {
void* handle = dlopen("./plugin1.so",RTLD_NOW | RTLD_LOCAL );
dlclose(handle);
return 0;
}
构建和运行:
>g++ -c plugin1.cpp -o plugin1.o -fPIC
>g++ -shared plugin.o -o plugin1.so
>g++ host.cpp -o host -ldl
>./host
>TestStatic create
>Segmentation fault
为什么testStatic :: 〜teststatic在'exit()''in dlclose()''in teststatic中命名为“ exit()”?
解决方案
C ++标准要求当程序以相反的施工顺序退出时,要求驱动器进行全局对象。大多数实现都通过调用C库Abexit例程来注册驱动器来处理此操作。这是有问题的,因为1999 C标准仅要求实施支持32个注册功能,尽管大多数实施支持更多。更重要的是,它根本不涉及大多数实施中通过在程序终止之前调用DLClose从运行程序图像中删除DSO的能力。
在以后的GCC版本中解决了此问题,包括C/C ++标准库和链接器。基本上,应使用C ++破坏者进行注册 __cxa_atexit
功能而不是 atexit
(3).
有关完整的技术细节 __cxa_atexit
, , 看 ITANIUM C ++ ABI规范.
从您的问题中尚不清楚您正在使用哪个版本的GCC,Linker和标准C库。另外,您提供的代码不符合 posix 标准是没有 RTDL_NOW
或者 RTDL_LOCAL
宏定义。他们是 RTLD_NOW
和 RTLD_LOCAL
(看 dlopen).
如果您的C标准库不支持 __cxa_atexit
, ,您可能需要通过指定将其禁用 -fno-use-cxa-atexit
GCC标志:
-fuse-cxa-atexit
注册带有静态存储持续时间的对象的破坏者,带有__CXA_ AEDEXIT函数,而不是AtexIT函数。对于完全符合标准的静态破坏者的处理,需要此选项,但仅当您的C库支持__cxa_atexit时才能使用。
但这可能会导致一个问题,即破坏者以不同的顺序调用或根本不调用。因此,在破裂的情况下,最好的解决方案 __cxa_atexit
支持或根本没有支持是不将静态对象与您的共享库中的破坏者一起使用。