[libc] Add implementation of sigaltstack for linux.
Reviewed By: michaelrj Differential Revision: https://reviews.llvm.org/D135949
This commit is contained in:
parent
09dcb933ef
commit
67957368ae
|
@ -210,6 +210,7 @@ def SignalAPI : PublicAPI<"signal.h"> {
|
|||
"struct sigaction",
|
||||
"union sigval",
|
||||
"siginfo_t",
|
||||
"stack_t",
|
||||
"pid_t",
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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__
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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));
|
||||
}
|
Loading…
Reference in New Issue