diff options
Diffstat (limited to 'lib/libc/stdlib/atexit.c')
| -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 916119f315e8..06f31c36f68e 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> @@ -146,6 +147,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 @@ -154,18 +158,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. @@ -182,4 +196,7 @@ __cxa_finalize(void *dso)  		}  	}  	_MUTEX_UNLOCK(&atexit_mutex); + +	if (has_phdr && &__pthread_cxa_finalize != NULL) +		__pthread_cxa_finalize(&phdr_info);  }  | 
