[libc-commits] [libc] [libc] update abort implementation and lift it for internal usage (PR #189756)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Wed Apr 1 07:51:32 PDT 2026


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/189756

>From 60be7798c2844812a54471013645ed3558fef8cc Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 31 Mar 2026 17:39:31 -0400
Subject: [PATCH 1/5] [libc] update abort implementation and lift it for
 internal usage

---
 libc/src/signal/linux/signal_utils.h          |  8 ++
 libc/src/stdlib/linux/CMakeLists.txt          | 16 +++-
 libc/src/stdlib/linux/abort.cpp               | 19 +---
 libc/src/stdlib/linux/abort_utils.h           | 78 ++++++++++++++++
 .../integration/src/stdlib/CMakeLists.txt     | 23 +++++
 .../integration/src/stdlib/abort_test.cpp     | 89 +++++++++++++++++++
 6 files changed, 214 insertions(+), 19 deletions(-)
 create mode 100644 libc/src/stdlib/linux/abort_utils.h
 create mode 100644 libc/test/integration/src/stdlib/abort_test.cpp

diff --git a/libc/src/signal/linux/signal_utils.h b/libc/src/signal/linux/signal_utils.h
index be4501c27dba5..e36d47f4fb602 100644
--- a/libc/src/signal/linux/signal_utils.h
+++ b/libc/src/signal/linux/signal_utils.h
@@ -113,6 +113,14 @@ LIBC_INLINE int restore_signals(const sigset_t &set) {
                                            &set, nullptr, sizeof(sigset_t));
 }
 
+LIBC_INLINE int unblock_signal(int signal) {
+  sigset_t set;
+  if (!add_signal(set, signal))
+    return -EINVAL;
+  return LIBC_NAMESPACE::syscall_impl<int>(SYS_rt_sigprocmask, SIG_UNBLOCK,
+                                           &set, nullptr, sizeof(sigset_t));
+}
+
 LIBC_INLINE ErrorOr<int>
 do_sigaction(int signal, const struct sigaction *__restrict libc_new,
              struct sigaction *__restrict libc_old) {
diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt
index 1d3c00a5e0ddb..4e476d8d57354 100644
--- a/libc/src/stdlib/linux/CMakeLists.txt
+++ b/libc/src/stdlib/linux/CMakeLists.txt
@@ -1,3 +1,15 @@
+add_header_library(
+  abort_utils
+  HDRS
+    abort_utils.h
+  DEPENDS
+    libc.include.stdlib
+    libc.src.signal.raise
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.threads.linux.rwlock
+    libc.src.signal.linux.__restore
+)
+
 add_entrypoint_object(
   abort
   SRCS
@@ -5,7 +17,7 @@ add_entrypoint_object(
   HDRS
     ../abort.h
   DEPENDS
+    .abort_utils
+    libc.src.signal.linux.__restore
     libc.include.stdlib
-    libc.src.signal.raise
-    libc.src.stdlib._Exit
 )
diff --git a/libc/src/stdlib/linux/abort.cpp b/libc/src/stdlib/linux/abort.cpp
index d78ea675593a4..0374e9315cba8 100644
--- a/libc/src/stdlib/linux/abort.cpp
+++ b/libc/src/stdlib/linux/abort.cpp
@@ -6,26 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-#include "src/signal/raise.h"
-#include "src/stdlib/_Exit.h"
-
 #include "src/stdlib/abort.h"
+#include "src/stdlib/linux/abort_utils.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(void, 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:
-  // Acquire 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 acquire it's own mutex.)
-  LIBC_NAMESPACE::raise(SIGABRT);
-  LIBC_NAMESPACE::raise(SIGKILL);
-  LIBC_NAMESPACE::_Exit(127);
-}
+LLVM_LIBC_FUNCTION(void, abort, ()) { abort_utils::abort(); }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/linux/abort_utils.h b/libc/src/stdlib/linux/abort_utils.h
new file mode 100644
index 0000000000000..c4795c879ae08
--- /dev/null
+++ b/libc/src/stdlib/linux/abort_utils.h
@@ -0,0 +1,78 @@
+//===-- Internal header for Linux abort -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_LINUX_ABORT_UTILS_H
+#define LLVM_LIBC_SRC_STDLIB_LINUX_ABORT_UTILS_H
+
+#include "hdr/types/sigset_t.h"
+#include "include/llvm-libc-types/sigset_t.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/OSUtil/exit.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/raise.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/linux/rwlock.h"
+#include "src/signal/linux/signal_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace abort_utils {
+
+// TODO: this lock needs to be acquired during _Fork/fork.
+class AbortLockGuard {
+private:
+  sigset_t old_mask;
+  LIBC_INLINE_VAR static RwLock abort_lock;
+
+public:
+  LIBC_INLINE constexpr AbortLockGuard(bool exclusive) : old_mask{} {
+    RwLock::LockResult result = RwLock::LockResult::Success;
+    do {
+      if (exclusive)
+        result = abort_lock.write_lock(cpp::nullopt);
+      else
+        result = abort_lock.read_lock(cpp::nullopt);
+    } while (result == RwLock::LockResult::Overflow);
+
+    (void)block_all_signals(old_mask);
+  }
+
+  LIBC_INLINE ~AbortLockGuard() {
+    (void)restore_signals(old_mask);
+    (void)abort_lock.unlock();
+  }
+};
+
+[[noreturn]] LIBC_INLINE void abort() {
+  // 1. Try to raise SIGABRT.
+  (void)LIBC_NAMESPACE::linux_syscalls::raise(SIGABRT);
+
+  // We get back from abort, potentially from a abort handler.
+  // We recover the handler to default and raise it again. Since this is the
+  // real abort routine, we demand exclusive access to the abort lock.
+  // We have already returned from the first raise, so it is okay to grab
+  // exclusive access.
+  AbortLockGuard guard(true);
+  struct sigaction sa{};
+  sa.sa_handler = SIG_DFL;
+  sa.sa_flags = 0;
+  (void)do_sigaction(SIGABRT, &sa, nullptr);
+  (void)LIBC_NAMESPACE::linux_syscalls::raise(SIGABRT);
+
+  // Now unblock the signal. The pending abort signal is now unblocked and
+  // should be delivered to its default handler.
+  (void)unblock_signal(SIGABRT);
+
+  LIBC_NAMESPACE::internal::exit(127);
+}
+} // namespace abort_utils
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_LINUX_ABORT_UTILS_H
diff --git a/libc/test/integration/src/stdlib/CMakeLists.txt b/libc/test/integration/src/stdlib/CMakeLists.txt
index 1773d9fc9f0f5..cf39b7ceb2f87 100644
--- a/libc/test/integration/src/stdlib/CMakeLists.txt
+++ b/libc/test/integration/src/stdlib/CMakeLists.txt
@@ -16,3 +16,26 @@ add_integration_test(
     FRANCE=Paris
     GERMANY=Berlin
 )
+
+if(${LIBC_TARGET_OS} STREQUAL "linux")
+  add_integration_test(
+    abort_test
+    SUITE
+      stdlib-integration-tests
+    SRCS
+      abort_test.cpp
+    DEPENDS
+      libc.include.signal
+      libc.include.sys_wait
+      libc.include.unistd
+      libc.src.signal.signal
+      libc.src.stdlib._Exit
+      libc.src.stdlib.abort
+      libc.src.sys.wait.waitpid
+      libc.src.unistd.close
+      libc.src.unistd.fork
+      libc.src.unistd.pipe
+      libc.src.unistd.read
+      libc.src.unistd.write
+  )
+endif()
diff --git a/libc/test/integration/src/stdlib/abort_test.cpp b/libc/test/integration/src/stdlib/abort_test.cpp
new file mode 100644
index 0000000000000..5b8a38655ef8c
--- /dev/null
+++ b/libc/test/integration/src/stdlib/abort_test.cpp
@@ -0,0 +1,89 @@
+//===-- Integration tests for abort --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/signal/signal.h"
+#include "src/stdlib/_Exit.h"
+#include "src/stdlib/abort.h"
+#include "src/stdlib/linux/abort_utils.h"
+#include "src/sys/wait/waitpid.h"
+#include "src/unistd/close.h"
+#include "src/unistd/fork.h"
+#include "src/unistd/pipe.h"
+#include "src/unistd/read.h"
+#include "src/unistd/write.h"
+
+#include "test/IntegrationTest/test.h"
+
+#include <signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace {
+
+constexpr char HANDLER_MARKER = 'A';
+int handler_pipe_fd = -1;
+
+void expect_child_died_with_signal(pid_t pid, int signal) {
+  int status = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::waitpid(pid, &status, 0), pid);
+  ASSERT_TRUE(WIFSIGNALED(status));
+  ASSERT_EQ(WTERMSIG(status), signal);
+}
+
+void child_abort() { LIBC_NAMESPACE::abort(); }
+
+void returning_sigabrt_handler(int) {
+  if (handler_pipe_fd >= 0)
+    LIBC_NAMESPACE::write(handler_pipe_fd, &HANDLER_MARKER, 1);
+}
+
+void child_abort_with_returning_handler() {
+  auto previous = LIBC_NAMESPACE::signal(SIGABRT, returning_sigabrt_handler);
+  ASSERT_NE(previous, SIG_ERR);
+  LIBC_NAMESPACE::abort();
+}
+
+void abort_kills_child_with_sigabrt() {
+  pid_t pid = LIBC_NAMESPACE::fork();
+  if (pid == 0)
+    child_abort();
+
+  ASSERT_TRUE(pid > 0);
+  expect_child_died_with_signal(pid, SIGABRT);
+}
+
+void abort_reraises_sigabrt_after_returning_handler() {
+  int pipefd[2];
+  ASSERT_EQ(LIBC_NAMESPACE::pipe(pipefd), 0);
+
+  pid_t pid = LIBC_NAMESPACE::fork();
+  if (pid == 0) {
+    LIBC_NAMESPACE::close(pipefd[0]);
+    handler_pipe_fd = pipefd[1];
+    child_abort_with_returning_handler();
+  }
+
+  ASSERT_TRUE(pid > 0);
+  ASSERT_EQ(LIBC_NAMESPACE::close(pipefd[1]), 0);
+
+  expect_child_died_with_signal(pid, SIGABRT);
+
+  char marker = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::read(pipefd[0], &marker, 1), ssize_t(1));
+  ASSERT_EQ(marker, HANDLER_MARKER);
+  ASSERT_EQ(LIBC_NAMESPACE::close(pipefd[0]), 0);
+}
+
+} // namespace
+
+TEST_MAIN([[maybe_unused]] int argc, [[maybe_unused]] char **argv,
+          [[maybe_unused]] char **envp) {
+  abort_kills_child_with_sigabrt();
+  abort_reraises_sigabrt_after_returning_handler();
+  return 0;
+}

>From 87eb626c1a325625b8fd8e8200db8173fc3ac249 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 1 Apr 2026 10:17:51 -0400
Subject: [PATCH 2/5] fix

---
 libc/src/stdlib/linux/CMakeLists.txt | 2 +-
 libc/src/stdlib/linux/abort_utils.h  | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt
index 4e476d8d57354..ca09842fa906d 100644
--- a/libc/src/stdlib/linux/CMakeLists.txt
+++ b/libc/src/stdlib/linux/CMakeLists.txt
@@ -6,7 +6,7 @@ add_header_library(
     libc.include.stdlib
     libc.src.signal.raise
     libc.src.__support.OSUtil.osutil
-    libc.src.__support.threads.linux.rwlock
+    libc.src.__support.threads.raw_rwlock
     libc.src.signal.linux.__restore
 )
 
diff --git a/libc/src/stdlib/linux/abort_utils.h b/libc/src/stdlib/linux/abort_utils.h
index c4795c879ae08..5e686f0c3475a 100644
--- a/libc/src/stdlib/linux/abort_utils.h
+++ b/libc/src/stdlib/linux/abort_utils.h
@@ -17,7 +17,7 @@
 #include "src/__support/OSUtil/syscall.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/threads/linux/rwlock.h"
+#include "src/__support/threads/raw_rwlock.h"
 #include "src/signal/linux/signal_utils.h"
 
 namespace LIBC_NAMESPACE_DECL {
@@ -28,17 +28,17 @@ namespace abort_utils {
 class AbortLockGuard {
 private:
   sigset_t old_mask;
-  LIBC_INLINE_VAR static RwLock abort_lock;
+  LIBC_INLINE_VAR static RawRwLock abort_lock;
 
 public:
   LIBC_INLINE constexpr AbortLockGuard(bool exclusive) : old_mask{} {
-    RwLock::LockResult result = RwLock::LockResult::Success;
+    RawRwLock::LockResult result = RawRwLock::LockResult::Success;
     do {
       if (exclusive)
         result = abort_lock.write_lock(cpp::nullopt);
       else
         result = abort_lock.read_lock(cpp::nullopt);
-    } while (result == RwLock::LockResult::Overflow);
+    } while (result == RawRwLock::LockResult::Overflow);
 
     (void)block_all_signals(old_mask);
   }

>From ac8cc59295cfa2c691bf12e0b247034e9a75815c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 1 Apr 2026 10:18:46 -0400
Subject: [PATCH 3/5] fix trivial auto var

---
 libc/src/signal/linux/signal_utils.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/signal/linux/signal_utils.h b/libc/src/signal/linux/signal_utils.h
index e36d47f4fb602..66e55943a2c3f 100644
--- a/libc/src/signal/linux/signal_utils.h
+++ b/libc/src/signal/linux/signal_utils.h
@@ -114,7 +114,7 @@ LIBC_INLINE int restore_signals(const sigset_t &set) {
 }
 
 LIBC_INLINE int unblock_signal(int signal) {
-  sigset_t set;
+  sigset_t set = empty_set();
   if (!add_signal(set, signal))
     return -EINVAL;
   return LIBC_NAMESPACE::syscall_impl<int>(SYS_rt_sigprocmask, SIG_UNBLOCK,

>From 0086fb5b41a88a8699a458a4b817269016ad9f4d Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 1 Apr 2026 10:41:43 -0400
Subject: [PATCH 4/5] fix

---
 libc/src/signal/linux/CMakeLists.txt |  1 +
 libc/src/signal/linux/sigaction.cpp  |  2 +-
 libc/src/signal/linux/signal_utils.h | 46 ++++++++++++++++++++++++++--
 libc/src/stdlib/linux/CMakeLists.txt |  1 -
 libc/src/stdlib/linux/abort_utils.h  | 35 ++-------------------
 5 files changed, 49 insertions(+), 36 deletions(-)

diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index 44c41737b89b0..45ffb6994573b 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -11,6 +11,7 @@ add_header_library(
     libc.src.__support.OSUtil.linux.vdso
     libc.src.__support.OSUtil.osutil
     libc.src.__support.error_or
+    libc.src.__support.threads.raw_rwlock
 )
 
 add_entrypoint_object(
diff --git a/libc/src/signal/linux/sigaction.cpp b/libc/src/signal/linux/sigaction.cpp
index 9e76c188ed440..c763718278467 100644
--- a/libc/src/signal/linux/sigaction.cpp
+++ b/libc/src/signal/linux/sigaction.cpp
@@ -18,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
 LLVM_LIBC_FUNCTION(int, sigaction,
                    (int signal, const struct sigaction *__restrict libc_new,
                     struct sigaction *__restrict libc_old)) {
-  ErrorOr<int> ret = do_sigaction(signal, libc_new, libc_old);
+  ErrorOr<int> ret = checked_sigaction(signal, libc_new, libc_old);
   if (ret)
     return ret.value();
 
diff --git a/libc/src/signal/linux/signal_utils.h b/libc/src/signal/linux/signal_utils.h
index 66e55943a2c3f..d7eb55f1be9f5 100644
--- a/libc/src/signal/linux/signal_utils.h
+++ b/libc/src/signal/linux/signal_utils.h
@@ -19,6 +19,7 @@
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/threads/raw_rwlock.h"
 
 #include <sys/syscall.h> // For syscall numbers.
 
@@ -121,9 +122,38 @@ LIBC_INLINE int unblock_signal(int signal) {
                                            &set, nullptr, sizeof(sigset_t));
 }
 
+// This guard is used to:
+// 1. temporarily block the all signal, avoid post fork invalid state to be
+//    exposed to async signal handlers.
+// 2. ensure the ordering between sigaction and fork/spawn, so that forked
+//    processes can see modification from a just returned concurrent call.
+class SigAbortGuard {
+private:
+  sigset_t old_mask;
+  LIBC_INLINE_VAR static RawRwLock abort_lock;
+
+public:
+  LIBC_INLINE constexpr SigAbortGuard(bool exclusive) : old_mask{} {
+    RawRwLock::LockResult result = RawRwLock::LockResult::Success;
+    do {
+      if (exclusive)
+        result = abort_lock.write_lock(cpp::nullopt);
+      else
+        result = abort_lock.read_lock(cpp::nullopt);
+    } while (result == RawRwLock::LockResult::Overflow);
+
+    (void)block_all_signals(old_mask);
+  }
+
+  LIBC_INLINE ~SigAbortGuard() {
+    (void)restore_signals(old_mask);
+    (void)abort_lock.unlock();
+  }
+};
+
 LIBC_INLINE ErrorOr<int>
-do_sigaction(int signal, const struct sigaction *__restrict libc_new,
-             struct sigaction *__restrict libc_old) {
+unchecked_sigaction(int signal, const struct sigaction *__restrict libc_new,
+                    struct sigaction *__restrict libc_old) {
   vdso::TypedSymbol<vdso::VDSOSym::RTSigReturn> rt_sigreturn;
   KernelSigaction kernel_new;
   if (libc_new) {
@@ -146,6 +176,18 @@ do_sigaction(int signal, const struct sigaction *__restrict libc_new,
   return 0;
 }
 
+LIBC_INLINE ErrorOr<int>
+checked_sigaction(int signal, const struct sigaction *__restrict libc_new,
+                  struct sigaction *__restrict libc_old) {
+  if (signal <= 0 || signal >= NSIG)
+    return Error(-EINVAL);
+  if (signal == SIGABRT) {
+    SigAbortGuard guard(true);
+    return unchecked_sigaction(signal, libc_new, libc_old);
+  }
+  return unchecked_sigaction(signal, libc_new, libc_old);
+}
+
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H
diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt
index ca09842fa906d..ac739abba0c26 100644
--- a/libc/src/stdlib/linux/CMakeLists.txt
+++ b/libc/src/stdlib/linux/CMakeLists.txt
@@ -6,7 +6,6 @@ add_header_library(
     libc.include.stdlib
     libc.src.signal.raise
     libc.src.__support.OSUtil.osutil
-    libc.src.__support.threads.raw_rwlock
     libc.src.signal.linux.__restore
 )
 
diff --git a/libc/src/stdlib/linux/abort_utils.h b/libc/src/stdlib/linux/abort_utils.h
index 5e686f0c3475a..daf47e1f08fa6 100644
--- a/libc/src/stdlib/linux/abort_utils.h
+++ b/libc/src/stdlib/linux/abort_utils.h
@@ -10,45 +10,16 @@
 #define LLVM_LIBC_SRC_STDLIB_LINUX_ABORT_UTILS_H
 
 #include "hdr/types/sigset_t.h"
-#include "include/llvm-libc-types/sigset_t.h"
-#include "src/__support/CPP/optional.h"
+#include "hdr/types/struct_sigaction.h"
 #include "src/__support/OSUtil/exit.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/raise.h"
-#include "src/__support/OSUtil/syscall.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/threads/raw_rwlock.h"
 #include "src/signal/linux/signal_utils.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 namespace abort_utils {
-
-// TODO: this lock needs to be acquired during _Fork/fork.
-class AbortLockGuard {
-private:
-  sigset_t old_mask;
-  LIBC_INLINE_VAR static RawRwLock abort_lock;
-
-public:
-  LIBC_INLINE constexpr AbortLockGuard(bool exclusive) : old_mask{} {
-    RawRwLock::LockResult result = RawRwLock::LockResult::Success;
-    do {
-      if (exclusive)
-        result = abort_lock.write_lock(cpp::nullopt);
-      else
-        result = abort_lock.read_lock(cpp::nullopt);
-    } while (result == RawRwLock::LockResult::Overflow);
-
-    (void)block_all_signals(old_mask);
-  }
-
-  LIBC_INLINE ~AbortLockGuard() {
-    (void)restore_signals(old_mask);
-    (void)abort_lock.unlock();
-  }
-};
-
 [[noreturn]] LIBC_INLINE void abort() {
   // 1. Try to raise SIGABRT.
   (void)LIBC_NAMESPACE::linux_syscalls::raise(SIGABRT);
@@ -58,11 +29,11 @@ class AbortLockGuard {
   // real abort routine, we demand exclusive access to the abort lock.
   // We have already returned from the first raise, so it is okay to grab
   // exclusive access.
-  AbortLockGuard guard(true);
+  SigAbortGuard guard(true);
   struct sigaction sa{};
   sa.sa_handler = SIG_DFL;
   sa.sa_flags = 0;
-  (void)do_sigaction(SIGABRT, &sa, nullptr);
+  (void)unchecked_sigaction(SIGABRT, &sa, nullptr);
   (void)LIBC_NAMESPACE::linux_syscalls::raise(SIGABRT);
 
   // Now unblock the signal. The pending abort signal is now unblocked and

>From 88e6368687ea76544c9605083d70ac03a0972deb Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 1 Apr 2026 10:51:16 -0400
Subject: [PATCH 5/5] fix deps and test

---
 libc/src/signal/linux/signal_utils.h | 2 +-
 libc/src/stdlib/linux/CMakeLists.txt | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libc/src/signal/linux/signal_utils.h b/libc/src/signal/linux/signal_utils.h
index d7eb55f1be9f5..bb9b6593f9f4b 100644
--- a/libc/src/signal/linux/signal_utils.h
+++ b/libc/src/signal/linux/signal_utils.h
@@ -180,7 +180,7 @@ LIBC_INLINE ErrorOr<int>
 checked_sigaction(int signal, const struct sigaction *__restrict libc_new,
                   struct sigaction *__restrict libc_old) {
   if (signal <= 0 || signal >= NSIG)
-    return Error(-EINVAL);
+    return Error(EINVAL);
   if (signal == SIGABRT) {
     SigAbortGuard guard(true);
     return unchecked_sigaction(signal, libc_new, libc_old);
diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt
index ac739abba0c26..6f52acdc856ac 100644
--- a/libc/src/stdlib/linux/CMakeLists.txt
+++ b/libc/src/stdlib/linux/CMakeLists.txt
@@ -3,10 +3,10 @@ add_header_library(
   HDRS
     abort_utils.h
   DEPENDS
-    libc.include.stdlib
-    libc.src.signal.raise
+    libc.src.__support.OSUtil.linux.syscall_wrappers.raise
     libc.src.__support.OSUtil.osutil
     libc.src.signal.linux.__restore
+    libc.src.signal.linux.signal_utils
 )
 
 add_entrypoint_object(



More information about the libc-commits mailing list