This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

dlclose() with zero references does not call library destructor


Hi,

The following plugin code loads fine from a client with dlopen() and
the RTLD_NOW flag. The library constructor is called. The problem
happens when i call dlclose() on the handle. It gives status zero,
meaning that it was successful. But the library destructor
library_fini is not called.


please consider the following code for a dynamic loaded library built
with g++-4.7 on linux, -fPIC and linked with -rdynamic option:




typedef std::vector< SomeData* > cbRegister_t;


struct Wrapper

{

    cbRegister_t instance;

    Wrapper() : instance() { HDebugLog("Wrapper CTOR!");}

    ~Wrapper() { HDebugLog("Wrapper DESTRUCTOR!"); }

};

inline cbRegister_t& getLibraryUnregisterMap()

{

    static Wrapper unregisterLibraryMap;

    HDebugLog("getLibraryUnregisterMap: we have "
<<unregisterLibraryMap.instance.size() << " elements. the address of
the map is " << &unregisterLibraryMap.instance);

    return unregisterLibraryMap.instance;

}


void registerLibrary(void* p)

{

  auto& map = getLibraryUnregisterMap();

  map.push_back(p);

}


void unregisterLibrary()

{

  auto& map = getLibraryUnregisterMap();

}


void __attribute__ ((constructor)) library_init()

{

  static SomeData cbContainer;

  HDebugLog("Library constructor: address of static cbContainer is: "
<< &cbContainer );

  registerLibrary( &cbContainer);

}

void __attribute__ ((destructor)) library_fini()

{ unregisterLibrary(); }




dlopen is called on a single place so the reference count should not
be a problem, but in order to be absolutely sure that there are really
no references dangling i tried doing the dlclose several times:


int result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: closing library: " << libraryPath);

HDebugLog("Library::dynamicLibraryClose: dlclose 1 failed with error:
" << result << " => " );

result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: dlclose 2 failed with error:
" << result << " => " );

result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: dlclose 3 failed with error:
" << result << " => " );

result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: dlclose 4 failed with error:
" << result << " => " );

result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: dlclose 5 failed with error:
" << result << " => " );

result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: dlclose 6 failed with error:
" << result << " => ");

result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: dlclose 7 failed with error:
" << result << " => ");

result = dlclose(handle);

HDebugLog("Library::dynamicLibraryClose: dlclose 8 failed with error:
" << result << " => " );

HAssertMsg( !libraryPath.empty(), "library path is not set");

HAssertMsg( 0 == dlopen(libraryPath.c_str(), RTLD_NOLOAD) , "library
is still resident!");


All those debug logs show that each time i call dlclose the status
result is zero. Success!

The last assertion, which doesn't fail, confirms that the library is
not resident anymore . But at this point library_fini has not been
called yet!

This behavior clearly is not what the standard says, because library
destructors should be guaranteed to be run if the reference count is
zero before dlclose returns.

quote from dlopen man page:

Instead,    libraries    should    export    routines     using     the

       __attribute__((constructor))  and  __attribute__((destructor)) function

       attributes.   See  the  gcc  info  pages  for  information  on   these.

       Constructor   routines   are  executed  before  dlopen()  returns,  and

       destructor routines are executed before dlclose() returns.



I've ask this in several places on the web, but all seems to suggest
that this issue is happening at g++/glibc level.

Is this a bug or a simple misunderstanding from my part?


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]