diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -4039,6 +4039,33 @@ #define INIT_SIGSETOPS #endif +#if SANITIZER_INTERCEPT_SIGSET_LOGICOPS +INTERCEPTOR(int, sigandset, __sanitizer_sigset_t *dst, __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigandset, dst, src1, src2); + if (src1) COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigandset)(dst, src1, src2); + if (!res && dst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} + +INTERCEPTOR(int, sigorset, __sanitizer_sigset_t *dst, __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigorset, dst, src1, src2); + if (src1) COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigorset)(dst, src1, src2); + if (!res && dst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} +#define INIT_SIGSET_LOGICOPS \ + COMMON_INTERCEPT_FUNCTION(sigandset); \ + COMMON_INTERCEPT_FUNCTION(sigorset); +#else +#define INIT_SIGSET_LOGICOPS +#endif + #if SANITIZER_INTERCEPT_SIGPENDING INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { void *ctx; @@ -9915,6 +9942,7 @@ INIT_SIGWAITINFO; INIT_SIGTIMEDWAIT; INIT_SIGSETOPS; + INIT_SIGSET_LOGICOPS; INIT_SIGPENDING; INIT_SIGPROCMASK; INIT_PTHREAD_SIGMASK; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -331,6 +331,7 @@ #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_SIGSETOPS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_SIGSET_LOGICOPS SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX diff --git a/compiler-rt/test/msan/Linux/sigandorset.cpp b/compiler-rt/test/msan/Linux/sigandorset.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/msan/Linux/sigandorset.cpp @@ -0,0 +1,27 @@ +// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -DLEFT_OK -std=c++11 -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -DRIGHT_OK -std=c++11 -O0 -g %s -o %t && not %run %t 2<&1 | FileCheck %s +// RUN: %clangxx_msan -DLEFT_OK -DRIGHT_OK -std=c++11 -O0 -g %s -o %t && %run %t + +#include +#include +#include +#include +#include + +int main(void) { + sigset_t s, t, u; +#ifdef LEFT_OK + sigemptyset(&t); +#endif +#ifdef RIGHT_OK + sigemptyset(&u); +#endif + + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK-NEXT: in main {{.*}}sigandorset.cpp:[[@LINE+1]] + sigandset(&s, &t, &u); + sigorset(&s, &t, &u); + __msan_check_mem_is_initialized(&s, sizeof s); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_send.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_send.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_send.cpp @@ -0,0 +1,75 @@ +// RUN: %clangxx -std=c++11 -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include + +sigset_t mkset(int n, ...) { + sigset_t s; + int res = 0; + res |= sigemptyset(&s); + va_list va; + va_start(va, n); + while (n--) { + res |= sigaddset(&s, va_arg(va, int)); + } + va_end(va); + assert(!res); + return s; +} + +sigset_t sigset_or(sigset_t first, sigset_t second) { + sigset_t out; + int res = sigorset(&out, &first, &second); + assert(!res); + return out; +} + +sigset_t sigset_and(sigset_t first, sigset_t second) { + sigset_t out; + int res = sigandset(&out, &first, &second); + assert(!res); + return out; +} + +int fork_and_signal(sigset_t s) { + if (pid_t pid = fork()) { + kill(pid, SIGUSR1); + kill(pid, SIGUSR2); + int child_stat; + wait(&child_stat); + return !WIFEXITED(child_stat); + } else { + int sig; + int res = sigwait(&s, &sig); + assert(!res); + fprintf(stderr, "died with sig %d\n", sig); + _exit(0); + } +} + +void test_sigwait() { + // test sigorset... s should now contain SIGUSR1 | SIGUSR2 + sigset_t s = sigset_or(mkset(1, SIGUSR1), mkset(1, SIGUSR2)); + sigprocmask(SIG_BLOCK, &s, 0); + int res; + res = fork_and_signal(s); + fprintf(stderr, "fork_and_signal with SIGUSR1,2: %d\n", res); + // CHECK: died with sig 10 + // CHECK: fork_and_signal with SIGUSR1,2: 0 + + // test sigandset... s should only have SIGUSR2 now + s = sigset_and(s, mkset(1, SIGUSR2)); + res = fork_and_signal(s); + fprintf(stderr, "fork_and_signal with SIGUSR2: %d\n", res); + // CHECK: died with sig 12 + // CHECK: fork_and_signal with SIGUSR2: 0 +} + +int main(void) { + test_sigwait(); + return 0; +}