2010-09-28 9 views
20

plugin1.cpp:dlclose() nie wywołać destruktor globalnych obiektów

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

zbudować i uruchomić:

>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 

dlaczego TestStatic :: ~ TestStatic wywołał w "exit()", ale nie w "dlclose()"?

+0

Dobre pytanie: +1. – Chubsdad

+2

Czy to pomocne? http://forum.soft32.com/linux2/dlclose-causing-segmentation-fault-exit-main-ftopict10002.html – Chubsdad

+0

opcja -fno-use-cxa-atexit dla kompilacji plugin.cpp rozwiązuje problem – AndryBlack

Odpowiedz

15

Standard C++ wymaga, aby destruktory były wywoływane dla obiektów globalnych, gdy program wychodzi w przeciwnej kolejności konstrukcji. Większość implementacji radzi sobie z tym poprzez wywoływanie procedury atexit biblioteki C w celu zarejestrowania destruktorów. Jest to problematyczne, ponieważ norma z 1999 r. Wymaga tylko, aby wsparcie implementacji było rejestrowane 32, chociaż większość implementacji obsługuje znacznie więcej. Co ważniejsze, w większości implementacji nie ma możliwości usunięcia obiektów DSO z działającego obrazu programu przez wywołanie dlclose przed zakończeniem programu.

Ten problem rozwiązano w późniejszych wersjach GCC, w tym w standardowej bibliotece C/C++ i łączu. Zasadniczo destruktory C++ powinny być rejestrowane przy użyciu funkcji __cxa_atexit zamiast atexit (3).

Aby uzyskać pełne informacje techniczne na temat __cxa_atexit, patrz: Itanium C++ ABI specification.


Z twojego pytania nie wynika, która wersja gcc, linker i standardowej biblioteki C używasz. Ponadto podany kod nie spełnia standardu POSIX, ponieważ nie zdefiniowano makr RTDL_NOW lub RTDL_LOCAL. Są to: RTLD_NOW i RTLD_LOCAL (patrz dlopen).

Jeśli standard C biblioteki nie obsługuje __cxa_atexit, może trzeba go wyłączyć poprzez określenie -fno-use-cxa-atexit gcc flag

-fuse-CXA-atexit

Rejestracja destruktorów dla obiektów z pamięci statycznej czas trwania z funkcją __cxa_ atexit , a nie funkcją atexit . Ta opcja jest wymagana do obsługi statycznych destruktorów zgodnych ze standardami , ale działa tylko , jeśli biblioteka C obsługuje __cxa_atexit.

Ale może to spowodować problem, w którym destruktory są wywoływane w różnej kolejności lub w ogóle nie są wywoływane. Najlepszym rozwiązaniem w przypadku zepsutej pomocy __cxa_atexit lub braku wsparcia w ogóle nie jest używanie statycznych obiektów z destruktorami w twoich wspólnych bibliotekach.

Powiązane problemy