|
Message-ID: <20120820004803.GA27715@brightrain.aerifal.cx> Date: Sun, 19 Aug 2012 20:48:03 -0400 From: Rich Felker <dalias@...ifal.cx> To: musl@...ts.openwall.com Subject: Re: ldso: dlclose. 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
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.