diff options
Diffstat (limited to 'src/exit')
-rw-r--r-- | src/exit/atexit.c | 12 | ||||
-rw-r--r-- | src/exit/exit.c | 14 |
2 files changed, 26 insertions, 0 deletions
diff --git a/src/exit/atexit.c b/src/exit/atexit.c index 854e9fdd..92c91c9d 100644 --- a/src/exit/atexit.c +++ b/src/exit/atexit.c @@ -19,6 +19,7 @@ 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; @@ -34,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) @@ -44,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; diff --git a/src/exit/exit.c b/src/exit/exit.c index a6869b37..17b33cc6 100644 --- a/src/exit/exit.c +++ b/src/exit/exit.c @@ -1,6 +1,9 @@ #include <stdlib.h> #include <stdint.h> #include "libc.h" +#include "pthread_impl.h" +#include "atomic.h" +#include "syscall.h" static void dummy() { @@ -26,6 +29,17 @@ weak_alias(libc_exit_fini, __libc_exit_fini); _Noreturn void exit(int code) { + /* Handle potentially concurrent or recursive calls to exit, + * whose behaviors have traditionally been undefined by the + * standards. Using a custom lock here avoids pulling in lock + * machinery and lets us trap recursive calls while supporting + * multiple threads contending to be the one to exit(). */ + static volatile int exit_lock[1]; + int tid = __pthread_self()->tid; + int prev = a_cas(exit_lock, 0, tid); + if (prev == tid) a_crash(); + else if (prev) for (;;) __sys_pause(); + __funcs_on_exit(); __libc_exit_fini(); __stdio_exit(); |