[libc-commits] [libc] [libc] Implement SA_NODEFER and SA_RESETHAND signal flags (PR #209429)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Tue Jul 14 03:20:33 PDT 2026


https://github.com/kaladron created https://github.com/llvm/llvm-project/pull/209429

Defined SA_NODEFER and SA_RESETHAND in Linux signal-macros.h.

Added unit tests in sigaction_test.cpp to verify the behavior of the new flags. Also added a test case for SA_SIGINFO.

Assisted-by: Automated tooling, human reviewed.

>From e8fda9fc4b71c909825dba39fde6d564c9a77e04 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Tue, 14 Jul 2026 08:09:48 +0100
Subject: [PATCH] [libc] Implement SA_NODEFER and SA_RESETHAND signal flags

Defined SA_NODEFER and SA_RESETHAND in Linux signal-macros.h.

Added unit tests in sigaction_test.cpp to verify the behavior of the new flags. Also added a test case for SA_SIGINFO.

Assisted-by: Automated tooling, human reviewed.
---
 .../llvm-libc-macros/linux/signal-macros.h    |   2 +
 libc/test/src/signal/sigaction_test.cpp       | 105 ++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/libc/include/llvm-libc-macros/linux/signal-macros.h b/libc/include/llvm-libc-macros/linux/signal-macros.h
index e7f268df87cba..b74d81683ac5e 100644
--- a/libc/include/llvm-libc-macros/linux/signal-macros.h
+++ b/libc/include/llvm-libc-macros/linux/signal-macros.h
@@ -73,6 +73,8 @@
 #define SA_RESTART 0x10000000
 #define SA_RESTORER 0x04000000
 #define SA_ONSTACK 0x08000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
 
 // Signal stack flags
 #define SS_ONSTACK 0x1
diff --git a/libc/test/src/signal/sigaction_test.cpp b/libc/test/src/signal/sigaction_test.cpp
index a12d7989586fe..c26cc4927e70f 100644
--- a/libc/test/src/signal/sigaction_test.cpp
+++ b/libc/test/src/signal/sigaction_test.cpp
@@ -63,3 +63,108 @@ TEST(LlvmLibcSigaction, Ignore) {
 
   EXPECT_EXITS([] { LIBC_NAMESPACE::raise(SIGUSR1); }, 0);
 }
+
+struct ResethandTest {
+  inline static int counter = 0;
+  static void handler(int) { counter++; }
+};
+
+// Verify that SA_RESETHAND resets the signal handler to SIG_DFL after one
+// execution.
+TEST(LlvmLibcSigaction, Resethand) {
+  ResethandTest::counter = 0;
+  struct sigaction action;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+  action.sa_handler = ResethandTest::handler;
+  action.sa_flags = SA_RESETHAND;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+  LIBC_NAMESPACE::raise(SIGUSR1);
+  EXPECT_EQ(ResethandTest::counter, 1);
+
+  // The handler should have been reset to SIG_DFL.
+  struct sigaction old_action;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &old_action),
+              Succeeds());
+  EXPECT_EQ(old_action.sa_handler, SIG_DFL);
+}
+
+struct NodeferTest {
+  inline static int max_depth = 0;
+  inline static int depth = 0;
+  static void handler(int sig) {
+    depth++;
+    if (depth > max_depth)
+      max_depth = depth;
+    if (depth < 3)
+      LIBC_NAMESPACE::raise(sig);
+    depth--;
+  }
+};
+
+struct WithoutNodeferTest {
+  inline static int calls = 0;
+  inline static int max_depth = 0;
+  inline static int depth = 0;
+  static void handler(int sig) {
+    depth++;
+    calls++;
+    if (depth > max_depth)
+      max_depth = depth;
+    if (calls == 1)
+      LIBC_NAMESPACE::raise(sig);
+    depth--;
+  }
+};
+
+// Verify that SA_NODEFER allows recursive/nested signal delivery.
+TEST(LlvmLibcSigaction, Nodefer) {
+  NodeferTest::max_depth = 0;
+  NodeferTest::depth = 0;
+  struct sigaction action;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+  action.sa_handler = NodeferTest::handler;
+  action.sa_flags = SA_NODEFER;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+  LIBC_NAMESPACE::raise(SIGUSR1);
+  EXPECT_EQ(NodeferTest::max_depth, 3);
+
+  // Test without SA_NODEFER (default behavior: signal is blocked)
+  WithoutNodeferTest::max_depth = 0;
+  WithoutNodeferTest::depth = 0;
+  WithoutNodeferTest::calls = 0;
+  action.sa_handler = WithoutNodeferTest::handler;
+  action.sa_flags = 0;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+  LIBC_NAMESPACE::raise(SIGUSR1);
+  EXPECT_EQ(WithoutNodeferTest::max_depth, 1);
+  EXPECT_EQ(WithoutNodeferTest::calls, 2);
+}
+
+struct SiginfoTest {
+  inline static bool received = false;
+  inline static int signo = 0;
+  static void handler(int, siginfo_t *info, void *) {
+    received = true;
+    if (!info)
+      return;
+    signo = info->si_signo;
+  }
+};
+
+// Verify that SA_SIGINFO invokes the sa_sigaction handler with siginfo_t.
+TEST(LlvmLibcSigaction, Siginfo) {
+  SiginfoTest::received = false;
+  SiginfoTest::signo = 0;
+  struct sigaction action;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+  action.sa_sigaction = SiginfoTest::handler;
+  action.sa_flags = SA_SIGINFO;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+  LIBC_NAMESPACE::raise(SIGUSR1);
+  EXPECT_TRUE(SiginfoTest::received);
+  EXPECT_EQ(SiginfoTest::signo, SIGUSR1);
+}



More information about the libc-commits mailing list