Pergunta

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

Construa e corra:

>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 que teststatic :: ~ testStatic chamado em 'exit ()', mas não em 'dlclose ()'?

Foi útil?

Solução

O padrão C ++ exige que os destruidores sejam chamados a objetos globais quando um programa sai na ordem oposta de construção. A maioria das implementações lidou com isso chamando a rotina ATEXIT da biblioteca C para registrar os destruidores. Isso é problemático porque o padrão de 1999 C exige apenas que a implementação suportasse 32 funções registradas, embora a maioria das implementações suporta muito mais. Mais importante, ele não lida com a habilidade na maioria das implementações de remover os DSOs de uma imagem de programa em execução, ligando para o DLCLOSE antes do término do programa.

Esse problema é abordado em versões posteriores do GCC, incluindo biblioteca padrão e linker C/C ++. Basicamente, os destruidores de C ++ devem ser registrados usando __cxa_atexit função em vez de atexit (3).

Para os detalhes técnicos completos sobre __cxa_atexit, Vejo Especificação Itanium C ++ ABI.


Não está claro na sua pergunta qual versão do GCC, Linker e Standard C Library você está usando. Além disso, o código que você forneceu não atende Posix padrão como não há RTDL_NOW ou RTDL_LOCAL macros definidos. Eles são RTLD_NOW e RTLD_LOCAL (Vejo Dlopen).

Se sua biblioteca padrão C não suportar __cxa_atexit, você pode precisar desativá -lo especificando -fno-use-cxa-atexit Bandeira do GCC:

-Fuse-CXA-ATEXIT

Registre os destruidores para objetos com duração de armazenamento estático com a função __cxA_ ATEXIT em vez da função ATEXIT. Esta opção é necessária para o manuseio totalmente compatível com os destruidores estáticos, mas só funcionará se sua biblioteca C suportar __cxa_atexit.

Mas isso pode resultar em um problema em que os destruidores são chamados em ordem diferente ou não. Portanto, a melhor solução em caso de quebra __cxa_atexit O suporte ou nenhum suporte não é usar objetos estáticos com destruidores em suas bibliotecas compartilhadas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top