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 называется «Выход ()», но не на «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
Поддержка или поддержка вообще не использовать статические объекты с деструкторами в ваших общих библиотеках.