dlclose () не вызывает деструктор глобальных объектов - PullRequest
22 голосов
/ 28 сентября 2010

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

сборка и запуск:

>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

почему TestStatic :: ~ TestStatic вызывается в 'exit () 'но не в' dlclose () '?

1 Ответ

16 голосов
/ 28 сентября 2010

Стандарт C ++ требует, чтобы деструкторы вызывались для глобальных объектов при выходе из программы в обратном порядке построения. Большинство реализаций обрабатывает это, вызывая подпрограмму atexit библиотеки C для регистрации деструкторов. Это проблематично, поскольку стандарт C 1999 года требует только того, чтобы реализация поддерживала 32 зарегистрированных функции, хотя большинство реализаций поддерживают гораздо больше. Более важно то, что в большинстве реализаций вообще отсутствует возможность удалять DSO из образа работающей программы, вызывая dlclose перед завершением программы.

Эта проблема решается в более поздних версиях GCC, включая стандартную библиотеку C / C ++ и компоновщик. По сути, деструкторы C ++ должны быть зарегистрированы с использованием функции __cxa_atexit вместо atexit (3).

Для получения полной информации о __cxa_atexit см. Спецификация Itanium C ++ ABI .


Из вашего вопроса не ясно, какую версию gcc, linker и стандартной библиотеки C вы используете. Кроме того, предоставленный вами код не соответствует стандарту POSIX , поскольку не определены макросы RTDL_NOW или RTDL_LOCAL. Это RTLD_NOW и RTLD_LOCAL (см. dlopen ).

Если ваша стандартная библиотека C не поддерживает __cxa_atexit, вам может потребоваться отключить ее, указав -fno-use-cxa-atexit gcc flag:

-fuse-CXA-atexit

Регистрация деструкторов для объектов со статическим хранилищем продолжительность с __cxa_ atexit функция, а не Atexit функция. Эта опция необходима для полностью совместимая со стандартами обработка статические деструкторы, но будут работать только если ваша библиотека C поддерживает __cxa_atexit.

Но это может привести к проблеме, когда деструкторы вызываются в другом порядке или не вызываются вообще. Таким образом, лучшее решение в случае неработающей поддержки __cxa_atexit или ее отсутствия вообще - не использовать статические объекты с деструкторами в общих библиотеках.

...