diff options
Diffstat (limited to 'src/exit/atexit.c')
-rw-r--r-- | src/exit/atexit.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/exit/atexit.c b/src/exit/atexit.c index 160d277a..92c91c9d 100644 --- a/src/exit/atexit.c +++ b/src/exit/atexit.c @@ -2,6 +2,12 @@ #include <stdint.h> #include "libc.h" #include "lock.h" +#include "fork_impl.h" + +#define malloc __libc_malloc +#define calloc __libc_calloc +#define realloc undef +#define free undef /* Ensure that at least 32 atexit handlers can be registered without malloc */ #define COUNT 32 @@ -13,8 +19,10 @@ static struct fl void *a[COUNT]; } builtin, *head; +static int finished_atexit; static int slot; static volatile int lock[1]; +volatile int *const __atexit_lockptr = lock; void __funcs_on_exit() { @@ -27,6 +35,10 @@ void __funcs_on_exit() func(arg); LOCK(lock); } + /* Unlock to prevent deadlock if a global dtor + * attempts to call atexit. */ + finished_atexit = 1; + UNLOCK(lock); } void __cxa_finalize(void *dso) @@ -37,6 +49,13 @@ int __cxa_atexit(void (*func)(void *), void *arg, void *dso) { LOCK(lock); + /* Prevent dtors from registering further atexit + * handlers that would never be run. */ + if (finished_atexit) { + UNLOCK(lock); + return -1; + } + /* Defer initialization of head so it can be in BSS */ if (!head) head = &builtin; |