【问题标题】:dlclose() does not call the destructor of global objectsdlclose() 不调用全局对象的析构函数
【发布时间】:2011-04-18 03:10:09
【问题描述】:

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

为什么在 'exit()' 而不是在 'dlclose()' 调用 TestStatic::~TestStatic?

【问题讨论】:

标签: c++ dll gcc dlopen atexit


【解决方案1】:

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_NOWRTDL_LOCAL 宏。它们是RTLD_NOWRTLD_LOCAL(参见dlopen)。

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

-fuse-cxa-atexit

为具有静态存储的对象注册析构函数 __cxa_ atexit 的持续时间 函数而不是 atexit 功能。此选项是必需的 完全符合标准的处理 静态析构函数,但只会工作 如果你的 C 库支持 __cxa_atexit。

但这可能会导致析构函数以不同的顺序调用或根本不调用的问题。因此,如果__cxa_atexit 支持中断或根本不支持,最好的解决方案是不要在共享库中使用带有析构函数的静态对象。

【讨论】:

    猜你喜欢
    • 2016-11-25
    • 2018-08-11
    • 2013-05-23
    • 2011-01-11
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    相关资源
    最近更新 更多