https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71971
Bug ID: 71971 Summary: Destructor of a global static variable in a shared library is not called on dlclose Product: gcc Version: 4.9.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: jeremyaouad at gmail dot com Target Milestone: --- In a main program, I dlopen and dlclose (LoadLibrary and FreeLibrary respectively) a shared library. The shared library contains a static variable that is instantiated upon dlopen, and destroyed upon dlclose. This behavior is consistent on MSVC 2008 and 2013, GCC 3.4.6, and Sunstudio 12.1. With GCC 4.4.7, GCC 4.9.1 and GCC 5.2.1 (only ones I tested) however, the destructor was no longer called on dlclose. Instead, it was called before program exit. The particularity of the static variable's class, is that in the constructor, there is a call to a templated function "get" (of global scope) that returns a local static variable. I was able to reproduce this behavior with the following one cpp file linked into a shared library: #include <iostream> template <typename T> // In my actual code, i is of type T, however, this has no effect int get() { static int i = 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 the tweaks that can be made in order to have the destructor called on dlclose, and concluded the following: - If the function "get" was not templated - else if the variable i in the function "get" was not static - else if the function "get" is made static The main program's code is the 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 the binaries with the 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 I get when the destructor is called before program exit is the following: Calling Constructor DLL unloaded Calling Destructor The output I get when the destructor is called on dlclose is the following: Calling Constructor Calling Destructor DLL unloaded Before launching main.out, run: export LD_LIBRARY=dir_location_of_dll:$LD_LIBRARY_PATH where dir_location_of_dll is the location of libdll.so GCC Compilers used: - g++34 (GCC) 3.4.6 20060404 (Red Hat 3.4.6-19.el6) - g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3) - g++491 (GCC) 4.9.1 20140922 (Red Hat 4.9.1-10) - g++ (GCC) 5.2.1 20150902 (Red Hat 5.2.1-2) Machine used: - Linux Red Hat 2.6.32-358.el6.x86_64