2010-09-28 9 views
20

plugin1.cpp:dlclose() non chiama il distruttore di oggetti globali

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

costruire e gestire:

>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 

perché TestStatic :: ~ TestStatic chiamato a 'exit()' ma non a 'dlclose()'?

+0

Buona domanda: +1. – Chubsdad

+2

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

+0

option -fno-use-cxa-atexit per la compilazione plugin.cpp risolva problema – AndryBlack

risposta

15

Lo standard C++ richiede che i distruttori vengano richiamati per oggetti globali quando un programma esce nell'ordine opposto di costruzione. La maggior parte delle implementazioni ha gestito ciò chiamando la routine Atexit della libreria C per registrare i distruttori. Ciò è problematico perché lo Standard C 1999 richiede solo che il supporto all'implementazione 32 funzioni registrate, sebbene molte implementazioni supportino molte di più. Ancora più importante, non si occupa affatto della capacità nella maggior parte delle implementazioni di rimuovere i DSO da un'immagine del programma in esecuzione chiamando dlclose prima della chiusura del programma.

Questo problema viene risolto nelle versioni successive di GCC, inclusi la libreria standard e il linker C/C++. Fondamentalmente, i distruttori C++ dovrebbero essere registrati usando la funzione __cxa_atexit invece di atexit (3).

Per i dettagli tecnici completi su __cxa_atexit, vedere Itanium C++ ABI specification.


Non è chiaro dalla tua domanda quale versione del gcc, linker e la libreria standard C che si sta utilizzando. Inoltre, il codice fornito non soddisfa lo standard POSIX in quanto non sono definiti macro RTDL_NOW o RTDL_LOCAL. Sono RTLD_NOW e RTLD_LOCAL (vedere dlopen).

Se la libreria standard C non supporta __cxa_atexit, potrebbe essere necessario disabilitarlo specificando bandiera -fno-use-cxa-atexit gcc:

-fuse-CXA-atexit

distruttori Registra per gli oggetti con archiviazione statica durata con la funzione __cxa_ atexit invece della funzione atexit . Questa opzione è richiesta per la gestione conforme allo standard dei distruttori statici , ma funzionerà solo se la libreria C supporta __cxa_atexit.

Ma ciò potrebbe causare un problema in cui i distruttori vengono chiamati in ordine diverso o non vengono chiamati affatto. Quindi la migliore soluzione in caso di supporto rotto __cxa_atexit o nessun supporto è di non usare oggetti statici con distruttori nelle tue librerie condivise.

Problemi correlati