1/*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#if defined(LIBC_SCCS) && !defined(lint) 34static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94"; 35#endif /* LIBC_SCCS and not lint */ 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: src/lib/libc/stdlib/atexit.c,v 1.8 2007/01/09 00:28:09 imp Exp $"); 38 39#include "namespace.h" 40#include <errno.h> 41#include <stddef.h> 42#include <stdlib.h> 43#include <unistd.h> 44#include <assert.h> 45#include <pthread.h> 46#if defined(__DYNAMIC__) || defined (__BLOCKS__) 47#include <dlfcn.h> 48#endif /* defined(__DYNAMIC__) */ 49#include "atexit.h" 50#include "un-namespace.h" 51 52#ifdef __BLOCKS__ 53#include <Block.h> 54#include <Block_private.h> 55#endif /* __BLOCKS__ */ 56#include "libc_private.h" 57#include <os/alloc_once_private.h> 58 59#include <TargetConditionals.h> 60 61#define ATEXIT_FN_EMPTY 0 62#define ATEXIT_FN_STD 1 63#define ATEXIT_FN_CXA 2 64#ifdef __BLOCKS__ 65#define ATEXIT_FN_BLK 3 66#endif /* __BLOCKS__ */ 67 68static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER; 69 70#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 71#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 72 73struct atexit { 74 struct atexit *next; /* next in list */ 75 int ind; /* next index in this table */ 76 struct atexit_fn { 77 int fn_type; /* ATEXIT_? from above */ 78 union { 79 void (*std_func)(void); 80 void (*cxa_func)(void *); 81#ifdef __BLOCKS__ 82 void (^block)(void); 83#endif /* __BLOCKS__ */ 84 } fn_ptr; /* function pointer */ 85 void *fn_arg; /* argument for CXA callback */ 86 void *fn_dso; /* shared module handle */ 87 } fns[ATEXIT_SIZE]; /* the table itself */ 88}; 89 90static struct atexit *__atexit; /* points to head of LIFO stack */ 91static int __atexit_new_registration; 92 93__attribute__ ((visibility ("hidden"))) 94void 95__atexit_init(void) 96{ 97 __atexit = os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_C, 98 sizeof(struct atexit), NULL); 99} 100 101/* 102 * Register the function described by 'fptr' to be called at application 103 * exit or owning shared object unload time. This is a helper function 104 * for atexit and __cxa_atexit. 105 */ 106static int 107atexit_register(struct atexit_fn *fptr) 108{ 109 struct atexit *p = __atexit; 110 assert(p); 111 _MUTEX_LOCK(&atexit_mutex); 112 while (p->ind >= ATEXIT_SIZE) { 113 struct atexit *old__atexit; 114 old__atexit = __atexit; 115 _MUTEX_UNLOCK(&atexit_mutex); 116 if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL) 117 return (-1); 118 _MUTEX_LOCK(&atexit_mutex); 119 if (old__atexit != __atexit) { 120 /* Lost race, retry operation */ 121 _MUTEX_UNLOCK(&atexit_mutex); 122 free(p); 123 _MUTEX_LOCK(&atexit_mutex); 124 p = __atexit; 125 continue; 126 } 127 p->ind = 0; 128 p->next = __atexit; 129 __atexit = p; 130 } 131 p->fns[p->ind++] = *fptr; 132 __atexit_new_registration = 1; 133 _MUTEX_UNLOCK(&atexit_mutex); 134 return 0; 135} 136 137/* 138 * Register a function to be performed at exit. 139 */ 140int 141atexit(void (*func)(void)) 142{ 143 struct atexit_fn fn; 144 int error; 145 146 fn.fn_type = ATEXIT_FN_STD; 147 fn.fn_ptr.std_func = func; 148 fn.fn_arg = NULL; 149 fn.fn_dso = NULL; 150 151#if defined(__DYNAMIC__) && !TARGET_OS_IPHONE 152 // <rdar://problem/14596032&15173956> 153 struct dl_info info; 154 if (dladdr(func, &info)) { 155 fn.fn_dso = info.dli_fbase; 156 } 157#endif 158 159 error = atexit_register(&fn); 160 return (error); 161} 162 163#ifdef __BLOCKS__ 164int 165atexit_b(void (^block)(void)) 166{ 167 struct atexit_fn fn; 168 int error; 169 170 fn.fn_type = ATEXIT_FN_BLK; 171 fn.fn_ptr.block = Block_copy(block); 172 fn.fn_arg = NULL; 173 fn.fn_dso = NULL; 174 175 error = atexit_register(&fn); 176 return (error); 177} 178#endif /* __BLOCKS__ */ 179 180/* 181 * Register a function to be performed at exit or when an shared object 182 * with given dso handle is unloaded dynamically. 183 */ 184int 185__cxa_atexit(void (*func)(void *), void *arg, void *dso) 186{ 187 struct atexit_fn fn; 188 int error; 189 190 fn.fn_type = ATEXIT_FN_CXA; 191 fn.fn_ptr.cxa_func = func;; 192 fn.fn_arg = arg; 193 fn.fn_dso = dso; 194 195 error = atexit_register(&fn); 196 return (error); 197} 198 199static bool 200__cxa_in_range(const struct __cxa_range_t ranges[], 201 unsigned int count, 202 const void* fn) 203{ 204 uintptr_t addr = (uintptr_t)fn; 205 206 unsigned int i; 207 for (i = 0; i < count; ++i) { 208 const struct __cxa_range_t *r = &ranges[i]; 209 if (addr < (uintptr_t)r->addr) { 210 continue; 211 } 212 if (addr < ((uintptr_t)r->addr + r->length)) { 213 return true; 214 } 215 } 216 return false; 217} 218 219/* 220 * Call handlers registered via __cxa_atexit/atexit that are in a 221 * a range specified. 222 * Note: rangeCount==0, means call all handlers. 223 */ 224void 225__cxa_finalize_ranges(const struct __cxa_range_t ranges[], unsigned int count) 226{ 227 struct atexit *p; 228 struct atexit_fn *fn; 229 int n; 230 _MUTEX_LOCK(&atexit_mutex); 231 232restart: 233 for (p = __atexit; p; p = p->next) { 234 for (n = p->ind; --n >= 0;) { 235 fn = &p->fns[n]; 236 237 if (fn->fn_type == ATEXIT_FN_EMPTY) { 238 continue; // already been called 239 } 240 241 // Verify that the entry is within the range being unloaded. 242 if (count > 0) { 243 if (fn->fn_type == ATEXIT_FN_CXA) { 244 // for __cxa_atexit(), call if *dso* is in range be unloaded 245 if (!__cxa_in_range(ranges, count, fn->fn_dso)) { 246 continue; // not being unloaded yet 247 } 248 } else if (fn->fn_type == ATEXIT_FN_STD) { 249 // for atexit, call if *function* is in range be unloaded 250 if (!__cxa_in_range(ranges, count, fn->fn_ptr.std_func)) { 251 continue; // not being unloaded yet 252 } 253#ifdef __BLOCKS__ 254 } else if (fn->fn_type == ATEXIT_FN_BLK) { 255 // for atexit_b, call if block code is in range be unloaded 256 void *a = ((struct Block_layout *)fn->fn_ptr.block)->invoke; 257 if (!__cxa_in_range(ranges, count, a)) { 258 continue; // not being unloaded yet 259 } 260#endif // __BLOCKS__ 261 } 262 } 263 264 // Clear the entry to indicate that this handler has been called. 265 int fn_type = fn->fn_type; 266 fn->fn_type = ATEXIT_FN_EMPTY; 267 268 // Detect recursive registrations. 269 __atexit_new_registration = 0; 270 _MUTEX_UNLOCK(&atexit_mutex); 271 272 // Call the handler. 273 if (fn_type == ATEXIT_FN_CXA) { 274 fn->fn_ptr.cxa_func(fn->fn_arg); 275 } else if (fn_type == ATEXIT_FN_STD) { 276 fn->fn_ptr.std_func(); 277#ifdef __BLOCKS__ 278 } else if (fn_type == ATEXIT_FN_BLK) { 279 fn->fn_ptr.block(); 280#endif // __BLOCKS__ 281 } 282 283 // Call any recursively registered handlers. 284 _MUTEX_LOCK(&atexit_mutex); 285 if (__atexit_new_registration) { 286 goto restart; 287 } 288 } 289 } 290 _MUTEX_UNLOCK(&atexit_mutex); 291} 292 293 294/* 295 * Call all handlers registered with __cxa_atexit for the shared 296 * object owning 'dso'. Note: if 'dso' is NULL, then all remaining 297 * handlers are called. 298 */ 299void 300__cxa_finalize(const void *dso) 301{ 302 if (dso != NULL) { 303 // Note: this should not happen as only dyld should be calling 304 // this and dyld has switched to call __cxa_finalize_ranges directly. 305 struct __cxa_range_t range; 306 range.addr = dso; 307 range.length = 1; 308 __cxa_finalize_ranges(&range, 1); 309 } else { 310 __cxa_finalize_ranges(NULL, 0); 311 } 312} 313 314#if !TARGET_IPHONE_SIMULATOR && (__i386__ || __x86_64__) 315/* 316 * Support for thread_local in C++, using existing _tlv_atexit() in libdyld 317 */ 318 319void _tlv_atexit(void(*f)(void*), void* arg); /* in libdyld */ 320 321void 322__cxa_thread_atexit(void(*f)(void*), void* arg) 323{ 324 _tlv_atexit(f, arg); 325} 326#endif 327