Index: libc/src/assert/CMakeLists.txt =================================================================== --- libc/src/assert/CMakeLists.txt +++ libc/src/assert/CMakeLists.txt @@ -10,4 +10,11 @@ # later. sys_syscall_h linux_syscall_h + # TOOD: Remove these as they are dependencies of abort + sigaction + sigemptyset + sigaddset + sigprocmask + signal + __errno_location ) Index: libc/src/signal/linux/CMakeLists.txt =================================================================== --- libc/src/signal/linux/CMakeLists.txt +++ libc/src/signal/linux/CMakeLists.txt @@ -95,4 +95,6 @@ DEPENDS sigaction signal_h + # TODO: Remove this it is a dependency of sigaction + __errno_location ) Index: libc/src/stdlib/CMakeLists.txt =================================================================== --- libc/src/stdlib/CMakeLists.txt +++ libc/src/stdlib/CMakeLists.txt @@ -12,4 +12,10 @@ raise _Exit stdlib_h + sigemptyset + sigaddset + sigprocmask + signal + # TODO: Remove this, dependency of signal via sigaction + __errno_location ) Index: libc/src/stdlib/abort.cpp =================================================================== --- libc/src/stdlib/abort.cpp +++ libc/src/stdlib/abort.cpp @@ -8,21 +8,36 @@ #include "src/__support/common.h" #include "src/signal/raise.h" +#include "src/signal/sigaddset.h" +#include "src/signal/sigemptyset.h" +#include "src/signal/signal.h" +#include "src/signal/sigprocmask.h" #include "src/stdlib/_Exit.h" #include "src/stdlib/abort.h" namespace __llvm_libc { +static bool called; + void LLVM_LIBC_ENTRYPOINT(abort)() { - // TODO: When sigprocmask and sigaction land: - // Unblock SIGABRT, raise it, if it was ignored or the handler returned, - // change its action to SIG_DFL, raise it again. - // TODO: When C11 mutexes land: - // Aquire recursive mutex (in case the current signal handler for SIGABRT - // itself calls abort we don't want to deadlock on the same thread trying - // to aquire it's own mutex.) + sigset_t set; + __llvm_libc::sigemptyset(&set); + __llvm_libc::sigaddset(&set, SIGABRT); + __llvm_libc::sigprocmask(SIG_UNBLOCK, &set, nullptr); + + // If the current SIGABRT handler calls abort(), we should make sure it + // it does not infinitely call itself. + if (!called) { + called = true; + __llvm_libc::raise(SIGABRT); + // Unblock again incase the handler caught then blocked it. + __llvm_libc::sigprocmask(SIG_UNBLOCK, &set, nullptr); + } + + __llvm_libc::signal(SIGABRT, SIG_DFL); __llvm_libc::raise(SIGABRT); + __llvm_libc::raise(SIGKILL); __llvm_libc::_Exit(127); } Index: libc/test/src/assert/CMakeLists.txt =================================================================== --- libc/test/src/assert/CMakeLists.txt +++ libc/test/src/assert/CMakeLists.txt @@ -12,4 +12,10 @@ abort raise _Exit + sigaction + sigemptyset + sigaddset + sigprocmask + signal + __errno_location ) Index: libc/test/src/assert/assert_test.cpp =================================================================== --- libc/test/src/assert/assert_test.cpp +++ libc/test/src/assert/assert_test.cpp @@ -7,21 +7,21 @@ //===----------------------------------------------------------------------===// #undef NDEBUG +#include "include/signal.h" #include "src/assert/assert.h" #include "utils/UnitTest/Test.h" extern "C" int close(int); TEST(Assert, Enabled) { - // -1 matches against any signal, which is necessary for now until - // __llvm_libc::abort() unblocks SIGABRT. Close standard error for the - // child process so we don't print the assertion failure message. + // Close standard error for the child process so we don't print the assertion + // failure message. EXPECT_DEATH( [] { close(2); assert(0); }, - -1); + SIGABRT); } #define NDEBUG Index: libc/test/src/stdlib/CMakeLists.txt =================================================================== --- libc/test/src/stdlib/CMakeLists.txt +++ libc/test/src/stdlib/CMakeLists.txt @@ -23,4 +23,11 @@ abort _Exit raise + # TODO: Remove depencies of abort + sigaction + sigemptyset + sigaddset + sigprocmask + signal + __errno_location ) Index: libc/test/src/stdlib/abort_test.cpp =================================================================== --- libc/test/src/stdlib/abort_test.cpp +++ libc/test/src/stdlib/abort_test.cpp @@ -8,11 +8,47 @@ #include "include/signal.h" #include "include/stdlib.h" +#include "src/signal/sigaddset.h" +#include "src/signal/sigemptyset.h" +#include "src/signal/signal.h" +#include "src/signal/sigprocmask.h" #include "src/stdlib/abort.h" #include "utils/UnitTest/Test.h" -TEST(Stdlib, abort) { - // -1 matches against any signal, which is necessary for now until - // __llvm_libc::abort() unblocks SIGABRT. - EXPECT_DEATH([] { __llvm_libc::abort(); }, -1); +TEST(Abort, Basic) { + EXPECT_DEATH([] { __llvm_libc::abort(); }, SIGABRT); +} + +TEST(Abort, Blocked) { + __llvm_libc::signal(SIGABRT, SIG_IGN); + EXPECT_DEATH([] { __llvm_libc::abort(); }, SIGABRT); +} + +TEST(Abort, RecursiveHandler) { + __llvm_libc::signal( + SIGABRT, +[](int) { __llvm_libc::abort(); }); + EXPECT_DEATH([] { __llvm_libc::abort(); }, SIGABRT); +} + +TEST(Abort, BlockFromHandler) { + __llvm_libc::signal( + SIGABRT, +[](int) { + sigset_t set; + __llvm_libc::sigemptyset(&set); + __llvm_libc::sigaddset(&set, SIGABRT); + __llvm_libc::sigprocmask(SIG_BLOCK, &set, nullptr); + }); + EXPECT_DEATH([] { __llvm_libc::abort(); }, SIGABRT); +} + +TEST(Abort, BlockFromHandlerRecursive) { + __llvm_libc::signal( + SIGABRT, +[](int) { + sigset_t set; + __llvm_libc::sigemptyset(&set); + __llvm_libc::sigaddset(&set, SIGABRT); + __llvm_libc::sigprocmask(SIG_BLOCK, &set, nullptr); + __llvm_libc::abort(); + }); + EXPECT_DEATH([] { __llvm_libc::abort(); }, SIGABRT); }