Index: libc/src/stdlib/atexit.cpp =================================================================== --- libc/src/stdlib/atexit.cpp +++ libc/src/stdlib/atexit.cpp @@ -27,8 +27,10 @@ void call_exit_callbacks() { handler_list_mtx.lock(); - for (auto callback : exit_callbacks) { + while (!exit_callbacks.empty()) { handler_list_mtx.unlock(); + auto *callback = exit_callbacks.back(); + exit_callbacks.pop_back(); callback(); handler_list_mtx.lock(); } Index: libc/test/src/stdlib/atexit_test.cpp =================================================================== --- libc/test/src/stdlib/atexit_test.cpp +++ libc/test/src/stdlib/atexit_test.cpp @@ -78,17 +78,12 @@ EXPECT_EXITS(test, 0); } -// POSIX doesn't specify if an atexit handler can call atexit, it only says it -// is undefined for a handler to call exit(3). The current implementation will -// end up invoking the newly registered function, although glibc does, other -// libc's do not. This just tests that we don't deadlock when an exit handler -// calls atexit. TEST(LlvmLibcAtExit, HandlerCallsAtExit) { auto test = [] { __llvm_libc::atexit(+[] { - __llvm_libc::atexit(+[] { __builtin_trap(); }); - __llvm_libc::exit(0); + __llvm_libc::atexit(+[] { __llvm_libc::exit(1); }); }); + __llvm_libc::exit(0); }; - EXPECT_EXITS(test, 0); + EXPECT_EXITS(test, 1); }