2010-09-28 18 views
20

plugin1.cpp:dlclose() no llama al destructor de objetos globales

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

generar y ejecutar:

>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 

qué TestStatic :: ~ TestStatic llamado a 'exit()' pero no a 'dlclose()'?

+0

Buena pregunta: +1. – Chubsdad

+2

¿Esto es útil? http://forum.soft32.com/linux2/dlclose-causing-segmentation-fault-exit-main-ftopict10002.html – Chubsdad

+0

opción -fno-use-cxa-atexit para la compilación plugin.cpp resuelve el problema – AndryBlack

Respuesta

15

El estándar C++ requiere que se invoquen destructores para objetos globales cuando un programa sale en el orden de construcción opuesto. La mayoría de las implementaciones han manejado esto llamando a la rutina atexit de la biblioteca C para registrar los destructores. Esto es problemático porque el Estándar C de 1999 solo requiere que la implementación soporte 32 funciones registradas, aunque la mayoría de las implementaciones admiten muchas más. Más importante aún, no trata en absoluto con la capacidad en la mayoría de las implementaciones de eliminar DSO de una imagen de programa en ejecución llamando a dlclose antes de la finalización del programa.

Este problema se trata en las versiones posteriores de GCC, incluida la biblioteca estándar de C/C++ y el enlazador. Básicamente, los destructores de C++ deben registrarse utilizando la función __cxa_atexit en lugar de atexit (3).

Para los detalles técnicos completos en __cxa_atexit, ver Itanium C++ ABI specification.


No está claro por su pregunta qué versión de la biblioteca gcc, linker y C estándar está utilizando. Además, el código que ha proporcionado no cumple con el estándar POSIX ya que no hay macros RTDL_NOW o RTDL_LOCAL definidos. Son RTLD_NOW y RTLD_LOCAL (ver dlopen).

Si la biblioteca estándar de C no soporta __cxa_atexit, es posible que tenga que desactivarlo mediante la especificación de la bandera -fno-use-cxa-atexit gcc:

-fuse-cxa-atexit

destructores Registro de objetos con almacenamiento estático duración con la función __cxa_ atexit en lugar de la función atexit . Esta opción es necesaria para el manejo totalmente conforme con las normas de los destructores estáticos , pero solo funcionará si su biblioteca C admite __cxa_atexit.

Pero eso puede dar como resultado un problema donde los destructores son llamados en diferente orden o no se llaman en absoluto. Por lo tanto, la mejor solución en caso de soporte roto __cxa_atexit o no soporte en absoluto es no usar objetos estáticos con destructores en sus bibliotecas compartidas.

Cuestiones relacionadas