I'm working on a cross-platform project which consists on several libraries, dynamically loading and unloading one another depending on run-time conditions. Currently I observe a crash which seems to be caused by the fact that static objects in one of the shared libraries are destroyed before the shared library is unloaded with dlclose(). This seems pretty strange and more like a bug to me.
To investigate the problem I've created a simple project, which consists of three source files: main.cpp, lib1.cpp and lib2.cpp (for executable and two libraries respectively). The main executable dynamically loads lib1, and lib1 in turn dynamically loads 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
is a simple struct which just logs in its constructor and destructor. libutil::AutoLib
is a shared library loader which calls dlopen(path, RTLD_LAZY)
in its ctor, and calls dlclose()
in its dtor, and allows to call functions exported from a shared library. The code for those classes is trivial, but I can post it here as well if needed.
Long story short, if I call main executable, I see the following log:
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
Please note the lib2Global dtor
line going before the Calling dlclose(0x14cd710)
line.
So the question is, is it a bug or correct behavior?
There are questions here in SO about static objects not being destroyed after dlclose()
, but I did not find any questions about somewhat the opposite situation.
I'm using GCC 5.4.0-6ubuntu1~16.04.10.