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()'但不调用'dlclose()'?
答案 0 :(得分:16)
当程序以相反的构造顺序退出时,C ++标准要求为全局对象调用析构函数。大多数实现都通过调用C库atexit例程来注册析构函数来处理这个问题。这是有问题的,因为1999 C标准只要求实现支持32个注册函数,尽管大多数实现支持更多。更重要的是,它完全没有处理大多数实现中通过在程序终止之前调用dlclose从正在运行的程序映像中删除DSO的能力。
此问题在GCC的更高版本中得到解决,包括C / C ++标准库和链接器。基本上,C ++析构函数应该使用__cxa_atexit
函数而不是atexit
(3)进行注册。
有关__cxa_atexit
的完整技术详情,请参阅Itanium C++ ABI specification。
从您的问题中不清楚您正在使用的gcc,链接器和标准C库的版本。此外,您提供的代码不符合POSIX标准,因为未定义RTDL_NOW
或RTDL_LOCAL
个宏。它们是RTLD_NOW
和RTLD_LOCAL
(请参阅dlopen)。
如果您的C标准库不支持__cxa_atexit
,您可能需要通过指定-fno-use-cxa-atexit
gcc标志来禁用它:
- 保险丝-CXA-atexit对
为具有静态存储的对象注册析构函数 使用__cxa_ atexit的持续时间 功能而不是atexit 功能。此选项是必需的 完全符合标准的处理 静态析构函数,但只会起作用 如果您的C库支持 __cxa_atexit。
但是这可能会导致以不同的顺序调用析构函数或根本不调用析构函数的问题。因此,在__cxa_atexit
支持损坏或根本不支持的情况下,最佳解决方案是不要在共享库中使用具有析构函数的静态对象。