[compiler-rt] r276876 - tsan: don't deliver signals when they are blocked

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 27 07:34:21 PDT 2016


Author: dvyukov
Date: Wed Jul 27 09:34:21 2016
New Revision: 276876

URL: http://llvm.org/viewvc/llvm-project?rev=276876&view=rev
Log:
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.


Added:
    compiler-rt/trunk/test/tsan/signal_block.cc
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=276876&r1=276875&r2=276876&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Wed Jul 27 09:34:21 2016
@@ -88,8 +88,6 @@ extern "C" int pthread_attr_setstacksize
 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 e
 #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 *
   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 *
           &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, i
   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);

Added: compiler-rt/trunk/test/tsan/signal_block.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/signal_block.cc?rev=276876&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/signal_block.cc (added)
+++ compiler-rt/trunk/test/tsan/signal_block.cc Wed Jul 27 09:34:21 2016
@@ -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




More information about the llvm-commits mailing list