diff options
author | kettenis <> | 2014-06-18 19:01:10 +0000 |
---|---|---|
committer | kettenis <> | 2014-06-18 19:01:10 +0000 |
commit | ea52171d7ee0bb85a996dc2021440e122bf0357d (patch) | |
tree | 25ba00731ee7e34a8f0bb9da9731d10eba63a790 /src | |
parent | 067b361c7dbce14db401c57d13ca4e1146dedc3c (diff) | |
download | openbsd-ea52171d7ee0bb85a996dc2021440e122bf0357d.tar.gz openbsd-ea52171d7ee0bb85a996dc2021440e122bf0357d.tar.bz2 openbsd-ea52171d7ee0bb85a996dc2021440e122bf0357d.zip |
Always call atexit handlers as if they were registered with __cxa_atexit.
The extra argument doesn't hurt genuine atexit handlers and this fixes a
bug where we didn't provide the argument (effectively passing garbage) for
functions registered with __cxa_atexit in the main executable.
Pointed out by Dmitriy Ivanov <dimitry@google.com> and Elliott Hughes
<enh@google.com>.
ok matthew@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libc/stdlib/atexit.c | 15 | ||||
-rw-r--r-- | src/lib/libc/stdlib/atexit.h | 7 | ||||
-rw-r--r-- | src/regress/lib/libc/atexit/atexit_test.c | 10 |
3 files changed, 13 insertions, 19 deletions
diff --git a/src/lib/libc/stdlib/atexit.c b/src/lib/libc/stdlib/atexit.c index 049da3261d..9b08ebd7e6 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.17 2013/12/28 18:38:42 kettenis Exp $ */ | 1 | /* $OpenBSD: atexit.c,v 1.18 2014/06/18 19:01:10 kettenis Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2002 Daniel Hartmeier | 3 | * Copyright (c) 2002 Daniel Hartmeier |
4 | * All rights reserved. | 4 | * All rights reserved. |
@@ -90,7 +90,7 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) | |||
90 | __atexit = p; | 90 | __atexit = p; |
91 | } | 91 | } |
92 | fnp = &p->fns[p->ind++]; | 92 | fnp = &p->fns[p->ind++]; |
93 | fnp->fn_ptr.cxa_func = func; | 93 | fnp->fn_ptr = func; |
94 | fnp->fn_arg = arg; | 94 | fnp->fn_arg = arg; |
95 | fnp->fn_dso = dso; | 95 | fnp->fn_dso = dso; |
96 | if (mprotect(p, pgsize, PROT_READ)) | 96 | if (mprotect(p, pgsize, PROT_READ)) |
@@ -118,7 +118,7 @@ __cxa_finalize(void *dso) | |||
118 | 118 | ||
119 | for (p = __atexit; p != NULL; p = p->next) { | 119 | for (p = __atexit; p != NULL; p = p->next) { |
120 | for (n = p->ind; --n >= 0;) { | 120 | for (n = p->ind; --n >= 0;) { |
121 | if (p->fns[n].fn_ptr.cxa_func == NULL) | 121 | if (p->fns[n].fn_ptr == NULL) |
122 | continue; /* already called */ | 122 | continue; /* already called */ |
123 | if (dso != NULL && dso != p->fns[n].fn_dso) | 123 | if (dso != NULL && dso != p->fns[n].fn_dso) |
124 | continue; /* wrong DSO */ | 124 | continue; /* wrong DSO */ |
@@ -129,13 +129,10 @@ __cxa_finalize(void *dso) | |||
129 | */ | 129 | */ |
130 | fn = p->fns[n]; | 130 | fn = p->fns[n]; |
131 | if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) { | 131 | if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) { |
132 | p->fns[n].fn_ptr.cxa_func = NULL; | 132 | p->fns[n].fn_ptr = NULL; |
133 | mprotect(p, pgsize, PROT_READ); | 133 | mprotect(p, pgsize, PROT_READ); |
134 | } | 134 | } |
135 | if (fn.fn_dso != NULL) | 135 | (*fn.fn_ptr)(fn.fn_arg); |
136 | (*fn.fn_ptr.cxa_func)(fn.fn_arg); | ||
137 | else | ||
138 | (*fn.fn_ptr.std_func)(); | ||
139 | } | 136 | } |
140 | } | 137 | } |
141 | 138 | ||
@@ -185,7 +182,7 @@ __atexit_register_cleanup(void (*func)(void)) | |||
185 | if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) | 182 | if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) |
186 | goto unlock; | 183 | goto unlock; |
187 | } | 184 | } |
188 | p->fns[0].fn_ptr.std_func = func; | 185 | p->fns[0].fn_ptr = (void (*)(void *))func; |
189 | p->fns[0].fn_arg = NULL; | 186 | p->fns[0].fn_arg = NULL; |
190 | p->fns[0].fn_dso = NULL; | 187 | p->fns[0].fn_dso = NULL; |
191 | mprotect(p, pgsize, PROT_READ); | 188 | mprotect(p, pgsize, PROT_READ); |
diff --git a/src/lib/libc/stdlib/atexit.h b/src/lib/libc/stdlib/atexit.h index c44005deda..3de2aa3bf6 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.8 2013/06/02 21:08:36 matthew Exp $ */ | 1 | /* $OpenBSD: atexit.h,v 1.9 2014/06/18 19:01:10 kettenis Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2002 Daniel Hartmeier | 4 | * Copyright (c) 2002 Daniel Hartmeier |
@@ -35,10 +35,7 @@ struct atexit { | |||
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 | struct atexit_fn { | 37 | struct atexit_fn { |
38 | union { | 38 | void (*fn_ptr)(void *); |
39 | void (*std_func)(void); | ||
40 | void (*cxa_func)(void *); | ||
41 | } fn_ptr; | ||
42 | void *fn_arg; /* argument for CXA callback */ | 39 | void *fn_arg; /* argument for CXA callback */ |
43 | void *fn_dso; /* shared module handle */ | 40 | void *fn_dso; /* shared module handle */ |
44 | } fns[1]; /* the table itself */ | 41 | } fns[1]; /* the table itself */ |
diff --git a/src/regress/lib/libc/atexit/atexit_test.c b/src/regress/lib/libc/atexit/atexit_test.c index 3dd0b62c3e..f374dee9eb 100644 --- a/src/regress/lib/libc/atexit/atexit_test.c +++ b/src/regress/lib/libc/atexit/atexit_test.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: atexit_test.c,v 1.6 2007/09/03 14:42:44 millert Exp $ */ | 1 | /* $OpenBSD: atexit_test.c,v 1.7 2014/06/18 19:01:10 kettenis Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2002 Daniel Hartmeier | 4 | * Copyright (c) 2002 Daniel Hartmeier |
@@ -43,7 +43,7 @@ | |||
43 | void handle_first(void); | 43 | void handle_first(void); |
44 | void handle_middle(void); | 44 | void handle_middle(void); |
45 | void handle_last(void); | 45 | void handle_last(void); |
46 | void handle_invalid(void); | 46 | void handle_invalid(void *); |
47 | void handle_cleanup(void); | 47 | void handle_cleanup(void); |
48 | void handle_signal(int); | 48 | void handle_signal(int); |
49 | 49 | ||
@@ -79,7 +79,7 @@ main(int argc, char *argv[]) | |||
79 | /* this is supposed to segfault */ | 79 | /* this is supposed to segfault */ |
80 | if (!strcmp(argv[1], "-invalid-atexit")) { | 80 | if (!strcmp(argv[1], "-invalid-atexit")) { |
81 | signal(SIGSEGV, handle_signal); | 81 | signal(SIGSEGV, handle_signal); |
82 | __atexit->fns[0].fn_ptr.std_func = handle_invalid; | 82 | __atexit->fns[0].fn_ptr = handle_invalid; |
83 | } else if (!strcmp(argv[1], "-invalid-cleanup")) { | 83 | } else if (!strcmp(argv[1], "-invalid-cleanup")) { |
84 | struct atexit *p = __atexit; | 84 | struct atexit *p = __atexit; |
85 | 85 | ||
@@ -88,7 +88,7 @@ main(int argc, char *argv[]) | |||
88 | p = p->next; | 88 | p = p->next; |
89 | if (p == NULL) | 89 | if (p == NULL) |
90 | fprintf(stderr, "p == NULL, no page found\n"); | 90 | fprintf(stderr, "p == NULL, no page found\n"); |
91 | p->fns[0].fn_ptr.std_func = handle_invalid; | 91 | p->fns[0].fn_ptr = handle_invalid; |
92 | } | 92 | } |
93 | __atexit_register_cleanup(handle_cleanup); | 93 | __atexit_register_cleanup(handle_cleanup); |
94 | counter = 0; | 94 | counter = 0; |
@@ -121,7 +121,7 @@ handle_cleanup(void) | |||
121 | } | 121 | } |
122 | 122 | ||
123 | void | 123 | void |
124 | handle_invalid(void) | 124 | handle_invalid(void *arg) |
125 | { | 125 | { |
126 | fprintf(stderr, "handle_invalid() THIS SHOULD HAVE SEGFAULTED INSTEAD!\n"); | 126 | fprintf(stderr, "handle_invalid() THIS SHOULD HAVE SEGFAULTED INSTEAD!\n"); |
127 | } | 127 | } |