dlclose()不调用全局对象的析构函数 [英] dlclose() does not call the destructor of global objects

查看:354
本文介绍了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创建
>分段错误

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

解决方案


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


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



有关 __ cxa_atexit 的完整技术细节,请参阅 Itanium C ++ ABI规范






从您的问题不清楚是什么版本的您正在使用的gcc,链接器和标准C库。此外,您提供的代码不符合 POSIX 标准,因为没有 RTDL_NOW RTDL_LOCAL 定义宏。他们是 RTLD_NOW RTLD_LOCAL (见 dlopen )。



如果您的C标准库不支持 __ cxa_atexit ,则可能需要通过指定 -fno-use-cxa-atexit gcc标志:


-fuse-cxa-atexit

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


但是这可能会导致一个问题,其中析构函数以不同的顺序调用或根本不调用。所以在破坏的 __ cxa_atexit 支持或根本不支持的情况下,最好的解决方案是不要在共享库中使用具有析构函数的静态对象。


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;
}

build and run:

>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

why TestStatic::~TestStatic called at 'exit()' but not at 'dlclose()' ?

解决方案

The C++ Standard requires that destructors be called for global objects when a program exits in the opposite order of construction. Most implementations have handled this by calling the C library atexit routine to register the destructors. This is problematic because the 1999 C Standard only requires that the implementation support 32 registered functions, although most implementations support many more. More important, it does not deal at all with the ability in most implementations to remove DSOs from a running program image by calling dlclose prior to program termination.

This problem is addressed in later versions of GCC including C/C++ standard library and linker. Basically, C++ destructors should be registered using __cxa_atexit function instead of atexit (3).

For the full technical details on __cxa_atexit, see Itanium C++ ABI specification.


It is not clear from your question what version of the gcc, linker and standard C library you are using. Plus, the code you have provided does not meet POSIX standard as there are no RTDL_NOW or RTDL_LOCAL macros defined. They are RTLD_NOW and RTLD_LOCAL (see dlopen).

If your C standard library does not support __cxa_atexit, you may need to disable it by specifying -fno-use-cxa-atexit gcc flag:

-fuse-cxa-atexit

Register destructors for objects with static storage duration with the __cxa_ atexit function rather than the atexit function. This option is required for fully standards-compliant handling of static destructors, but will only work if your C library supports __cxa_atexit.

But that might result in a problem where destructors are called in different order or not called at all. So the best solution in case of broken __cxa_atexit support or no support at all is not to use static objects with destructors in your shared libraries.

这篇关于dlclose()不调用全局对象的析构函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆