From: Siva Chandra Reddy Date: Thu, 13 Oct 2022 22:18:52 +0000 (+0000) Subject: [libc] Add implementation of sigaltstack for linux. X-Git-Tag: upstream/17.0.6~30169 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=67957368ae9776ec25db80c69f772e40c75ed690;p=platform%2Fupstream%2Fllvm.git [libc] Add implementation of sigaltstack for linux. Reviewed By: michaelrj Differential Revision: https://reviews.llvm.org/D135949 --- diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index 9423827..8067d1e 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -210,6 +210,7 @@ def SignalAPI : PublicAPI<"signal.h"> { "struct sigaction", "union sigval", "siginfo_t", + "stack_t", "pid_t", ]; } diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 6afd1bf..a05c451 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -400,6 +400,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.signal.raise libc.src.signal.kill libc.src.signal.sigaction + libc.src.signal.sigaltstack libc.src.signal.sigdelset libc.src.signal.sigaddset libc.src.signal.sigemptyset diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 8f7a505..cd614ab 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -136,6 +136,7 @@ add_gen_header( .llvm-libc-macros.signal_macros .llvm-libc-types.struct_sigaction .llvm-libc-types.__sighandler_t + .llvm-libc-types.stack_t .llvm-libc-types.sigset_t .llvm-libc-types.pid_t ) diff --git a/libc/include/llvm-libc-macros/linux/signal-macros.h b/libc/include/llvm-libc-macros/linux/signal-macros.h index 9fe71d1..069a233 100644 --- a/libc/include/llvm-libc-macros/linux/signal-macros.h +++ b/libc/include/llvm-libc-macros/linux/signal-macros.h @@ -70,6 +70,21 @@ #define SA_SIGINFO 0x00000004 #define SA_RESTART 0x10000000 #define SA_RESTORER 0x04000000 +#define SA_ONSTACK 0x08000000 + +// Signal stack flags +#define SS_ONSTACK 0x1 +#define SS_DISABLE 0x2 + +#ifdef __x86_64__ +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#elif defined(__aarch64__) +#define MINSIGSTKSZ 5120 +#define SIGSTKSZ 16384 +#else +#error "Signal stack sizes not defined for your platform." +#endif #define SIG_DFL ((__sighandler_t)0) #define SIG_IGN ((__sighandler_t)1) diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index 2e8bded..40717f7 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -50,6 +50,7 @@ add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h) add_header(pthread_once_t HDR pthread_once_t.h DEPENDS .__futex_word) add_header(rlim_t HDR rlim_t.h) add_header(time_t HDR time_t.h) +add_header(stack_t HDR stack_t.h) add_header(suseconds_t HDR suseconds_t.h) add_header(struct_timeval HDR struct_timeval.h DEPENDS .suseconds_t .time_t) add_header(struct_rlimit HDR struct_rlimit.h DEPENDS .rlim_t) diff --git a/libc/include/llvm-libc-types/stack_t.h b/libc/include/llvm-libc-types/stack_t.h new file mode 100644 index 0000000..f564d91 --- /dev/null +++ b/libc/include/llvm-libc-types/stack_t.h @@ -0,0 +1,22 @@ +//===-- Definition of stack_t type ----------------------------------------===// +// +// 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_TYPES_STACK_T_H__ +#define __LLVM_LIBC_TYPES_STACK_T_H__ + +#include + +typedef struct { + // The order of the fields declared here should match the kernel definition + // of stack_t in order for the SYS_sigaltstack syscall to work correctly. + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#endif // __LLVM_LIBC_TYPES_STACK_T_H__ diff --git a/libc/spec/posix.td b/libc/spec/posix.td index 2f27eb2..38ca165 100644 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -65,6 +65,11 @@ def StructTermiosPtr : PtrType; def ConstStructTermiosPtr : ConstType; def TcFlagT : NamedType<"tcflag_t">; +def StackT : NamedType<"stack_t">; +def StackTPtr : PtrType; +def RestrictedStackTPtr : RestrictedPtrType; +def ConstRestrictedStackTPtr : ConstType; + def POSIX : StandardSpec<"POSIX"> { PtrType CharPtr = PtrType; RestrictedPtrType RestrictedCharPtr = RestrictedPtrType; @@ -273,6 +278,7 @@ def POSIX : StandardSpec<"POSIX"> { [ SigInfoType, SigSetType, + StackT, StructSigaction, UnionSigVal, PidT, @@ -293,6 +299,11 @@ def POSIX : StandardSpec<"POSIX"> { ArgSpec] >, FunctionSpec< + "sigaltstack", + RetValSpec, + [ArgSpec, ArgSpec] + >, + FunctionSpec< "sigdelset", RetValSpec, [ArgSpec, diff --git a/libc/src/signal/CMakeLists.txt b/libc/src/signal/CMakeLists.txt index 8627ecb..c70ab95 100644 --- a/libc/src/signal/CMakeLists.txt +++ b/libc/src/signal/CMakeLists.txt @@ -24,6 +24,13 @@ add_entrypoint_object( ) add_entrypoint_object( + sigaltstack + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sigaltstack +) + +add_entrypoint_object( sigprocmask ALIAS DEPENDS diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt index 9800db8..46297c2 100644 --- a/libc/src/signal/linux/CMakeLists.txt +++ b/libc/src/signal/linux/CMakeLists.txt @@ -66,6 +66,19 @@ add_entrypoint_object( ) add_entrypoint_object( + sigaltstack + SRCS + sigaltstack.cpp + HDRS + ../sigaltstack.h + DEPENDS + libc.include.signal + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( sigprocmask SRCS sigprocmask.cpp diff --git a/libc/src/signal/linux/sigaltstack.cpp b/libc/src/signal/linux/sigaltstack.cpp new file mode 100644 index 0000000..7af9106 --- /dev/null +++ b/libc/src/signal/linux/sigaltstack.cpp @@ -0,0 +1,45 @@ +//===-- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/signal/sigaltstack.h" +#include "src/signal/linux/signal_utils.h" + +#include "src/__support/common.h" + +#include +#include +#include + +namespace __llvm_libc { + +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". + errno = EINVAL; + return -1; + } + if (ss->ss_size < MINSIGSTKSZ) { + errno = ENOMEM; + return -1; + } + } + + int ret = __llvm_libc::syscall_impl(SYS_sigaltstack, ss, oss); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/signal/sigaltstack.h b/libc/src/signal/sigaltstack.h new file mode 100644 index 0000000..f6c8a4b --- /dev/null +++ b/libc/src/signal/sigaltstack.h @@ -0,0 +1,20 @@ +//===-- Implementation header for sigaltstack -------------------*- 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_SIGNAL_SIGALSTACK_H +#define LLVM_LIBC_SRC_SIGNAL_SIGALSTACK_H + +#include + +namespace __llvm_libc { + +int sigaltstack(const stack_t *__restrict ss, stack_t *__restrict oss); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SIGNAL_SIGALSTACK_H diff --git a/libc/test/src/signal/CMakeLists.txt b/libc/test/src/signal/CMakeLists.txt index 8855743..030a154 100644 --- a/libc/test/src/signal/CMakeLists.txt +++ b/libc/test/src/signal/CMakeLists.txt @@ -115,3 +115,17 @@ add_libc_unittest( libc.src.signal.sigprocmask libc.test.errno_setter_matcher ) + +add_libc_unittest( + sigaltstack_test + SUITE + libc_signal_unittests + SRCS + sigaltstack_test.cpp + DEPENDS + libc.include.errno + libc.include.signal + 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 new file mode 100644 index 0000000..3920c0d --- /dev/null +++ b/libc/test/src/signal/sigaltstack_test.cpp @@ -0,0 +1,79 @@ +//===-- 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 +// +//===----------------------------------------------------------------------===// + +#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" + +#include "test/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" + +#include +#include +#include +#include + +constexpr int LOCAL_VAR_SIZE = 512; +constexpr int ALT_STACK_SIZE = SIGSTKSZ + LOCAL_VAR_SIZE * 2; +static uint8_t alt_stack[ALT_STACK_SIZE]; + +using __llvm_libc::testing::ErrnoSetterMatcher::Fails; +using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + +static bool good_stack; +static void handler(int) { + // Allocate a large stack variable so that it does not get optimized + // out or mapped to a register. + uint8_t var[LOCAL_VAR_SIZE]; + for (int i = 0; i < LOCAL_VAR_SIZE; ++i) + var[i] = i; + // Verify that array is completely on the alt_stack. + for (int i = 0; i < LOCAL_VAR_SIZE; ++i) { + if (!(uintptr_t(var + i) < uintptr_t(alt_stack + ALT_STACK_SIZE) && + uintptr_t(alt_stack) <= uintptr_t(var + i))) { + good_stack = false; + return; + } + } + good_stack = true; +} + +TEST(LlvmLibcSignalTest, SigaltstackRunOnAltStack) { + struct sigaction action; + errno = 0; + ASSERT_THAT(__llvm_libc::sigaction(SIGUSR1, nullptr, &action), Succeeds(0)); + action.sa_handler = handler; + // Indicate that the signal should be delivered on an alternate stack. + action.sa_flags = SA_ONSTACK; + ASSERT_THAT(__llvm_libc::sigaction(SIGUSR1, &action, nullptr), Succeeds(0)); + + stack_t ss; + ss.ss_sp = alt_stack; + ss.ss_size = ALT_STACK_SIZE; + ss.ss_flags = 0; + // Setup the alternate stack. + ASSERT_THAT(__llvm_libc::sigaltstack(&ss, nullptr), Succeeds(0)); + + good_stack = false; + __llvm_libc::raise(SIGUSR1); + EXPECT_TRUE(good_stack); +} + +// This tests for invalid input. +TEST(LlvmLibcSignalTest, SigaltstackInvalidStack) { + stack_t ss; + ss.ss_sp = alt_stack; + ss.ss_size = 0; + ss.ss_flags = SS_ONSTACK; + ASSERT_THAT(__llvm_libc::sigaltstack(&ss, nullptr), Fails(EINVAL)); + + ss.ss_flags = 0; + ASSERT_THAT(__llvm_libc::sigaltstack(&ss, nullptr), Fails(ENOMEM)); +}