[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
This commit is contained in:
parent
9bca8fc4cf
commit
4d35055635
@ -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",
|
||||
|
||||
@ -9,3 +9,7 @@
|
||||
%%begin()
|
||||
|
||||
#include <linux/signal.h>
|
||||
|
||||
#ifndef __LLVM_LIBC_INTERNAL_SIGACTION
|
||||
#define sigaction __sigaction
|
||||
#endif
|
||||
|
||||
@ -18,6 +18,7 @@ add_entrypoint_library(
|
||||
|
||||
# signal.h entrypoints
|
||||
raise
|
||||
sigaction
|
||||
sigaddset
|
||||
sigemptyset
|
||||
sigprocmask
|
||||
|
||||
@ -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>,
|
||||
|
||||
@ -225,7 +225,6 @@ def StdC : StandardSpec<"stdc"> {
|
||||
Macro<"SIGTERM">
|
||||
],
|
||||
[
|
||||
NamedType<"sigset_t">,
|
||||
SizeTType,
|
||||
],
|
||||
[], // Enumerations
|
||||
|
||||
@ -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
|
||||
|
||||
20
libc/src/signal/linux/__restore.cpp
Normal file
20
libc/src/signal/linux/__restore.cpp
Normal file
@ -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); }
|
||||
56
libc/src/signal/linux/sigaction.cpp
Normal file
56
libc/src/signal/linux/sigaction.cpp
Normal file
@ -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
|
||||
22
libc/src/signal/sigaction.h
Normal file
22
libc/src/signal/sigaction.h
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
66
libc/test/src/signal/sigaction_test.cpp
Normal file
66
libc/test/src/signal/sigaction_test.cpp
Normal file
@ -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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user