Subject: atexit handler not called
To: None <tech-userlevel@NetBSD.org>
From: Krister Walfridsson <cato@df.lth.se>
List: tech-userlevel
Date: 08/04/2007 14:42:48
The second bug in __cxa_finalize() found by the gcc test suite was
described as following on the newlib mailinglist
(http://www.cygwin.com/ml/newlib/2007/msg00308.html):
The init19.C failures we're seeing with GCC 4.2 on newlib targets
are in fact a bug in newlib. The test case is calling "atexit" from
within a function that is itself an "atexit" function; in other
words, we call exit, which calls the first atexit function, which
then registers a second atexit function. The second atexit function
was never being called by newlib. The C99 standard does imply that
the library should handle this case:
First, all functions registered by the atexit function are called,
in the reverse order of their registration, except that a function
is called after any previously registered functions that had been
called at the time it was registered.
That last clause says that the second atexit function above is
called after the first one, even though the first one was registered
first.
The patch below fix the problem. Is it OK to commit?
/Krister
Index: atexit.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdlib/atexit.c,v
retrieving revision 1.17
diff -u -p -r1.17 atexit.c
--- atexit.c 12 Jun 2005 05:21:28 -0000 1.17
+++ atexit.c 3 Aug 2007 23:01:54 -0000
@@ -191,9 +191,11 @@ __cxa_finalize(void *dso)
* When the depth 1 caller sees those, it will simply unlink them
* for us.
*/
+again:
for (prevp = &atexit_handler_stack; (ah = (*prevp)) != NULL;) {
if (dso == NULL || dso == ah->ah_dso || ah->ah_atexit == NULL) {
if (ah->ah_atexit != NULL) {
+ void *p = atexit_handler_stack;
if (ah->ah_dso != NULL) {
cxa_func = ah->ah_cxa_atexit;
ah->ah_cxa_atexit = NULL;
@@ -203,6 +205,9 @@ __cxa_finalize(void *dso)
ah->ah_atexit = NULL;
(*atexit_func)();
}
+ /* Restart if new atexit handler was added. */
+ if (p != atexit_handler_stack)
+ goto again;
}
if (call_depth == 1) {