[Bug c++/71971] New: Destructor of a global static variable in a shared library is not called on dlclose

jeremyaouad at gmail dot com gcc-bugzilla@gcc.gnu.org
Fri Jul 22 14:04:00 GMT 2016


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


More information about the Gcc-bugs mailing list