Subject: Infinite loop in __cxa_finalize
To: None <tech-userlevel@NetBSD.org>
From: Krister Walfridsson <cato@df.lth.se>
List: tech-userlevel
Date: 08/04/2007 14:40:42
The gcc testsuite finds two bugs in the NetBSD implementation of
__cxa_atexit() and __cxa_finalize().
One bug is that programs registering atexit handlers from atexit
handlers may go into an infinite loop, as demonstrated by:
#include <stdlib.h>
void two(void) {
}
void one(void) {
atexit(two);
}
int main(void) {
atexit(one);
return 0;
}
The reason is that the struct atexit_handler representing this function
is marked as unused before calling __cxa_atexit(). __cxa_atexit() does
therefore reuse this structure, but it has not been removed from the
list of handlers yet, so the list becomes a loop when the element is
re-inserted into the list.
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 4 Aug 2007 12:32:15 -0000
@@ -101,7 +101,7 @@ atexit_handler_alloc(void *dso)
if (dso == NULL) {
for (i = 0; i < NSTATIC_HANDLERS; i++) {
ah = &atexit_handler0[i];
- if (ah->ah_atexit == NULL) {
+ if (ah->ah_atexit == NULL && ah->ah_next == NULL) {
/* Slot is free. */
return (ah);
}
@@ -207,7 +207,9 @@ __cxa_finalize(void *dso)
if (call_depth == 1) {
*prevp = ah->ah_next;
- if (! STATIC_HANDLER_P(ah)) {
+ if (STATIC_HANDLER_P(ah))
+ ah->ah_next = NULL;
+ else {
ah->ah_next = dead_handlers;
dead_handlers = ah;
}