[libc-commits] [libc] d86e39a - [libc] Fix sigaltstack with SS_DISABLE (#230053)
via libc-commits
libc-commits at lists.llvm.org
Fri Oct 9 00:17:03 PDT 2026
Author: Jeff Bailey
Date: 2026-10-09T08:16:58+01:00
New Revision: d86e39a0def0d82f4e76a77e9919458e99015193
URL: https://github.com/llvm/llvm-project/commit/d86e39a0def0d82f4e76a77e9919458e99015193
DIFF: https://github.com/llvm/llvm-project/commit/d86e39a0def0d82f4e76a77e9919458e99015193.diff
LOG: [libc] Fix sigaltstack with SS_DISABLE (#230053)
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.
Added:
Modified:
libc/src/signal/linux/CMakeLists.txt
libc/src/signal/linux/sigaltstack.cpp
libc/test/src/signal/CMakeLists.txt
libc/test/src/signal/sigaltstack_test.cpp
Removed:
################################################################################
diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index e585aa1a01fce1..8360ce21364766 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -74,11 +74,12 @@ 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, ¤t_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));
}
More information about the libc-commits
mailing list