#include "msan_report.h"
#include "msan_thread.h"
#include "msan_poisoning.h"
+#include "sanitizer_common/sanitizer_errno_codes.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
#include "sanitizer_common/sanitizer_allocator.h"
static int sigaction_impl(int signo, const __sanitizer_sigaction *act,
__sanitizer_sigaction *oldact) {
ENSURE_MSAN_INITED();
+ if (signo <= 0 || signo >= kMaxSignals) {
+ errno = errno_EINVAL;
+ return -1;
+ }
if (act) read_sigaction(act);
int res;
if (flags()->wrap_signals) {
SpinMutexLock lock(&sigactions_mu);
- CHECK_LT(signo, kMaxSignals);
uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
__sanitizer_sigaction new_act;
__sanitizer_sigaction *pnew_act = act ? &new_act : nullptr;
static uptr signal_impl(int signo, uptr cb) {
ENSURE_MSAN_INITED();
+ if (signo <= 0 || signo >= kMaxSignals) {
+ errno = errno_EINVAL;
+ return -1;
+ }
if (flags()->wrap_signals) {
- CHECK_LT(signo, kMaxSignals);
SpinMutexLock lock(&sigactions_mu);
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
atomic_store(&sigactions[signo], cb, memory_order_relaxed);
--- /dev/null
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <climits>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <initializer_list>
+
+constexpr int std_signals[] = {
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGIOT,
+ SIGBUS,
+ SIGFPE,
+ SIGUSR1,
+ SIGSEGV,
+ SIGUSR2,
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ SIGCHLD,
+ SIGCONT,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU,
+ SIGURG,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+ SIGSYS,
+};
+
+constexpr int no_change_act_signals[] = {
+ SIGKILL,
+ SIGSTOP,
+};
+
+void signal_handler(int) {}
+void signal_action_handler(int, siginfo_t*, void*) {}
+
+void test_signal_custom() {
+ for (int signum : std_signals) {
+ sighandler_t ret = signal(signum, &signal_handler);
+ assert(ret != SIG_ERR);
+ }
+ for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
+ sighandler_t ret = signal(signum, &signal_handler);
+ assert(ret != SIG_ERR);
+ }
+ for (int signum : no_change_act_signals) {
+ sighandler_t ret = signal(signum, &signal_handler);
+ int err = errno;
+ assert(ret == SIG_ERR);
+ assert(err == EINVAL);
+ }
+ for (int signum : { 0, SIGRTMAX + 1, INT_MAX}) {
+ sighandler_t ret = signal(signum, &signal_handler);
+ int err = errno;
+ assert(ret == SIG_ERR);
+ assert(err == EINVAL);
+ }
+}
+
+void test_signal_ignore() {
+ for (int signum : std_signals) {
+ sighandler_t ret = signal(signum, SIG_IGN);
+ if (signum != SIGCHLD) {
+ // POSIX.1-1990 disallowed setting the action for SIGCHLD to SIG_IGN
+ // though POSIX.1-2001 and later allow this possibility.
+ assert(ret != SIG_ERR);
+ }
+ }
+ for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
+ sighandler_t ret = signal(signum, SIG_IGN);
+ assert(ret != SIG_ERR);
+ }
+ for (int signum : no_change_act_signals) {
+ sighandler_t ret = signal(signum, SIG_IGN);
+ int err = errno;
+ assert(ret == SIG_ERR);
+ assert(err == EINVAL);
+ }
+ for (int signum : { 0, SIGRTMAX + 1, INT_MAX}) {
+ sighandler_t ret = signal(signum, SIG_IGN);
+ int err = errno;
+ assert(ret == SIG_ERR);
+ assert(err == EINVAL);
+ }
+}
+
+void test_signal_default() {
+ for (int signum : std_signals) {
+ sighandler_t ret = signal(signum, SIG_DFL);
+ assert(ret != SIG_ERR);
+ }
+ for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
+ sighandler_t ret = signal(signum, SIG_DFL);
+ assert(ret != SIG_ERR);
+ }
+ for (int signum : { 0, SIGRTMAX + 1, INT_MAX}) {
+ sighandler_t ret = signal(signum, SIG_DFL);
+ int err = errno;
+ assert(ret == SIG_ERR);
+ assert(err == EINVAL);
+ }
+}
+
+void test_sigaction_custom() {
+ struct sigaction act = {}, oldact;
+
+ act.sa_handler = &signal_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ for (int signum : std_signals) {
+ int ret = sigaction(signum, &act, &oldact);
+ assert(ret == 0);
+ }
+ for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
+ int ret = sigaction(signum, &act, &oldact);
+ assert(ret == 0);
+ }
+ for (int signum : no_change_act_signals) {
+ int ret = sigaction(signum, &act, &oldact);
+ int err = errno;
+ assert(ret == -1);
+ assert(err == EINVAL);
+ }
+ for (int signum : { 0, SIGRTMAX + 1, INT_MAX}) {
+ int ret = sigaction(signum, &act, &oldact);
+ int err = errno;
+ assert(ret == -1);
+ assert(err == EINVAL);
+ }
+
+ act.sa_handler = nullptr;
+ act.sa_sigaction = &signal_action_handler;
+ act.sa_flags = SA_SIGINFO;
+
+ for (int signum : std_signals) {
+ int ret = sigaction(signum, &act, &oldact);
+ assert(ret == 0);
+ }
+ for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
+ int ret = sigaction(signum, &act, &oldact);
+ assert(ret == 0);
+ }
+ for (int signum : no_change_act_signals) {
+ int ret = sigaction(signum, &act, &oldact);
+ int err = errno;
+ assert(ret == -1);
+ assert(err == EINVAL);
+ }
+ for (int signum : { 0, SIGRTMAX + 1, INT_MAX}) {
+ int ret = sigaction(signum, &act, &oldact);
+ int err = errno;
+ assert(ret == -1);
+ assert(err == EINVAL);
+ }
+}
+
+void test_sigaction_ignore() {
+ struct sigaction act = {}, oldact;
+
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ for (int signum : std_signals) {
+ int ret = sigaction(signum, &act, &oldact);
+ if (signum != SIGCHLD) {
+ // POSIX.1-1990 disallowed setting the action for SIGCHLD to SIG_IGN
+ // though POSIX.1-2001 and later allow this possibility.
+ assert(ret == 0);
+ }
+ }
+ for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
+ int ret = sigaction(signum, &act, &oldact);
+ assert(ret == 0);
+ }
+ for (int signum : no_change_act_signals) {
+ int ret = sigaction(signum, &act, &oldact);
+ int err = errno;
+ assert(ret == -1);
+ assert(err == EINVAL);
+ }
+ for (int signum : { 0, SIGRTMAX + 1, INT_MAX}) {
+ int ret = sigaction(signum, &act, &oldact);
+ int err = errno;
+ assert(ret == -1);
+ assert(err == EINVAL);
+ }
+}
+
+void test_sigaction_default() {
+ struct sigaction act = {}, oldact;
+
+ act.sa_handler = SIG_DFL;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ for (int signum : std_signals) {
+ int ret = sigaction(signum, &act, &oldact);
+ assert(ret == 0);
+ }
+ for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
+ int ret = sigaction(signum, &act, &oldact);
+ assert(ret == 0);
+ }
+ for (int signum : { 0, SIGRTMAX + 1, INT_MAX}) {
+ int ret = sigaction(signum, &act, &oldact);
+ int err = errno;
+ assert(ret == -1);
+ assert(err == EINVAL);
+ }
+}
+
+int main(void) {
+ printf("sigaction\n");
+
+ test_signal_custom();
+ test_signal_ignore();
+ test_signal_default();
+
+ test_sigaction_custom();
+ test_sigaction_ignore();
+ test_sigaction_default();
+
+ // CHECK: sigaction
+
+ return 0;
+}