2010-09-28 150 views
20

plugin1.cpp的析构函数:dlclose()不会调用全局对象

#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

好问题:+1。 – Chubsdad 2010-09-28 06:29:42

+2

对您有帮助吗? http://forum.soft32.com/linux2/dlclose-causing-segmentation-fault-exit-main-ftopict10002.html – Chubsdad 2010-09-28 06:31:52

+0

选项-fno-use-cxa-atexit用于编译plugin.cpp解决问题 – AndryBlack 2010-09-28 07:00:12

回答

15

C++标准要求在程序以相反的构造顺序退出时调用全局对象的析构函数。大多数实现通过调用C库atexit例程来注册析构函数来处理这个问题。这是有问题的,因为1999 C标准只要求实现支持32个注册函数,尽管大多数实现支持更多。更重要的是,在大多数实现中,通过在程序终止之前调用dlclose来从正在运行的程序映像中删除DSO,它根本没有处理这种能力。

此问题在GCC的后续版本中得到解决,包括C/C++标准库和链接器。基本上,应该使用__cxa_atexit函数而不是atexit(3)注册C++析构函数。

有关__cxa_atexit的完整技术细节,请参见Itanium C++ ABI specification


从您的问题中不清楚您使用的是哪个版本的gcc,链接器和标准C库。另外,您提供的代码不符合POSIX标准,因为没有定义RTDL_NOWRTDL_LOCAL宏。它们是RTLD_NOWRTLD_LOCAL(见dlopen)。

如果你的C标准库不支持__cxa_atexit,你可能需要通过指定-fno-use-cxa-atexit GCC标志来禁用它:

- 保险丝-CXA-atexit对

注册析构函数与静态存储 对象持续时间与__cxa_ atexit 函数相比,而不是atexit 函数。对于 静态析构函数完全符合标准的处理,此选项是必需的,但如果您的C库支持 __cxa_atexit,将仅适用于 。

但是,这可能会导致一个问题,其中析构函数按不同顺序调用或根本不调用。因此,支持破解__cxa_atexit或根本不支持的最佳解决方案不是在共享库中使用具有析构函数的静态对象。