dlclose() doesn't unload any .so that uses Boost
Pavel Tolkachev
paultolk@yahoo.com
Tue May 31 05:49:00 GMT 2011
--- On Mon, 5/30/11, J <j@jabster.pl> wrote:
> From: J <j@jabster.pl>
> Subject: Re: dlclose() doesn't unload any .so that uses Boost
> To: paulTolk@yahoo.com
> Cc: gcc-help@gcc.gnu.org
> Date: Monday, May 30, 2011, 11:56 PM
> On Mon, May 30, 2011 at 9:12 PM,
> Pavel Tolkachev <paultolk@yahoo.com>
> wrote:
> > 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).
>
> Yes, I've read man dlclose:
>
> "If the same library is loaded again with dlopen(), the
> same file
> handle is returned. The dl library maintains reference
> counts for
> library handles, so a dynamic library is not deallocated
> until
> dlclose() has been called on it as many times as dlopen()
> has
> succeeded on it."
>
> I'm only calling dlopen() once and boost doesn't call
> dlopen() at all,
> so following this manpage my dlclose() should close the
> library. If
> the refcount can be increased by something else then maybe
> this
> manpage needs updating?
>
> Besides, RTLD_NOLOAD paragraph states this:
>
> "This can be used to test if the library is already
> resident (dlopen()
> returns NULL if it is not, or the library's handle if it
> is
> resident)."
>
> While library is clearly still resident dlopen( RTLD_NOLOAD
> ) returns
> NULL; another bug either in the code or in the manpage.
>
> > 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.
>
> Unfortunately, this doesn't work, e.g. this is enough to
> make a .so
> impossible unload:
>
> delete ( new boost :: signal< void () > );
>
> Oh and, I've just noticed that this code doesn't really
> even have to
> run. Consider:
>
> // child.cpp
> // compile with: g++ -lboost_signals child.cpp -shared
> -fPIC -o libchild.so
> #include <stdio.h>
> #include <boost/signals.hpp>
>
> void __attribute__ ( ( constructor ) ) ctor()
> {
> printf( "child: Constructor\n" );
> }
>
> void __attribute__ ( ( destructor ) ) dtor()
> {
> printf( "child: Destructor\n" );
> }
>
> void a_function_that_does_not_get_called()
> {
> new boost :: signal< void () >();
> }
>
> The result:
>
> host: Loading libchild.so...
> child: Constructor
> host: so = 0x8938020
> host: Unloading libchild.so...
> host: Unloaded.
> host: (nil)
> child: Destructor
>
> This pretty much looks like a bug to me.
I admit I spoke too soon, assumed before actually trying your code. After I have tried (both 1st and 2nd versions), the code gave different output to me:
host: Loading libchild.so...
child: Constructor
host: so = 0x8db4020
host: Unloading libchild.so...
child: Destructor
host: Unloaded.
host: (nil)
Which seems correct (dlclose() calls the dtor()). I used
gcc version 4.4.5
libdl-2.12.1.so
boost 1.45.0
Linux kernel 2.6.35-28
libc-2.12.1.so
Hope this helps,
-Pavel
>
> Thanks.
>
More information about the Gcc-help
mailing list