Я работаю над кроссплатформенным проектом, который состоит из нескольких библиотек, динамически загружающих и выгружающих друг друга в зависимости от условий выполнения. В настоящее время я наблюдаю сбой, который, по-видимому, вызван тем, что статические объекты в одной из разделяемых библиотек уничтожаются до того, как разделяемая библиотека выгружается с помощью dlclose (). Это кажется довольно странным и больше похоже на ошибку.
Чтобы исследовать проблему, я создал простой проект, который состоит из трех исходных файлов: main.cpp, lib1.cpp и lib2.cpp (для исполняемого файла и двух библиотек соответственно). Основной исполняемый файл динамически загружает lib1, а lib1, в свою очередь, динамически загружает lib2.
main.cpp:
Logger mainGlobal("mainGlobal");
int main(int argc, char * argv[])
{
Logger mainFunction("mainFunction");
try
{
Logger mainTry("mainTry");
libutil::AutoLib lib("lib1");
lib.call("loadLib2");
}
catch (std::exception & e)
{
std::cerr << "Fatal: " << e.what() << std::endl;
}
std::cout << "Exiting main" << std::endl;
}
lib1.cpp:
Logger lib1Global("lib1Global");
std::auto_ptr<libutil::AutoLib> lib2;
DLL_EXPORT void loadLib2()
{
std::cout << "loadLib2" << std::endl;
lib2.reset(new libutil::AutoLib("lib2"));
}
lib2.cpp:
Logger lib2Global("lib2Global");
Logger
- это простая структура, которая просто регистрирует свой конструктор и деструктор. libutil::AutoLib
- это загрузчик разделяемой библиотеки, который вызывает dlopen(path, RTLD_LAZY)
в своем ctor, и вызывает dlclose()
в своем dtor, и позволяет вызывать функции, экспортированные из разделяемой библиотеки. Код для этих классов тривиален, но я могу опубликовать его здесь, если это необходимо.
Короче говоря, если я вызываю основной исполняемый файл, я вижу следующий журнал:
mainGlobal ctor
mainFunction ctor
mainTry ctor
Loading library lib1.so
lib1Global ctor
dlopen(lib1.so) returned 0x14cd050
Library lib1.so loaded with handle 0x14cd050
Calling loadLib2 in library 0x14cd050
loadLib2
Loading library lib2.so
lib2Global ctor
dlopen(lib2.so) returned 0x14cd710
Library lib2.so loaded with handle 0x14cd710
Unloading library 0x14cd050
Calling dlclose(0x14cd050)
Library unloaded 0x14cd050
mainTry dtor
Exiting main
mainFunction dtor
lib2Global dtor
Unloading library 0x14cd710
Calling dlclose(0x14cd710)
Library unloaded 0x14cd710
lib1Global dtor
mainGlobal dtor
Обратите внимание, что строка lib2Global dtor
идет перед строкой Calling dlclose(0x14cd710)
.
Итак, вопрос в том, является ли это ошибкой или правильным поведением?
Здесь, в SO, есть вопросы о том, что статические объекты не разрушаются после dlclose()
, но я не нашел вопросов о несколько противоположной ситуации.
Я использую GCC 5.4.0-6ubuntu1 ~ 16.04.10.