about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2015-07-24 21:15:49 +0000
committerRich Felker <dalias@aerifal.cx>2015-07-24 21:22:43 +0000
commit57243b30214656e7dd9fff509a1b6370b712f863 (patch)
tree7ef562b56739ce7732d083793ae151cc042ad103
parent3975577922aedab7d60788dd320a2c8e4e94bc6e (diff)
downloadmusl-57243b30214656e7dd9fff509a1b6370b712f863.tar.gz
musl-57243b30214656e7dd9fff509a1b6370b712f863.tar.xz
musl-57243b30214656e7dd9fff509a1b6370b712f863.zip
fix atexit when it is called from an atexit handler
The old code accepted atexit handlers after exit, but did not run them
reliably. C11 seems to explicitly allow atexit to fail (and report
such failure) in this case, but this situation can easily come up in
C++ if a destructor has a local static object with a destructor so it
should be handled.

Note that the memory usage can grow linearly with the overall number
of registered atexit handlers instead of with the worst case list
length. (This only matters if atexit handlers keep registering atexit
handlers which should not happen in practice).

Commit message/rationale based on text by Szabolcs Nagy.
-rw-r--r--src/exit/atexit.c21
1 files changed, 9 insertions, 12 deletions
diff --git a/src/exit/atexit.c b/src/exit/atexit.c
index be827181..2b58b8bb 100644
--- a/src/exit/atexit.c
+++ b/src/exit/atexit.c
@@ -12,18 +12,16 @@ static struct fl
 	void *a[COUNT];
 } builtin, *head;
 
+static int slot;
 static volatile int lock[2];
 
 void __funcs_on_exit()
 {
-	int i;
 	void (*func)(void *), *arg;
 	LOCK(lock);
-	for (; head; head=head->next) for (i=COUNT-1; i>=0; i--) {
-		if (!head->f[i]) continue;
-		func = head->f[i];
-		arg = head->a[i];
-		head->f[i] = 0;
+	for (; head; head=head->next, slot=COUNT) while(slot-->0) {
+		func = head->f[slot];
+		arg = head->a[slot];
 		UNLOCK(lock);
 		func(arg);
 		LOCK(lock);
@@ -36,15 +34,13 @@ void __cxa_finalize(void *dso)
 
 int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
 {
-	int i;
-
 	LOCK(lock);
 
 	/* Defer initialization of head so it can be in BSS */
 	if (!head) head = &builtin;
 
 	/* If the current function list is full, add a new one */
-	if (head->f[COUNT-1]) {
+	if (slot==COUNT) {
 		struct fl *new_fl = calloc(sizeof(struct fl), 1);
 		if (!new_fl) {
 			UNLOCK(lock);
@@ -52,12 +48,13 @@ int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
 		}
 		new_fl->next = head;
 		head = new_fl;
+		slot = 0;
 	}
 
 	/* Append function to the list. */
-	for (i=0; i<COUNT && head->f[i]; i++);
-	head->f[i] = func;
-	head->a[i] = arg;
+	head->f[slot] = func;
+	head->a[slot] = arg;
+	slot++;
 
 	UNLOCK(lock);
 	return 0;