This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: dlclose() doesn't unload any .so that uses Boost
- From: Pavel Tolkachev <paultolk at yahoo dot com>
- To: gcc-help at gcc dot gnu dot org, J <j at jabster dot pl>
- Date: Mon, 30 May 2011 12:12:24 -0700 (PDT)
- Subject: Re: dlclose() doesn't unload any .so that uses Boost
- Reply-to: paulTolk at yahoo dot com
--- On Sun, 5/29/11, J <j@jabster.pl> wrote:
> From: J <j@jabster.pl>
> Subject: dlclose() doesn't unload any .so that uses Boost
> To: gcc-help@gcc.gnu.org
> Date: Sunday, May 29, 2011, 3:32 AM
> Hi.
>
> First, I would like to apologize if this isn't in any way
> related to
> GCC, however I don't know anywhere else where I can turn
> to. Please
> consider the following code:
>
> // host.cpp
> // compile with: g++ -ldl host.cpp -o host
> #include <stdio.h>
> #include <dlfcn.h>
>
> int main( int argc, char ** argv )
> {
> ? ? printf( "host: Loading libchild.so...\n" );
> ? ? void * so = dlopen( "./libchild.so",
> RTLD_LOCAL | RTLD_NOW );
> ? ? printf( "host: so = %p\n", so );
>
> ? ? if( so == 0 ) return 1;
>
> ? ? printf( "host: Unloading libchild.so...\n"
> );
> ? ? if( dlclose( so ) != 0 )
> ? ? {
> ? ? ? ? printf( "host: Error: %s\n",
> dlerror() );
> ? ? ? ? return 1;
> ? ? }
> ? ? printf( "host: Unloaded.\n" );
> ? ? printf( "host: %p\n", dlopen(
> "./libchild.so", RTLD_NOLOAD ) );
>
> ? ? return 0;
> }
>
> // child.cpp
> // compile with: g++ -lboost_signals child.cpp -shared
> -fPIC -o libchild.so
> #include <stdio.h>
> #include <boost/signals.hpp>
>
> struct foobar_t
> {
> ? ? boost :: signal< void () > signal;
> };
>
> void? __attribute__ ( ( constructor ) ) ctor()
> {
> ? ? foobar_t foobar;
>
> ? ? printf( "child: Constructor\n" );
> }
>
> void? __attribute__ ( ( destructor ) ) dtor()
> {
> ? ? printf( "child: Destructor\n" );
> }
>
>
> This is the output I get:
>
> host: Loading libchild.so...
> child: Constructor
> host: so = 0x94b6020
> host: Unloading libchild.so...
> host: Unloaded.
> host: (nil)
> child: Destructor
>
> As you can see, dlclose() doesn't properly unload the .so,
> even though
> it claims that it has done so.
It actually doesn't. It just confirms there were one or more references counts to the library and it decreased their count by 1 (see man dlclose). I think you can achieve same effect by defining any global object with non-trivial destructor in the library, not necessarily a boost::signal.
On remediation side, if you are comfortable with the client code's explicitly calling dlclose() anyway, why don't you allocate your signal object in free storage via operator new and call something like MyDlclose() (or childClose()) instead of it where you would first delete this object (and all others of the kind) and then call dlclose()? This won't increase the degree of client code cooperation needed to use your library.
> If you'll remove this line:
>
> boost :: signal< void () > signal;
>
> it works properly:
>
> host: Loading libchild.so...
> child: Constructor
> host: so = 0x8f6f020
> host: Unloading libchild.so...
> child: Destructor
> host: Unloaded.
> host: (nil)
>
> It took me a while to track this down. Now, my question is
> - is this a
> bug? If so, in what? In GCC? (I tried this with both 4.5
> and 4.6) In
> the dynamic linker? In Boost? If not - why? And how would I
> fix this?
> Any insight in greatly appreciated.
>
> Thanks.
>
Hope this helps,
-Pavel