in main program, dlopen , dlclose (loadlibrary , freelibrary respectively) shared library. shared library contains static variable instantiated upon dlopen, , destroyed upon dlclose. behavior consistent on msvc 2008 , 2013, gcc 3.4.6, , sunstudio 12.1. gcc 4.9.1 , gcc 5.2.1 however, destructor no longer called on dlclose. instead, called before program exit.
the particularity of static variable's class, in constructor, there call templated function get (of global scope) returns local static variable.
i able reproduce behavior following 1 cpp file linked shared library:
#include <iostream> template <typename t> // in actual code, of type t, however, has no effect int get() { static int = 0; return i; } class dictionary { public: dictionary() { std::cout << "calling constructor" << std::endl; get<int>(); } ~dictionary(){ std::cout << "calling destructor" << std::endl; } private: dictionary(const dictionary&); dictionary& operator=(const dictionary&); }; static dictionary d;
i investigated tweaks can made in order have destructor called on dlclose, , concluded following:
- if function get not templated
- else if variable in function get not static
- else if function get made static
the main program's code following:
#include <dlfcn.h> #include <cassert> #include <string> #include <iostream> void* loadlib(std::string name) { void* libinstance; name = "lib" + name + ".so"; libinstance = dlopen(name.c_str(), rtld_now); if ( ! libinstance ) std::cout << "loading of dictionary library failed. reason: " << dlerror() << std::endl; return libinstance; } bool unloadlib(void* libinstance) { int ret = dlclose(libinstance); if (ret == -1) { std::cout << "unloading of dictionary library failed. reason: " << dlerror() << std::endl; return false; } return true; } int main() { void* instance = loadlib("dll"); assert(instance != 0); assert(unloadlib(instance)); std::cout << "dll unloaded" << std::endl; }
i built binaries following commands:
g++ -m64 -g -std=c++11 -shared -fpic dll.cpp -o libdll.so g++ -m64 -g -std=c++11 -ldl main.cpp -o main.out
the output when destructor called before program exit following:
calling constructor dll unloaded calling destructor
the output when destructor called on dlclose following:
calling constructor calling destructor dll unloaded
questions:
- if change of behavior between versions of gcc not bug, can please explain why destructor not called on dlclose?
- can please explain each tweak: why destructor called on dlclose in case?
there no guarantee unloading (destructors invoked) happens on dlclose. on musl (as opposed glibc), constructors run first time library run, , destructors run on exit. portable code, dlclose cannot assumed unload symbols immediately.
the unload behavior depends on glibc's symbol binding when doing dynamic linking, , independent of gcc.
the static variable get::i has stb_gnu_unique binding. static variables in inline functions, uniqueness of object assured elf linker. however, dynamic loading, dynamic linker assures uniqueness marking symbol stb_gnu_unique. hence, attempt dlopen same shared library other code lookup symbol , find unique , return existent 1 unique symbols table. symbol unique binding cannot unloaded.
unique binding can disabled "-fno-gnu-unique" if not needed.
references
Comments
Post a Comment