Mikhail Teterin
2003-02-04 15:46:13 UTC
[Moved to -arch]
On Tuesday 04 February 2003 03:26 am, Alfred Perlstein wrote:
= * Wes Peters <***@softweyr.com> [030203 23:41] wrote:
= > On Mon, 2003-02-03 at 18:58, Mikhail Teterin wrote:
= > > There remains an unresolved issue with mplayer on FreeBSD -- some
= > > of the libraries it dlopens and dlcloses are calling atexit() in
= > > between with their own functions.
= > >
= > > This causes SEGFAULTs in exit(), which tries to call those
= > > functions. The application catches the signals and would not quit
= > > until SIGKILL-ed.
= > >
= > > This does not affect Linux, where, reportedly, calls to atexit()
= > > are treated differently if made from dlopened code. I'm not sure
= > > how best to fix this (Call _exit()? Remove signal handlers before
= > > exit()?), but something needs to be done...
= > I think ideally we'd want dlclose to be able to deinstall any
= > atexit handlers that were installed by library functions. The
= > most straight- forward path to this I can see is an atexit-remove
= > call that can be passed a start and end address and will remove
= > any function references found between the two. dlclose could call
= > this function with the start and end addresses of the library text
= > segment to remove any exit handlers in the library code space.
= > I can probably take a look at this later in the week if this seems
= > like a reasonable approach.
= Please see if you can emulate the glibc behaviour just to ease
= porting. I think that means you must actually call the atexit handler,
= not just deregister it.
Last time I brought this up, it was not clear, what The Right Thing to
do is. Are these details mandatated by some standard out there, or is
everyone on their own, and we should, indeed, do what Linux does, to not
increase the enthropy?
Should, for example, exit handlers, which will still be valid after the
dlclose() still be called at dlclose() or at the actual exit()? How
about atexit() calls made between dlopen() and dlclose(), and not by the
library but by the application, or by another library? Have each library
get its own list of exit-handlers?
Or should it still be a global list, but examined by both dlclose()
and exit() -- if an item on the list is about to become invalid after
dlclose() (how can we know, BTW?), have dlclose() call it -- otherwise,
leave it alone?
That is what Solaris is doing, apparently. From their atexit(3c)
The atexit() function registers the function pointed to by
func to be called without arguments on normal termination of
the program or when the object defining the function is
unloaded.
[...]
On process exit, functions are called in the reverse order
of their registration. On object unloading, any functions
belonging to an unloadable object are called in the reverse
order of their registration.
The Solaris' approach seems the most robust. The Linux' one fails,
when the exit handler belongs to another library. Attached are two
files, which illustrate this -- even if somewhat artificially.
. the main program dlopens two libraries (both built from
the same source);
. it then passes the library number (integer) -- for reporting,
and the address of the handler _found in the other library_
to each one;
. the libraries both register each other's functions as handlers;
. the application unloads both libraris.
On FreeBSD both libraries are quietly unloaded, and the application
SEGFAULTs in exit(). On Linux, the crash happens at the second unload,
which tries to call the handler from the first library. On Solaris
everything runs to completion, which -- unless it violates some standard --
makes it the most appealing implementation (hostnames edited out):
[...] 5.0-CURRENT FreeBSD 5.0-CURRENT #0: Wed Jan 8 19:15:03 EST 2003
[....]
Loading the libraries
./l0.so loaded as 0x28064200
./l1.so loaded as 0x28064300
Library 0 calling atexit(0x2813a6f0)
Library 1 calling atexit(0x281386f0)
Unloading the libraries
0x28064200 unloaded
0x28064300 unloaded
Libraries unloaded. Returning
Segmentation fault
Linux [...] 2.4.18-14 #1 Wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
Loading the libraries
./l0.so loaded as 0x8049ad0
./l1.so loaded as 0x8049e00
Library 0 calling atexit(0x40016788)
Library 1 calling atexit(0x40014788)
Unloading the libraries
Exit handler 0x40016788 of library 1 is invoked
0x8049ad0 unloaded
Segmentation fault (core dumped)
SunOS [...] 5.8 Generic_108528-13 sun4u sparc SUNW,Sun-Fire-280R
Loading the libraries
./l0.so loaded as ff3a1458
./l1.so loaded as ff3a17b8
Library 0 calling atexit(ff260380)
Library 1 calling atexit(ff350380)
Unloading the libraries
Exit handler ff350380 of library 0 is invoked
ff3a1458 unloaded
Exit handler ff260380 of library 1 is invoked
ff3a17b8 unloaded
Libraries unloaded. Returning
Yet another plan would be to have the atexit() call simply increase the
ref-count of the library a handler is from, so it will not actually be
unloaded by dlclose(). But that will be yet another implementation...
-mi
On Tuesday 04 February 2003 03:26 am, Alfred Perlstein wrote:
= * Wes Peters <***@softweyr.com> [030203 23:41] wrote:
= > On Mon, 2003-02-03 at 18:58, Mikhail Teterin wrote:
= > > There remains an unresolved issue with mplayer on FreeBSD -- some
= > > of the libraries it dlopens and dlcloses are calling atexit() in
= > > between with their own functions.
= > >
= > > This causes SEGFAULTs in exit(), which tries to call those
= > > functions. The application catches the signals and would not quit
= > > until SIGKILL-ed.
= > >
= > > This does not affect Linux, where, reportedly, calls to atexit()
= > > are treated differently if made from dlopened code. I'm not sure
= > > how best to fix this (Call _exit()? Remove signal handlers before
= > > exit()?), but something needs to be done...
= > I think ideally we'd want dlclose to be able to deinstall any
= > atexit handlers that were installed by library functions. The
= > most straight- forward path to this I can see is an atexit-remove
= > call that can be passed a start and end address and will remove
= > any function references found between the two. dlclose could call
= > this function with the start and end addresses of the library text
= > segment to remove any exit handlers in the library code space.
= > I can probably take a look at this later in the week if this seems
= > like a reasonable approach.
= Please see if you can emulate the glibc behaviour just to ease
= porting. I think that means you must actually call the atexit handler,
= not just deregister it.
Last time I brought this up, it was not clear, what The Right Thing to
do is. Are these details mandatated by some standard out there, or is
everyone on their own, and we should, indeed, do what Linux does, to not
increase the enthropy?
Should, for example, exit handlers, which will still be valid after the
dlclose() still be called at dlclose() or at the actual exit()? How
about atexit() calls made between dlopen() and dlclose(), and not by the
library but by the application, or by another library? Have each library
get its own list of exit-handlers?
Or should it still be a global list, but examined by both dlclose()
and exit() -- if an item on the list is about to become invalid after
dlclose() (how can we know, BTW?), have dlclose() call it -- otherwise,
leave it alone?
That is what Solaris is doing, apparently. From their atexit(3c)
The atexit() function registers the function pointed to by
func to be called without arguments on normal termination of
the program or when the object defining the function is
unloaded.
[...]
On process exit, functions are called in the reverse order
of their registration. On object unloading, any functions
belonging to an unloadable object are called in the reverse
order of their registration.
The Solaris' approach seems the most robust. The Linux' one fails,
when the exit handler belongs to another library. Attached are two
files, which illustrate this -- even if somewhat artificially.
. the main program dlopens two libraries (both built from
the same source);
. it then passes the library number (integer) -- for reporting,
and the address of the handler _found in the other library_
to each one;
. the libraries both register each other's functions as handlers;
. the application unloads both libraris.
On FreeBSD both libraries are quietly unloaded, and the application
SEGFAULTs in exit(). On Linux, the crash happens at the second unload,
which tries to call the handler from the first library. On Solaris
everything runs to completion, which -- unless it violates some standard --
makes it the most appealing implementation (hostnames edited out):
[...] 5.0-CURRENT FreeBSD 5.0-CURRENT #0: Wed Jan 8 19:15:03 EST 2003
[....]
Loading the libraries
./l0.so loaded as 0x28064200
./l1.so loaded as 0x28064300
Library 0 calling atexit(0x2813a6f0)
Library 1 calling atexit(0x281386f0)
Unloading the libraries
0x28064200 unloaded
0x28064300 unloaded
Libraries unloaded. Returning
Segmentation fault
Linux [...] 2.4.18-14 #1 Wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
Loading the libraries
./l0.so loaded as 0x8049ad0
./l1.so loaded as 0x8049e00
Library 0 calling atexit(0x40016788)
Library 1 calling atexit(0x40014788)
Unloading the libraries
Exit handler 0x40016788 of library 1 is invoked
0x8049ad0 unloaded
Segmentation fault (core dumped)
SunOS [...] 5.8 Generic_108528-13 sun4u sparc SUNW,Sun-Fire-280R
Loading the libraries
./l0.so loaded as ff3a1458
./l1.so loaded as ff3a17b8
Library 0 calling atexit(ff260380)
Library 1 calling atexit(ff350380)
Unloading the libraries
Exit handler ff350380 of library 0 is invoked
ff3a1458 unloaded
Exit handler ff260380 of library 1 is invoked
ff3a17b8 unloaded
Libraries unloaded. Returning
Yet another plan would be to have the atexit() call simply increase the
ref-count of the library a handler is from, so it will not actually be
unloaded by dlclose(). But that will be yet another implementation...
-mi