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) {