2010-09-28 149 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或根本不支持的最佳解決方案不是在共享庫中使用具有析構函數的靜態對象。