[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:
Alex Brachet 2020-03-18 01:08:59 -04:00
parent 9bca8fc4cf
commit 4d35055635
11 changed files with 253 additions and 2 deletions

View File

@ -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",

View File

@ -9,3 +9,7 @@
%%begin()
#include <linux/signal.h>
#ifndef __LLVM_LIBC_INTERNAL_SIGACTION
#define sigaction __sigaction
#endif

View File

@ -18,6 +18,7 @@ add_entrypoint_library(
# signal.h entrypoints
raise
sigaction
sigaddset
sigemptyset
sigprocmask

View File

@ -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>,

View File

@ -225,7 +225,6 @@ def StdC : StandardSpec<"stdc"> {
Macro<"SIGTERM">
],
[
NamedType<"sigset_t">,
SizeTType,
],
[], // Enumerations

View File

@ -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

View 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); }

View 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

View 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

View File

@ -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

View 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);
}