From 7149ca04ad8cce1171ec99e78db40d4b84d655bd Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 5 Jul 2017 22:17:44 +0000 Subject: [PATCH] [tsan] Use pthread_sigmask instead of sigprocmask to block signals in a thread on Darwin On Darwin, sigprocmask changes the signal mask for the entire process. This has some unwanted consequences, because e.g. internal_start_thread wants to disable signals only in the current thread (to make the new thread inherit the signal mask), which is currently broken on Darwin. This patch switches to pthread_sigmask. Differential Revision: https://reviews.llvm.org/D35016 llvm-svn: 307212 --- .../lib/sanitizer_common/sanitizer_mac.cc | 3 +- .../test/tsan/Darwin/signals-blocked.cc | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 compiler-rt/test/tsan/Darwin/signals-blocked.cc diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc index b48238106dd9..2a13fee0518f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc @@ -191,7 +191,8 @@ void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { - return sigprocmask(how, set, oldset); + // Don't use sigprocmask here, because it affects all threads. + return pthread_sigmask(how, set, oldset); } // Doesn't call pthread_atfork() handlers (but not available on 10.6). diff --git a/compiler-rt/test/tsan/Darwin/signals-blocked.cc b/compiler-rt/test/tsan/Darwin/signals-blocked.cc new file mode 100644 index 000000000000..209dc2229ff6 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/signals-blocked.cc @@ -0,0 +1,75 @@ +// RUN: %clangxx_tsan %s -o %t && %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include +#include +#include + +volatile bool signal_delivered; + +static void handler(int sig) { + if (sig == SIGALRM) + signal_delivered = true; +} + +static void* thr(void *p) { + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGALRM); + int ret = pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); + if (ret) abort(); + + struct sigaction act = {}; + act.sa_handler = &handler; + if (sigaction(SIGALRM, &act, 0)) { + perror("sigaction"); + exit(1); + } + + itimerval t; + t.it_value.tv_sec = 0; + t.it_value.tv_usec = 10000; + t.it_interval = t.it_value; + if (setitimer(ITIMER_REAL, &t, 0)) { + perror("setitimer"); + exit(1); + } + + while (!signal_delivered) { + usleep(1000); + } + + t.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &t, 0)) { + perror("setitimer"); + exit(1); + } + + fprintf(stderr, "SIGNAL DELIVERED\n"); + + return 0; +} + +int main() { + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGALRM); + int ret = pthread_sigmask(SIG_BLOCK, &sigset, NULL); + if (ret) abort(); + + pthread_t th; + pthread_create(&th, 0, thr, 0); + pthread_join(th, 0); + + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer: +// CHECK: SIGNAL DELIVERED +// CHECK: DONE +// CHECK-NOT: WARNING: ThreadSanitizer: