23

plugin1.cpp:

#include <iostream>

static class TestStatic {
public:
  TestStatic() {
     std::cout << "TestStatic create" << std::endl;
  }
  ~TestStatic() {
     std::cout << "TestStatic destroy" << std::endl;
  }
} test_static;

ホスト.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 が「dlclose()」ではなく「exit()」で呼び出されるのはなぜですか?

4

1 に答える 1

16

C ++標準では、プログラムが逆の構築順序で終了するときに、グローバルオブジェクトに対してデストラクタを呼び出す必要があります。ほとんどの実装では、Cライブラリのatexitルーチンを呼び出してデストラクタを登録することでこれを処理しています。1999 C標準では、実装が32の登録済み関数をサポートすることだけが要求されているため、これは問題がありますが、ほとんどの実装はさらに多くの関数をサポートします。さらに重要なことに、ほとんどの実装では、プログラムの終了前にdlcloseを呼び出して、実行中のプログラムイメージからDSOを削除する機能をまったく処理していません。

この問題は、C /C++標準ライブラリとリンカを含むGCCの新しいバージョンで対処されています。基本的に、C ++デストラクタは(3)__cxa_atexitの代わりに関数を使用して登録する必要があります。atexit

の完全な技術的詳細については__cxa_atexitItanium C++ABI仕様を参照してください。


質問から、使用しているgcc、リンカー、および標準Cライブラリのバージョンは明確ではありません。さらに、マクロが定義されていないため、提供したコードはPOSIX標準を満たしていません。それらはとです(dlopenを参照)。RTDL_NOWRTDL_LOCALRTLD_NOWRTLD_LOCAL

C標準ライブラリがをサポートしていない場合は、 gccフラグ__cxa_atexitを指定して無効にする必要があります。-fno-use-cxa-atexit

-fuse-cxa-atexit

静的ストレージ期間を持つオブジェクトのデストラクタを、atexit関数ではなく__cxa_atexit関数で登録します。このオプションは、静的デストラクタを完全に標準に準拠して処理するために必要ですが、Cライブラリが__cxa_atexitをサポートしている場合にのみ機能します。

ただし、デストラクタが異なる順序で呼び出されるか、まったく呼び出されないという問題が発生する可能性があります。したがって、サポートが壊れ__cxa_atexitているか、サポートがまったくない場合の最善の解決策は、共有ライブラリのデストラクタで静的オブジェクトを使用しないことです。

于 2010-09-28T16:38:13.617 に答える