[libc-commits] [libc] 6795736 - [libc] Add implementation of sigaltstack for linux.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Tue Oct 18 15:04:44 PDT 2022


Author: Siva Chandra Reddy
Date: 2022-10-18T22:04:30Z
New Revision: 67957368ae9776ec25db80c69f772e40c75ed690

URL: https://github.com/llvm/llvm-project/commit/67957368ae9776ec25db80c69f772e40c75ed690
DIFF: https://github.com/llvm/llvm-project/commit/67957368ae9776ec25db80c69f772e40c75ed690.diff

LOG: [libc] Add implementation of sigaltstack for linux.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D135949

Added: 
    libc/include/llvm-libc-types/stack_t.h
    libc/src/signal/linux/sigaltstack.cpp
    libc/src/signal/sigaltstack.h
    libc/test/src/signal/sigaltstack_test.cpp

Modified: 
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/CMakeLists.txt
    libc/include/llvm-libc-macros/linux/signal-macros.h
    libc/include/llvm-libc-types/CMakeLists.txt
    libc/spec/posix.td
    libc/src/signal/CMakeLists.txt
    libc/src/signal/linux/CMakeLists.txt
    libc/test/src/signal/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 9423827b55826..8067d1ec17abf 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 6afd1bf4f6925..a05c451c9d1b7 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 8f7a505186e6b..cd614ab81bfd0 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 9fe71d1c75d81..069a233477979 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 2e8bded262f1f..40717f7549400 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 0000000000000..f564d9134010b
--- /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 <llvm-libc-types/size_t.h>
+
+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 2f27eb2b3cc44..38ca165fb5f70 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -65,6 +65,11 @@ def StructTermiosPtr : PtrType<StructTermios>;
 def ConstStructTermiosPtr : ConstType<StructTermiosPtr>;
 def TcFlagT : NamedType<"tcflag_t">;
 
+def StackT : NamedType<"stack_t">;
+def StackTPtr : PtrType<StackT>;
+def RestrictedStackTPtr : RestrictedPtrType<StackT>;
+def ConstRestrictedStackTPtr : ConstType<RestrictedStackTPtr>;
+
 def POSIX : StandardSpec<"POSIX"> {
   PtrType CharPtr = PtrType<CharType>;
   RestrictedPtrType RestrictedCharPtr = RestrictedPtrType<CharType>;
@@ -273,6 +278,7 @@ def POSIX : StandardSpec<"POSIX"> {
       [
         SigInfoType,
         SigSetType,
+        StackT,
         StructSigaction,
         UnionSigVal,
         PidT,
@@ -292,6 +298,11 @@ def POSIX : StandardSpec<"POSIX"> {
            ArgSpec<ConstRestrictedStructSigactionPtr>,
            ArgSpec<RestrictedStructSigactionPtr>]
         >,
+        FunctionSpec<
+          "sigaltstack",
+          RetValSpec<IntType>,
+          [ArgSpec<ConstRestrictedStackTPtr>, ArgSpec<RestrictedStackTPtr>]
+        >,
         FunctionSpec<
           "sigdelset",
           RetValSpec<IntType>,

diff  --git a/libc/src/signal/CMakeLists.txt b/libc/src/signal/CMakeLists.txt
index 8627ecb8cc8ca..c70ab952b9950 100644
--- a/libc/src/signal/CMakeLists.txt
+++ b/libc/src/signal/CMakeLists.txt
@@ -23,6 +23,13 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.sigaction
 )
 
+add_entrypoint_object(
+  sigaltstack
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.sigaltstack
+)
+
 add_entrypoint_object(
   sigprocmask
   ALIAS

diff  --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index 9800db8138ca2..46297c2310375 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -65,6 +65,19 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+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

diff  --git a/libc/src/signal/linux/sigaltstack.cpp b/libc/src/signal/linux/sigaltstack.cpp
new file mode 100644
index 0000000000000..7af9106c7ecc8
--- /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 <errno.h>
+#include <signal.h>
+#include <sys/syscall.h>
+
+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 0000000000000..f6c8a4bebe3f1
--- /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 <signal.h>
+
+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 885574354db37..030a15437c40d 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 0000000000000..3920c0dfe193a
--- /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 <errno.h>
+#include <signal.h>
+#include <stdint.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];
+
+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));
+}


        


More information about the libc-commits mailing list