[libc-commits] [libc] 4d35055 - [libc] Add sigaction
Alex Brachet via libc-commits
libc-commits at lists.llvm.org
Tue Mar 17 22:10:18 PDT 2020
Author: Alex Brachet
Date: 2020-03-18T01:08:59-04:00
New Revision: 4d35055635ab91e640e8ae67c312ea6091ef7dae
URL: https://github.com/llvm/llvm-project/commit/4d35055635ab91e640e8ae67c312ea6091ef7dae
DIFF: https://github.com/llvm/llvm-project/commit/4d35055635ab91e640e8ae67c312ea6091ef7dae.diff
LOG: [libc] Add sigaction
Summary: This patch adds `sigaction` and the `sa_restorer` signal trampoline function `__restore_rt`
Reviewers: sivachandra, MaskRay, PaulkaToast
Reviewed By: sivachandra
Subscribers: gchatelet, mgorny, tschuett, libc-commits
Differential Revision: https://reviews.llvm.org/D75802
Added:
libc/src/signal/linux/__restore.cpp
libc/src/signal/linux/sigaction.cpp
libc/src/signal/sigaction.h
libc/test/src/signal/sigaction_test.cpp
Modified:
libc/config/linux/api.td
libc/config/linux/signal.h.in
libc/lib/CMakeLists.txt
libc/spec/posix.td
libc/spec/stdc.td
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 aecdce206f65..e9391cb52feb 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -180,9 +180,28 @@ def SysMManAPI : PublicAPI<"sys/mman.h"> {
];
}
+def StructSigactionDefn : TypeDecl<"struct sigaction"> {
+ let Decl = [{
+ struct __sigaction {
+ union {
+ void (*sa_handler)(int);
+ void (*sa_action)(int, siginfo_t *, void *);
+ };
+ sigset_t sa_mask;
+ int sa_flags;
+ void (*sa_restorer)(void);
+ };
+ }];
+}
+
def SignalAPI : PublicAPI<"signal.h"> {
+ let TypeDeclarations = [
+ StructSigactionDefn,
+ ];
+
let Functions = [
"raise",
+ "sigaction",
"sigprocmask",
"sigemptyset",
"sigaddset",
diff --git a/libc/config/linux/signal.h.in b/libc/config/linux/signal.h.in
index 1c2a30779f2b..fc7ca9a54206 100644
--- a/libc/config/linux/signal.h.in
+++ b/libc/config/linux/signal.h.in
@@ -9,3 +9,7 @@
%%begin()
#include <linux/signal.h>
+
+#ifndef __LLVM_LIBC_INTERNAL_SIGACTION
+#define sigaction __sigaction
+#endif
diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt
index 238bcb447512..832d79c1e859 100644
--- a/libc/lib/CMakeLists.txt
+++ b/libc/lib/CMakeLists.txt
@@ -18,6 +18,7 @@ add_entrypoint_library(
# signal.h entrypoints
raise
+ sigaction
sigaddset
sigemptyset
sigprocmask
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index edd670a5f149..172b0c30fede 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -4,6 +4,12 @@ def ConstSigSetPtrType : ConstType<SigSetPtrType>;
def RestrictSigSetType : RestrictedPtrType<SigSetType>;
def ConstRestrictSigSetType : ConstType<RestrictSigSetType>;
+def StructSigaction : NamedType<"struct sigaction">;
+def StructSigactionPtr : PtrType<StructSigaction>;
+def ConstStructSigactionPtr : ConstType<StructSigactionPtr>;
+def RestrictStructSigactionPtr : RestrictedPtrType<StructSigaction>;
+def ConstRestrictStructSigactionPtr : ConstType<RestrictStructSigactionPtr>;
+
def POSIX : StandardSpec<"POSIX"> {
NamedType OffTType = NamedType<"off_t">;
@@ -137,9 +143,19 @@ def POSIX : StandardSpec<"POSIX"> {
HeaderSpec Signal = HeaderSpec<
"signal.h",
[], // Macros
- [], // Types
+ [
+ SigSetType,
+ StructSigaction,
+ ],
[], // Enumerations
[
+ FunctionSpec<
+ "sigaction",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>,
+ ArgSpec<ConstRestrictStructSigactionPtr>,
+ ArgSpec<RestrictStructSigactionPtr>]
+ >,
FunctionSpec<
"sigprocmask",
RetValSpec<IntType>,
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 4df855056e9b..dfac8ebed3c7 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -225,7 +225,6 @@ def StdC : StandardSpec<"stdc"> {
Macro<"SIGTERM">
],
[
- NamedType<"sigset_t">,
SizeTType,
],
[], // Enumerations
diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index 022f41b5a0eb..1d59b7502f7b 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -12,6 +12,39 @@ add_entrypoint_object(
signal_h
)
+add_object(
+ __restore
+ SRC
+ __restore.cpp
+ COMPILE_OPTIONS
+ -fomit-frame-pointer
+ -O3
+ -Wframe-larger-than=0
+ -Werror
+ -Wno-attributes
+ # asan creates asan.module_ctor which uses stack space, causing warinngs.
+ -fno-sanitize=address
+ DEPENDS
+ linux_syscall_h
+ sys_syscall_h
+)
+
+add_entrypoint_object(
+ sigaction
+ SRCS
+ sigaction.cpp
+ HDRS
+ signal.h
+ ../sigaction.h
+ DEPENDS
+ __restore
+ sys_syscall_h
+ linux_syscall_h
+ signal_h
+ SPECIAL_OBJECTS
+ __restore
+)
+
add_entrypoint_object(
sigprocmask
SRCS
diff --git a/libc/src/signal/linux/__restore.cpp b/libc/src/signal/linux/__restore.cpp
new file mode 100644
index 000000000000..bfdee4bab1c3
--- /dev/null
+++ b/libc/src/signal/linux/__restore.cpp
@@ -0,0 +1,20 @@
+//===----------------- Linux implementation of __restore_rt ---------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// This file is implemented seperately from sigaction.cpp so that we can
+// strongly control the options this file is compiled with. __restore_rt cannot
+// make any stack allocations so we must ensure this.
+
+#include "config/linux/syscall.h"
+#include "include/sys/syscall.h"
+
+extern "C" void __restore_rt()
+ __attribute__((no_sanitize("thread", "memory", "undefined", "fuzzer"),
+ hidden));
+
+extern "C" void __restore_rt() { __llvm_libc::syscall(SYS_rt_sigreturn); }
diff --git a/libc/src/signal/linux/sigaction.cpp b/libc/src/signal/linux/sigaction.cpp
new file mode 100644
index 000000000000..18caeacb4819
--- /dev/null
+++ b/libc/src/signal/linux/sigaction.cpp
@@ -0,0 +1,56 @@
+//===----------------- Linux implementation of sigaction ------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#define __LLVM_LIBC_INTERNAL_SIGACTION
+#include "src/signal/sigaction.h"
+#include "src/errno/llvmlibc_errno.h"
+#include "src/signal/linux/signal.h"
+
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+// TOOD: Some architectures will have their signal trampoline functions in the
+// vdso, use those when available.
+
+extern "C" void __restore_rt();
+
+template <typename T, typename V>
+static void copySigaction(T &dest, const V &source) {
+ dest.sa_handler = source.sa_handler;
+ dest.sa_mask = source.sa_mask;
+ dest.sa_flags = source.sa_flags;
+ dest.sa_restorer = source.sa_restorer;
+}
+
+int LLVM_LIBC_ENTRYPOINT(sigaction)(
+ int signal, const struct __sigaction *__restrict libc_new,
+ struct __sigaction *__restrict libc_old) {
+ struct sigaction kernel_new;
+ if (libc_new) {
+ copySigaction(kernel_new, *libc_new);
+ if (!(kernel_new.sa_flags & SA_RESTORER)) {
+ kernel_new.sa_flags |= SA_RESTORER;
+ kernel_new.sa_restorer = __restore_rt;
+ }
+ }
+
+ struct sigaction kernel_old;
+ int ret = syscall(SYS_rt_sigaction, signal, libc_new ? &kernel_new : nullptr,
+ libc_old ? &kernel_old : nullptr, sizeof(sigset_t));
+ if (ret) {
+ llvmlibc_errno = -ret;
+ return -1;
+ }
+
+ if (libc_old)
+ copySigaction(*libc_old, kernel_old);
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/signal/sigaction.h b/libc/src/signal/sigaction.h
new file mode 100644
index 000000000000..c2e8f4b39762
--- /dev/null
+++ b/libc/src/signal/sigaction.h
@@ -0,0 +1,22 @@
+//===------------ Implementation header for sigaction --------*- 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_SIGACTION_H
+#define LLVM_LIBC_SRC_SIGNAL_SIGACTION_H
+
+#define __LLVM_LIBC_INTERNAL_SIGACTION
+#include "include/signal.h"
+
+namespace __llvm_libc {
+
+int sigaction(int signal, const struct __sigaction *__restrict libc_new,
+ struct __sigaction *__restrict libc_old);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SIGNAL_SIGACTION_H
diff --git a/libc/test/src/signal/CMakeLists.txt b/libc/test/src/signal/CMakeLists.txt
index 38f6961920d1..db919b6f5d01 100644
--- a/libc/test/src/signal/CMakeLists.txt
+++ b/libc/test/src/signal/CMakeLists.txt
@@ -11,6 +11,21 @@ add_libc_unittest(
signal_h
)
+add_libc_unittest(
+ sigaction_test
+ SUITE
+ libc_signal_unittests
+ SRCS
+ sigaction_test.cpp
+ DEPENDS
+ sigaction
+ raise
+ signal_h
+ errno_h
+ __errno_location
+ __restore
+)
+
add_libc_unittest(
sigprocmask_test
SUITE
diff --git a/libc/test/src/signal/sigaction_test.cpp b/libc/test/src/signal/sigaction_test.cpp
new file mode 100644
index 000000000000..fc7d143a10df
--- /dev/null
+++ b/libc/test/src/signal/sigaction_test.cpp
@@ -0,0 +1,66 @@
+//===----------------------- Unittests for sigaction ----------------------===//
+//
+// 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 "include/errno.h"
+#define __LLVM_LIBC_INTERNAL_SIGACTION
+#include "include/signal.h"
+#include "src/signal/raise.h"
+#include "src/signal/sigaction.h"
+
+#include "utils/UnitTest/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+
+TEST(Sigaction, Invalid) {
+ // -1 is a much larger signal that NSIG, so this should fail.
+ EXPECT_THAT(__llvm_libc::sigaction(-1, nullptr, nullptr), Fails(EINVAL));
+}
+
+// SIGKILL cannot have its action changed, but it can be examined.
+TEST(Sigaction, Sigkill) {
+ struct __sigaction action;
+ EXPECT_THAT(__llvm_libc::sigaction(SIGKILL, nullptr, &action), Succeeds());
+ EXPECT_THAT(__llvm_libc::sigaction(SIGKILL, &action, nullptr), Fails(EINVAL));
+}
+
+static int sigusr1Count;
+static bool correctSignal;
+
+TEST(Sigaction, CustomAction) {
+ // Zero this incase tests get run multiple times in the future.
+ sigusr1Count = 0;
+
+ struct __sigaction action;
+ EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+
+ action.sa_handler = +[](int signal) {
+ correctSignal = signal == SIGUSR1;
+ sigusr1Count++;
+ };
+ EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+ __llvm_libc::raise(SIGUSR1);
+ EXPECT_EQ(sigusr1Count, 1);
+ EXPECT_TRUE(correctSignal);
+
+ action.sa_handler = SIG_DFL;
+ EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+ EXPECT_DEATH([] { __llvm_libc::raise(SIGUSR1); }, SIGUSR1);
+}
+
+TEST(Sigaction, Ignore) {
+ struct __sigaction action;
+ EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, nullptr, &action), Succeeds());
+ action.sa_handler = SIG_IGN;
+ EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, &action, nullptr), Succeeds());
+
+ EXPECT_EXITS([] { __llvm_libc::raise(SIGUSR1); }, 0);
+}
More information about the libc-commits
mailing list