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

StackOverflow https://stackoverflow.com/questions/3810157

  •  25-09-2019
  •  | 
  •  

Вопрос

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 называется «Выход ()», но не на «DLCLOSE ()»?

Это было полезно?

Решение

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

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

Для полной технической детали на __cxa_atexit, видеть Спецификация Itanium C ++ ABI.


Из вашего вопроса не ясно, какая версия GCC, линкера и стандартной библиотеки C использует. Плюс, код, который вы предоставили, не соответствует Поставка стандарт, так как нет RTDL_NOW или RTDL_LOCAL Макросы определены. Они есть RTLD_NOW а также RTLD_LOCAL (видеть ДЛОПЕН).

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

-FUSE-CXA-ATEXIT

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top