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 create
>Segmentation fault
なぜtestStatic :: 〜TESTSTATICは「exit()」で「dlclose()」ではそうではありませんか?
解決
C ++標準では、プログラムが反対の建設順に終了すると、グローバルオブジェクトに対してデストラクタを呼び出す必要があります。ほとんどの実装は、CライブラリAtexitルーチンを呼び出してデストラクタを登録することにより、これを処理しています。 1999年のC規格では、実装が32の登録機能をサポートすることのみが必要なため、これは問題です。ほとんどの実装はさらに多くをサポートしています。さらに重要なことは、プログラム終了の前にDLCloseを呼び出すことにより、実行中のプログラム画像からDSOを削除するほとんどの実装では、ほとんどの実装ではまったく対処していないことです。
この問題は、C/C ++標準ライブラリとリンカーを含むGCCの後のバージョンで対処されています。基本的に、C ++デストラクタを使用して登録する必要があります __cxa_atexit
の代わりに関数 atexit
(3).
完全な技術的な詳細については __cxa_atexit
, 、 見る イタニウム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
ATEXIT関数ではなく、__CXA_ ATEXIT関数を使用して、静的ストレージ期間のオブジェクトにデストラクタを登録します。このオプションは、静的デストラクタの完全な標準に準拠した取り扱いに必要ですが、Cライブラリが__CXA_ATEXITをサポートしている場合にのみ機能します。
しかし、それは破壊者が異なる順序で呼び出されるか、まったく呼ばれない問題をもたらすかもしれません。したがって、壊れた場合の最良の解決策 __cxa_atexit
サポートまたはサポートがまったくないことは、共有ライブラリにデストラクタを備えた静的オブジェクトを使用しないことです。