mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Rich Felker <dalias@aerifal.cx>
To: musl@lists.openwall.com
Subject: Re: ldso: dlclose.
Date: Sun, 19 Aug 2012 20:48:03 -0400	[thread overview]
Message-ID: <20120820004803.GA27715@brightrain.aerifal.cx> (raw)
In-Reply-To: <503113C5.5010206@gmail.com>

On Sun, Aug 19, 2012 at 06:26:45PM +0200, musl wrote:
> Hi,
> 
> I noticed that the dlclose function is not implemented (always return 0).
> It might be a problem in my case cause I use dlfuncs to implement a plugin system and when I unload a plugin, the memory
> is not released.
> 
> Do you plan to implement this function ?

It is implemented. Per POSIX:

    The use of dlclose() reflects a statement of intent on the part of
    the process, but does not create any requirement upon the
    implementation, such as removal of the code or symbols referenced
    by handle.

Source:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlclose.html

To elaborate, removing a DSO from a process's address space is highly
non-trivial and error-prone. If you've spent any time reading glibc's
bug tracker, you'll find they've had a lot of nasty bugs stemming from
dlclose doing the wrong things. I don't want to recreate that kind of
bugginess. The requirements get even worse once we implement TLS.

At first, I thought it might be feasible to just support unloading of
DOSs that were loaded non-global, since there's no way their symbols
have been used to resolve references elsewhere in the program. However
there are still major ugly issues that seemingly can't be handled
correctly. Suppose for instance myplugin.so is part of your
application and intended only to be loaded/unloaded with
dlopen/dlclose, never linked directly, but it depends on libfoo.so
which was designed to be linked directly. Both will get loaded
non-globally when dlopen is called on myplugin.so, but libfoo.so might
do things that are incompatible with later being unloaded -- for
example, registering an atexit function. You can try to solve this
issue with __cxa_atexit and DSO handles but that only covers a special
case. The library might instead have registered its atexit function
through code in a third library, or it might not even be directly
registering an atexit function but instead a cleanup function that
some other library will call directly during its own cleanup routines,
or even registered pointers to functions or data within libfoo.so with
an interface in another library that's not doing to be unloaded at the
same time.

What it comes down to is that it's never safe to unload a library that
was not designed to be unloadable. As such, the maximum possible
unloading we could ever safely support is unloading only the dlopen'd
library itself and never any of its dependencies; but even that's not
entirely safe since some programs will directly dlopen libraries that
were not designed to be loaded and unloaded.

Also, note that all of the above is purely the fundamental issues that
make unloading a bad idea; I haven't even touched on all the things
that are easy to get wrong in the implementation, leading to race
conditions and crashes in the dynamic linker itself.

In summary, I don't see any way to make a correct implementation where
dlclose actually unloads stuff. If you have ideas for how to do it,
please explain; I'm not against doing it, but only if it can be done
correctly.

> BTW I think there is a bug in the '__funcs_on_exit' (atexit.c) : only the first non null function of each function pool
> is called.

I'll take a look...

> Something like this should do the trick.
> 
> void __funcs_on_exit()
> {
>     int i;
>     void (*func)(void *), *arg;
>     LOCK(lock);
>     for (; head; head=head->next) {
>         for (i=COUNT-1; i>=0 && !head->f[i]; i--);
>         if (i<0) continue;
>         for (; i>=0; i--) {
>             func = head->f[i];
>             arg = head->a[i];
>             head->f[i] = 0;
>             UNLOCK(lock);
>             func(arg);
>             LOCK(lock);
>         }
>     }
> }

You're right. Thanks for the catch! I've fixed it slightly differently
(avoiding two separate loops over the array).

Rich


  reply	other threads:[~2012-08-20  0:48 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-19 16:26 musl
2012-08-20  0:48 ` Rich Felker [this message]
2012-08-22 22:41   ` Rich Felker
2012-08-23 12:39   ` Arvid E. Picciani
2012-08-23 12:48     ` Rich Felker
2012-08-23 16:02       ` orc
2012-08-23 18:01         ` Rich Felker
2012-08-24  7:52           ` musl
2012-08-24 12:27             ` Rich Felker
2012-08-24 13:54               ` musl
2012-08-24 17:46                 ` Rich Felker
2012-08-25  7:54                   ` boris brezillon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120820004803.GA27715@brightrain.aerifal.cx \
    --to=dalias@aerifal.cx \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).