Подтвердить что ты не робот

Dlclose() не вызывает деструктор глобальных объектов

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()'?

4b9b3361

Ответ 1

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

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

Подробную техническую информацию о __cxa_atexit см. в спецификации Itanium С++ ABI.


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

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

-fuse-CXA-atexit

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

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