summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authormillert <>2007-09-03 14:40:16 +0000
committermillert <>2007-09-03 14:40:16 +0000
commit7e0e6a2581ab1d1bca602865b8e38dfa2f54424a (patch)
tree276e35092c38431624dd4e601442d98afb2a617d /src/lib
parent2056049ed6b7a028e611838a742280fced6d2c23 (diff)
downloadopenbsd-7e0e6a2581ab1d1bca602865b8e38dfa2f54424a.tar.gz
openbsd-7e0e6a2581ab1d1bca602865b8e38dfa2f54424a.tar.bz2
openbsd-7e0e6a2581ab1d1bca602865b8e38dfa2f54424a.zip
Add __cxa_atexit() support for gcc3. This provides support for shared object destructors called at dlclose() time. Inspired by similar changes in FreeBSD and NetBSD.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libc/stdlib/abort.c9
-rw-r--r--src/lib/libc/stdlib/atexit.c93
-rw-r--r--src/lib/libc/stdlib/atexit.h14
-rw-r--r--src/lib/libc/stdlib/exit.c22
4 files changed, 108 insertions, 30 deletions
diff --git a/src/lib/libc/stdlib/abort.c b/src/lib/libc/stdlib/abort.c
index 072a9fa8c1..244e3b28aa 100644
--- a/src/lib/libc/stdlib/abort.c
+++ b/src/lib/libc/stdlib/abort.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: abort.c,v 1.14 2005/08/08 08:05:36 espie Exp $ */ 1/* $OpenBSD: abort.c,v 1.15 2007/09/03 14:40:16 millert Exp $ */
2/* 2/*
3 * Copyright (c) 1985 Regents of the University of California. 3 * Copyright (c) 1985 Regents of the University of California.
4 * All rights reserved. 4 * All rights reserved.
@@ -54,11 +54,14 @@ abort(void)
54 * POSIX requires we flush stdio buffers on abort 54 * POSIX requires we flush stdio buffers on abort
55 */ 55 */
56 if (cleanup_called == 0) { 56 if (cleanup_called == 0) {
57 /* the cleanup routine lives in fns[0] on the last page */
57 while (p != NULL && p->next != NULL) 58 while (p != NULL && p->next != NULL)
58 p = p->next; 59 p = p->next;
59 if (p != NULL && p->fns[0] != NULL) { 60 /* the check for fn_dso == NULL is mostly paranoia */
61 if (p != NULL && p->fns[0].fn_dso == NULL &&
62 p->fns[0].fn_ptr.std_func != NULL) {
60 cleanup_called = 1; 63 cleanup_called = 1;
61 (*p->fns[0])(); 64 (*p->fns[0].fn_ptr.std_func)();
62 } 65 }
63 } 66 }
64 67
diff --git a/src/lib/libc/stdlib/atexit.c b/src/lib/libc/stdlib/atexit.c
index 50f8ec9372..ebf5f8775c 100644
--- a/src/lib/libc/stdlib/atexit.c
+++ b/src/lib/libc/stdlib/atexit.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: atexit.c,v 1.12 2006/02/22 07:16:32 otto Exp $ */ 1/* $OpenBSD: atexit.c,v 1.13 2007/09/03 14:40:16 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Daniel Hartmeier 3 * Copyright (c) 2002 Daniel Hartmeier
4 * All rights reserved. 4 * All rights reserved.
@@ -45,17 +45,22 @@ struct atexit *__atexit;
45 * function pointer in the first allocated page (the last one in 45 * function pointer in the first allocated page (the last one in
46 * the linked list) is reserved for the cleanup function. 46 * the linked list) is reserved for the cleanup function.
47 * 47 *
48 * Outside the following two functions, all pages are mprotect()'ed 48 * Outside the following functions, all pages are mprotect()'ed
49 * to prevent unintentional/malicious corruption. 49 * to prevent unintentional/malicious corruption.
50 */ 50 */
51 51
52/* 52/*
53 * Register a function to be performed at exit. 53 * Register a function to be performed at exit or when a shared object
54 * with the given dso handle is unloaded dynamically. Also used as
55 * the backend for atexit(). For more info on this API, see:
56 *
57 * http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor
54 */ 58 */
55int 59int
56atexit(void (*fn)(void)) 60__cxa_atexit(void (*func)(void *), void *arg, void *dso)
57{ 61{
58 struct atexit *p; 62 struct atexit *p = __atexit;
63 struct atexit_fn *fnp;
59 int pgsize = getpagesize(); 64 int pgsize = getpagesize();
60 int ret = -1; 65 int ret = -1;
61 66
@@ -75,7 +80,7 @@ atexit(void (*fn)(void))
75 if (p == MAP_FAILED) 80 if (p == MAP_FAILED)
76 goto unlock; 81 goto unlock;
77 if (__atexit == NULL) { 82 if (__atexit == NULL) {
78 p->fns[0] = NULL; 83 memset(&p->fns[0], 0, sizeof(p->fns[0]));
79 p->ind = 1; 84 p->ind = 1;
80 } else 85 } else
81 p->ind = 0; 86 p->ind = 0;
@@ -86,7 +91,10 @@ atexit(void (*fn)(void))
86 if (__atexit_invalid) 91 if (__atexit_invalid)
87 __atexit_invalid = 0; 92 __atexit_invalid = 0;
88 } 93 }
89 p->fns[p->ind++] = fn; 94 fnp = &p->fns[p->ind++];
95 fnp->fn_ptr.cxa_func = func;
96 fnp->fn_arg = arg;
97 fnp->fn_dso = dso;
90 if (mprotect(p, pgsize, PROT_READ)) 98 if (mprotect(p, pgsize, PROT_READ))
91 goto unlock; 99 goto unlock;
92 ret = 0; 100 ret = 0;
@@ -96,10 +104,75 @@ unlock:
96} 104}
97 105
98/* 106/*
107 * Register a function to be performed at exit.
108 */
109int
110atexit(void (*func)(void))
111{
112 return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
113}
114
115/*
116 * Call all handlers registered with __cxa_atexit() for the shared
117 * object owning 'dso'.
118 * Note: if 'dso' is NULL, then all remaining handlers are called.
119 */
120void
121__cxa_finalize(void *dso)
122{
123 struct atexit *p, *q;
124 struct atexit_fn fn;
125 int n, pgsize = getpagesize();
126 static int call_depth;
127
128 if (__atexit_invalid)
129 return;
130
131 call_depth++;
132
133 for (p = __atexit; p != NULL; p = p->next) {
134 for (n = p->ind; --n >= 0;) {
135 if (p->fns[n].fn_ptr.cxa_func == NULL)
136 continue; /* already called */
137 if (dso != NULL && dso != p->fns[n].fn_dso)
138 continue; /* wrong DSO */
139
140 /*
141 * Mark handler as having been already called to avoid
142 * dupes and loops, then call the appropriate function.
143 */
144 fn = p->fns[n];
145 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) {
146 p->fns[n].fn_ptr.cxa_func = NULL;
147 mprotect(p, pgsize, PROT_READ);
148 }
149 if (dso != NULL)
150 (*fn.fn_ptr.cxa_func)(fn.fn_arg);
151 else
152 (*fn.fn_ptr.std_func)();
153 }
154 }
155
156 /*
157 * If called via exit(), unmap the pages since we have now run
158 * all the handlers. We defer this until calldepth == 0 so that
159 * we don't unmap things prematurely if called recursively.
160 */
161 if (dso == NULL && --call_depth == 0) {
162 for (p = __atexit; p != NULL; ) {
163 q = p;
164 p = p->next;
165 munmap(q, pgsize);
166 }
167 __atexit = NULL;
168 }
169}
170
171/*
99 * Register the cleanup function 172 * Register the cleanup function
100 */ 173 */
101void 174void
102__atexit_register_cleanup(void (*fn)(void)) 175__atexit_register_cleanup(void (*func)(void))
103{ 176{
104 struct atexit *p; 177 struct atexit *p;
105 int pgsize = getpagesize(); 178 int pgsize = getpagesize();
@@ -126,7 +199,9 @@ __atexit_register_cleanup(void (*fn)(void))
126 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) 199 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
127 goto unlock; 200 goto unlock;
128 } 201 }
129 p->fns[0] = fn; 202 p->fns[0].fn_ptr.std_func = func;
203 p->fns[0].fn_arg = NULL;
204 p->fns[0].fn_dso = NULL;
130 mprotect(p, pgsize, PROT_READ); 205 mprotect(p, pgsize, PROT_READ);
131unlock: 206unlock:
132 _ATEXIT_UNLOCK(); 207 _ATEXIT_UNLOCK();
diff --git a/src/lib/libc/stdlib/atexit.h b/src/lib/libc/stdlib/atexit.h
index 21b0c2e532..1b23565dd0 100644
--- a/src/lib/libc/stdlib/atexit.h
+++ b/src/lib/libc/stdlib/atexit.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: atexit.h,v 1.6 2003/07/31 07:08:42 deraadt Exp $ */ 1/* $OpenBSD: atexit.h,v 1.7 2007/09/03 14:40:16 millert Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2002 Daniel Hartmeier 4 * Copyright (c) 2002 Daniel Hartmeier
@@ -34,8 +34,18 @@ struct atexit {
34 struct atexit *next; /* next in list */ 34 struct atexit *next; /* next in list */
35 int ind; /* next index in this table */ 35 int ind; /* next index in this table */
36 int max; /* max entries >= ATEXIT_SIZE */ 36 int max; /* max entries >= ATEXIT_SIZE */
37 void (*fns[1])(void); /* the table itself */ 37 struct atexit_fn {
38 union {
39 void (*std_func)(void);
40 void (*cxa_func)(void *);
41 } fn_ptr;
42 void *fn_arg; /* argument for CXA callback */
43 void *fn_dso; /* shared module handle */
44 } fns[1]; /* the table itself */
38}; 45};
39 46
40extern int __atexit_invalid; 47extern int __atexit_invalid;
41extern struct atexit *__atexit; /* points to head of LIFO stack */ 48extern struct atexit *__atexit; /* points to head of LIFO stack */
49
50int __cxa_atexit(void (*)(void *), void *, void *);
51void __cxa_finalize(void *);
diff --git a/src/lib/libc/stdlib/exit.c b/src/lib/libc/stdlib/exit.c
index 90b7d5adc2..83fe3d2de5 100644
--- a/src/lib/libc/stdlib/exit.c
+++ b/src/lib/libc/stdlib/exit.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: exit.c,v 1.11 2005/08/08 08:05:36 espie Exp $ */ 1/* $OpenBSD: exit.c,v 1.12 2007/09/03 14:40:16 millert Exp $ */
2/*- 2/*-
3 * Copyright (c) 1990 The Regents of the University of California. 3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved. 4 * All rights reserved.
@@ -50,20 +50,10 @@ int __isthreaded = 0;
50void 50void
51exit(int status) 51exit(int status)
52{ 52{
53 struct atexit *p, *q; 53 /*
54 int n, pgsize = getpagesize(); 54 * Call functions registered by atexit() or _cxa_atexit()
55 55 * (including the stdio cleanup routine) and then _exit().
56 if (!__atexit_invalid) { 56 */
57 p = __atexit; 57 __cxa_finalize(NULL);
58 while (p != NULL) {
59 for (n = p->ind; --n >= 0;)
60 if (p->fns[n] != NULL)
61 (*p->fns[n])();
62 q = p;
63 p = p->next;
64 munmap(q, pgsize);
65 }
66 }
67 /* cleanup, if registered, was called through fns[0] in the last page */
68 _exit(status); 58 _exit(status);
69} 59}