diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2016-07-27 14:34:21 +0000 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2016-07-27 14:34:21 +0000 |
| commit | 246e0283d40e4045e3d4adc42e2f0303be19c7f9 (patch) | |
| tree | 30e612d75ac61e44404c6fcd8833845692feb68f | |
| parent | 6756a2c95335fba8bece4402e62f5057a20f3b4c (diff) | |
| download | bcm5719-llvm-246e0283d40e4045e3d4adc42e2f0303be19c7f9.tar.gz bcm5719-llvm-246e0283d40e4045e3d4adc42e2f0303be19c7f9.zip | |
tsan: don't deliver signals when they are blocked
When we delay signals we can deliver them when the signal
is blocked. This can be surprising to the program.
Intercept signal blocking functions merely to process
pending signals. As the result, at worst we will delay
a signal till return from the signal blocking function.
llvm-svn: 276876
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_interceptors.cc | 41 | ||||
| -rw-r--r-- | compiler-rt/test/tsan/signal_block.cc | 60 |
2 files changed, 92 insertions, 9 deletions
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc index fb6227651d2..90b1264bf66 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc @@ -88,8 +88,6 @@ extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize); extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v)); extern "C" int pthread_setspecific(unsigned key, const void *v); DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *) -extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset); DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) @@ -1762,6 +1760,31 @@ TSAN_INTERCEPTOR(int, epoll_pwait, int epfd, void *ev, int cnt, int timeout, #define TSAN_MAYBE_INTERCEPT_EPOLL #endif +// The following functions are intercepted merely to process pending signals. +// If program blocks signal X, we must deliver the signal before the function +// returns. Similarly, if program unblocks a signal (or returns from sigsuspend) +// it's better to deliver the signal straight away. +TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) { + SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask); + return REAL(sigsuspend)(mask); +} + +TSAN_INTERCEPTOR(int, sigblock, int mask) { + SCOPED_TSAN_INTERCEPTOR(sigblock, mask); + return REAL(sigblock)(mask); +} + +TSAN_INTERCEPTOR(int, sigsetmask, int mask) { + SCOPED_TSAN_INTERCEPTOR(sigsetmask, mask); + return REAL(sigsetmask)(mask); +} + +TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + SCOPED_TSAN_INTERCEPTOR(pthread_sigmask, how, set, oldset); + return REAL(pthread_sigmask)(how, set, oldset); +} + namespace __tsan { static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, @@ -1833,7 +1856,8 @@ void ProcessPendingSignals(ThreadState *thr) { atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed); atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); internal_sigfillset(&sctx->emptyset); - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sctx->emptyset, &sctx->oldset)); + int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, &sctx->oldset); + CHECK_EQ(res, 0); for (int sig = 0; sig < kSigCount; sig++) { SignalDesc *signal = &sctx->pending_signals[sig]; if (signal->armed) { @@ -1842,7 +1866,8 @@ void ProcessPendingSignals(ThreadState *thr) { &signal->siginfo, &signal->ctx); } } - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sctx->oldset, 0)); + res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0); + CHECK_EQ(res, 0); atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); } @@ -1958,11 +1983,6 @@ TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) { return old.sa_handler; } -TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) { - SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask); - return REAL(sigsuspend)(mask); -} - TSAN_INTERCEPTOR(int, raise, int sig) { SCOPED_TSAN_INTERCEPTOR(raise, sig); ThreadSignalContext *sctx = SigCtx(thr); @@ -2553,6 +2573,9 @@ void InitializeInterceptors() { TSAN_INTERCEPT(sigaction); TSAN_INTERCEPT(signal); TSAN_INTERCEPT(sigsuspend); + TSAN_INTERCEPT(sigblock); + TSAN_INTERCEPT(sigsetmask); + TSAN_INTERCEPT(pthread_sigmask); TSAN_INTERCEPT(raise); TSAN_INTERCEPT(kill); TSAN_INTERCEPT(pthread_kill); diff --git a/compiler-rt/test/tsan/signal_block.cc b/compiler-rt/test/tsan/signal_block.cc new file mode 100644 index 00000000000..dfd4259c43c --- /dev/null +++ b/compiler-rt/test/tsan/signal_block.cc @@ -0,0 +1,60 @@ +// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s + +// Test that a signal is not delivered when it is blocked. + +#include "test.h" +#include <semaphore.h> +#include <signal.h> +#include <errno.h> + +int stop; +sig_atomic_t signal_blocked; + +void handler(int signum) { + if (signal_blocked) { + fprintf(stderr, "signal arrived when blocked\n"); + exit(1); + } +} + +void *thread(void *arg) { + sigset_t myset; + sigemptyset(&myset); + sigaddset(&myset, SIGUSR1); + while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) { + usleep(1); + if (pthread_sigmask(SIG_BLOCK, &myset, 0)) { + fprintf(stderr, "pthread_sigmask failed %d\n", errno); + exit(1); + } + signal_blocked = 1; + usleep(1); + signal_blocked = 0; + if (pthread_sigmask(SIG_UNBLOCK, &myset, 0)) { + fprintf(stderr, "pthread_sigmask failed %d\n", errno); + exit(1); + } + } + return 0; +} + +int main(int argc, char** argv) { + struct sigaction act = {}; + act.sa_handler = &handler; + if (sigaction(SIGUSR1, &act, 0)) { + fprintf(stderr, "sigaction failed %d\n", errno); + return 1; + } + pthread_t th; + pthread_create(&th, 0, thread, 0); + for (int i = 0; i < 100000; i++) + pthread_kill(th, SIGUSR1); + __atomic_store_n(&stop, 1, __ATOMIC_RELAXED); + pthread_join(th, 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: ThreadSanitizer CHECK +// CHECK-NOT: WARNING: ThreadSanitizer: +// CHECK: DONE |

