c++ - herencia - dlclose() no llama al destructor de objetos globales
objetos en c (1)
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;
}
construir 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
¿Por qué TestStatic :: ~ TestStatic llamó a ''exit ()'' pero no a ''dlclose ()''?
El Estándar de C ++ requiere que los destructores sean llamados para objetos globales cuando un programa sale en el orden opuesto de construcción. 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 aborda en versiones posteriores de GCC, incluida la biblioteca estándar y el enlazador C / C ++. Básicamente, los destructores de C ++ deben registrarse usando la función __cxa_atexit
lugar de atexit
(3).
Para obtener todos los detalles técnicos sobre __cxa_atexit
, consulte la especificación Itanium C ++ ABI .
No está claro a partir de 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 RTDL_LOCAL
macros RTDL_NOW
ni RTDL_LOCAL
definidos. Son RTLD_NOW
y RTLD_LOCAL
(ver dlopen ).
Si su biblioteca estándar C no admite __cxa_atexit
, puede necesitar deshabilitarla especificando -fno-use-cxa-atexit
gcc flag:
-fuse-cxa-atexit
Registre destructores para objetos con duración de almacenamiento estático con la función __cxa_ atexit en lugar de la función atexit. Esta opción es necesaria para el manejo completo 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 son llamados 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.