diff options
author | kib <kib@FreeBSD.org> | 2010-08-23 15:38:02 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2010-08-23 15:38:02 +0000 |
commit | df9bc4850f3a6aef289d53c0c3d1fc78d63bdda2 (patch) | |
tree | 509be3ad57df8011e952d3da4691f43abd346d2e /lib/libc/stdlib | |
parent | 7ca1c6f40abcb8550b7bbf0c67ceb3a73d93b342 (diff) | |
download | FreeBSD-src-df9bc4850f3a6aef289d53c0c3d1fc78d63bdda2.zip FreeBSD-src-df9bc4850f3a6aef289d53c0c3d1fc78d63bdda2.tar.gz |
On shared object unload, in __cxa_finalize, call and clear all installed
atexit and __cxa_atexit handlers that are either installed by unloaded
dso, or points to the functions provided by the dso.
Use _rtld_addr_phdr to locate segment information from the address of
private variable belonging to the dso, supplied by crtstuff.c. Provide
utility function __elf_phdr_match_addr to do the match of address against
dso executable segment.
Call back into libthr from __cxa_finalize using weak
__pthread_cxa_finalize symbol to remove any atfork handler which
function points into unloaded object.
The rtld needs private __pthread_cxa_finalize symbol to not require
resolution of the weak undefined symbol at initialization time. This
cannot work, since rtld is relocated before sym_zero is set up.
Idea by: kan
Reviewed by: kan (previous version)
MFC after: 3 weeks
Diffstat (limited to 'lib/libc/stdlib')
-rw-r--r-- | lib/libc/stdlib/atexit.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c index a7a9a32..97cf234 100644 --- a/lib/libc/stdlib/atexit.c +++ b/lib/libc/stdlib/atexit.c @@ -37,6 +37,7 @@ static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include <link.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> @@ -147,6 +148,9 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) return (error); } +#pragma weak __pthread_cxa_finalize +void __pthread_cxa_finalize(const struct dl_phdr_info *); + /* * Call all handlers registered with __cxa_atexit for the shared * object owning 'dso'. Note: if 'dso' is NULL, then all remaining @@ -155,18 +159,28 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) void __cxa_finalize(void *dso) { + struct dl_phdr_info phdr_info; struct atexit *p; struct atexit_fn fn; - int n; + int n, has_phdr; + + if (dso != NULL) + has_phdr = _rtld_addr_phdr(dso, &phdr_info); + else + has_phdr = 0; _MUTEX_LOCK(&atexit_mutex); for (p = __atexit; p; p = p->next) { for (n = p->ind; --n >= 0;) { if (p->fns[n].fn_type == ATEXIT_FN_EMPTY) continue; /* already been called */ - if (dso != NULL && dso != p->fns[n].fn_dso) - continue; /* wrong DSO */ fn = p->fns[n]; + if (dso != NULL && dso != fn.fn_dso) { + /* wrong DSO ? */ + if (!has_phdr || !__elf_phdr_match_addr( + &phdr_info, fn.fn_ptr.cxa_func)) + continue; + } /* Mark entry to indicate that this particular handler has already been called. @@ -185,4 +199,7 @@ __cxa_finalize(void *dso) _MUTEX_UNLOCK(&atexit_mutex); if (dso == NULL) _MUTEX_DESTROY(&atexit_mutex); + + if (&__pthread_cxa_finalize != NULL) + __pthread_cxa_finalize(&phdr_info); } |