[libc-commits] [libc] [libc] Fix sigaltstack with SS_DISABLE (PR #230053)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Thu Oct 8 13:46:54 PDT 2026


https://github.com/kaladron updated https://github.com/llvm/llvm-project/pull/230053

>From 5adffa983622b6fe9bd03250717de607f83b5feb Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Thu, 8 Oct 2026 10:41:49 +0100
Subject: [PATCH 1/2] [libc] Fix sigaltstack with SS_DISABLE

POSIX.1-2024 (IEEE Std 1003.1-2024) states in the DESCRIPTION section
for sigaltstack: "If it is set to SS_DISABLE, the stack is disabled and
ss_sp and ss_size are ignored."

Previously, sigaltstack unconditionally checked that ss_size was at
least MINSIGSTKSZ. This caused valid calls that disable an alternate
signal stack with ss_size = 0 and ss_sp = nullptr to erroneously fail
with ENOMEM.

Only validate ss_size against MINSIGSTKSZ when SS_DISABLE is not set.
Added SigaltstackDisableStack unit tests and verified invalid stack
combinations. Also updated file headers in the touched files.

Assisted-by: Automated tooling, human reviewed.
---
 libc/src/signal/linux/CMakeLists.txt      |  6 +--
 libc/src/signal/linux/sigaltstack.cpp     | 24 +++++-----
 libc/test/src/signal/CMakeLists.txt       |  2 +-
 libc/test/src/signal/sigaltstack_test.cpp | 54 ++++++++++++++++++++---
 4 files changed, 67 insertions(+), 19 deletions(-)

diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index e585aa1a01fce1..663e00fbf249a5 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -74,11 +74,11 @@ add_entrypoint_object(
   HDRS
     ../sigaltstack.h
   DEPENDS
-    libc.include.signal
+    libc.hdr.signal_macros
+    libc.hdr.types.stack_t
     libc.include.sys_syscall
+    libc.src.__support.libc_errno
     libc.src.__support.OSUtil.osutil
-    libc.src.errno.errno
-    libc.hdr.types.stack_t
 )
 
 add_entrypoint_object(
diff --git a/libc/src/signal/linux/sigaltstack.cpp b/libc/src/signal/linux/sigaltstack.cpp
index 990b841c6d9047..a874cd1064e0bc 100644
--- a/libc/src/signal/linux/sigaltstack.cpp
+++ b/libc/src/signal/linux/sigaltstack.cpp
@@ -1,18 +1,24 @@
-//===-- Linux implementation of sigaltstack -------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // 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
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of sigaltstack.
+///
+//===----------------------------------------------------------------------===//
 
 #include "src/signal/sigaltstack.h"
+
+#include "hdr/signal_macros.h"
 #include "hdr/types/stack_t.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
-#include "src/signal/linux/signal_utils.h"
-
-#include "src/__support/common.h"
 
 #include <sys/syscall.h>
 
@@ -21,15 +27,13 @@ namespace LIBC_NAMESPACE_DECL {
 LLVM_LIBC_FUNCTION(int, sigaltstack,
                    (const stack_t *__restrict ss, stack_t *__restrict oss)) {
   if (ss != nullptr) {
-    unsigned not_ss_disable = ~unsigned(SS_DISABLE);
-    if ((unsigned(ss->ss_flags) & not_ss_disable) != 0) {
-      // Flags cannot have anything other than SS_DISABLE set.
-      // We do the type-casting to unsigned because the |ss_flags|
-      // field of stack_t is of type "int".
+    if (ss->ss_flags != 0 && ss->ss_flags != SS_DISABLE) {
       libc_errno = EINVAL;
       return -1;
     }
-    if (ss->ss_size < MINSIGSTKSZ) {
+    // ss_size is only validated if the alternate stack is being enabled.
+    // When disabling (SS_DISABLE), ss_size and ss_sp are ignored.
+    if (ss->ss_flags != SS_DISABLE && ss->ss_size < MINSIGSTKSZ) {
       libc_errno = ENOMEM;
       return -1;
     }
diff --git a/libc/test/src/signal/CMakeLists.txt b/libc/test/src/signal/CMakeLists.txt
index ac394ea6b7ab75..f22a8a8f0a092c 100644
--- a/libc/test/src/signal/CMakeLists.txt
+++ b/libc/test/src/signal/CMakeLists.txt
@@ -135,9 +135,9 @@ add_libc_test(
   SRCS
     sigaltstack_test.cpp
   DEPENDS
+    libc.hdr.errno_macros
     libc.hdr.signal_macros
     libc.hdr.stdint_proxy
-    libc.src.errno.errno
     libc.src.signal.raise
     libc.src.signal.sigaltstack
     libc.src.signal.sigaction
diff --git a/libc/test/src/signal/sigaltstack_test.cpp b/libc/test/src/signal/sigaltstack_test.cpp
index 43c679b23bb299..200122c0d997f1 100644
--- a/libc/test/src/signal/sigaltstack_test.cpp
+++ b/libc/test/src/signal/sigaltstack_test.cpp
@@ -1,15 +1,19 @@
-//===-- Unittests for sigaltstack -----------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // 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
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for sigaltstack.
+///
+//===----------------------------------------------------------------------===//
 
+#include "hdr/errno_macros.h"
 #include "hdr/signal_macros.h"
 #include "hdr/stdint_proxy.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
-#include "src/signal/linux/signal_utils.h"
 #include "src/signal/raise.h"
 #include "src/signal/sigaction.h"
 #include "src/signal/sigaltstack.h"
@@ -17,8 +21,6 @@
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
 
-#include <sys/syscall.h>
-
 constexpr int LOCAL_VAR_SIZE = 512;
 constexpr int ALT_STACK_SIZE = SIGSTKSZ + LOCAL_VAR_SIZE * 2;
 static uint8_t alt_stack[ALT_STACK_SIZE];
@@ -77,4 +79,46 @@ TEST_F(LlvmLibcSigaltstackTest, SigaltstackInvalidStack) {
 
   ss.ss_flags = 0;
   ASSERT_THAT(LIBC_NAMESPACE::sigaltstack(&ss, nullptr), Fails(ENOMEM));
+
+  // Sub-minimum size without SS_DISABLE should fail with ENOMEM.
+  ss.ss_size = MINSIGSTKSZ - 1;
+  ASSERT_THAT(LIBC_NAMESPACE::sigaltstack(&ss, nullptr), Fails(ENOMEM));
+
+  // SS_DISABLE combined with unsupported flags should fail with EINVAL.
+  ss.ss_flags = SS_DISABLE | SS_ONSTACK;
+  ASSERT_THAT(LIBC_NAMESPACE::sigaltstack(&ss, nullptr), Fails(EINVAL));
+}
+
+TEST_F(LlvmLibcSigaltstackTest, SigaltstackDisableStack) {
+  // First, set up a valid alternate stack.
+  stack_t ss;
+  ss.ss_sp = alt_stack;
+  ss.ss_size = ALT_STACK_SIZE;
+  ss.ss_flags = 0;
+  ASSERT_THAT(LIBC_NAMESPACE::sigaltstack(&ss, nullptr), Succeeds(0));
+
+  // Disable the alternate stack with ss_size = 0 and ss_sp = nullptr.
+  stack_t disable_ss;
+  disable_ss.ss_sp = nullptr;
+  disable_ss.ss_size = 0;
+  disable_ss.ss_flags = SS_DISABLE;
+  stack_t old_ss;
+  ASSERT_THAT(LIBC_NAMESPACE::sigaltstack(&disable_ss, &old_ss), Succeeds(0));
+  EXPECT_EQ(old_ss.ss_sp, static_cast<void *>(alt_stack));
+  EXPECT_EQ(old_ss.ss_size, static_cast<size_t>(ALT_STACK_SIZE));
+  EXPECT_EQ(old_ss.ss_flags, 0);
+
+  // Verify that subsequent query reports SS_DISABLE and zeroed stack info.
+  stack_t current_ss;
+  ASSERT_THAT(LIBC_NAMESPACE::sigaltstack(nullptr, &current_ss), Succeeds(0));
+  EXPECT_EQ(current_ss.ss_flags & SS_DISABLE, SS_DISABLE);
+  EXPECT_EQ(current_ss.ss_sp, nullptr);
+  EXPECT_EQ(current_ss.ss_size, size_t(0));
+
+  // Verify disabling when ss_size is non-zero sub-minimum and ss_sp is non-null
+  // (both should be ignored when SS_DISABLE is set).
+  disable_ss.ss_sp = alt_stack;
+  disable_ss.ss_size = MINSIGSTKSZ - 1;
+  disable_ss.ss_flags = SS_DISABLE;
+  EXPECT_THAT(LIBC_NAMESPACE::sigaltstack(&disable_ss, nullptr), Succeeds(0));
 }

>From eb6caafacffb846637b29f4c59349b5cbfb25036 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Thu, 8 Oct 2026 21:46:31 +0100
Subject: [PATCH 2/2] [libc] Add libc.src.errno.errno to sigaltstack DEPENDS

Add libc.src.errno.errno to the DEPENDS list for sigaltstack to satisfy
the link-time requirement for runtime errno storage.

Assisted-by: Automated tooling, human reviewed.
---
 libc/src/signal/linux/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index 663e00fbf249a5..8360ce21364766 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -79,6 +79,7 @@ add_entrypoint_object(
     libc.include.sys_syscall
     libc.src.__support.libc_errno
     libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
 )
 
 add_entrypoint_object(



More information about the libc-commits mailing list