[compiler-rt] r200304 - tsan: relax checking of errno spoiling in signal handlers

Dmitry Vyukov dvyukov at google.com
Tue Jan 28 01:49:48 PST 2014


Author: dvyukov
Date: Tue Jan 28 03:49:48 2014
New Revision: 200304

URL: http://llvm.org/viewvc/llvm-project?rev=200304&view=rev
Log:
tsan: relax checking of errno spoiling in signal handlers
allow SIGABRT to spoil errno, because some real programs
reset SIGABRT handler in the handler, re-raise SIGABRT and return from the handler


Modified:
    compiler-rt/trunk/lib/tsan/lit_tests/signal_errno.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface_atomic.cc

Modified: compiler-rt/trunk/lib/tsan/lit_tests/signal_errno.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/signal_errno.cc?rev=200304&r1=200303&r2=200304&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/signal_errno.cc (original)
+++ compiler-rt/trunk/lib/tsan/lit_tests/signal_errno.cc Tue Jan 28 03:49:48 2014
@@ -16,10 +16,20 @@ static void MyHandler(int, siginfo_t *s,
 }
 
 static void* sendsignal(void *p) {
+  sleep(1);
   pthread_kill(mainth, SIGPROF);
   return 0;
 }
 
+static __attribute__((noinline)) void loop() {
+  while (done == 0) {
+    volatile char *p = (char*)malloc(1);
+    p[0] = 0;
+    free((void*)p);
+    pthread_yield();
+  }
+}
+
 int main() {
   mainth = pthread_self();
   struct sigaction act = {};
@@ -27,17 +37,14 @@ int main() {
   sigaction(SIGPROF, &act, 0);
   pthread_t th;
   pthread_create(&th, 0, sendsignal, 0);
-  while (done == 0) {
-    volatile char *p = (char*)malloc(1);
-    p[0] = 0;
-    free((void*)p);
-    pthread_yield();
-  }
+  loop();
   pthread_join(th, 0);
   return 0;
 }
 
 // CHECK: WARNING: ThreadSanitizer: signal handler spoils errno
 // CHECK:     #0 MyHandler(int, siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cc
+// CHECK:     #1 loop
+// CHECK:     #2 main
 // CHECK: SUMMARY: ThreadSanitizer: signal handler spoils errno{{.*}}MyHandler
 

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=200304&r1=200303&r2=200304&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Tue Jan 28 03:49:48 2014
@@ -186,8 +186,8 @@ ScopedInterceptor::~ScopedInterceptor()
     ThreadIgnoreEnd(thr_, pc_);
   }
   if (!thr_->ignore_interceptors) {
-    FuncExit(thr_);
     ProcessPendingSignals(thr_);
+    FuncExit(thr_);
   }
 }
 
@@ -1630,23 +1630,24 @@ TSAN_INTERCEPTOR(int, epoll_wait, int ep
 
 namespace __tsan {
 
-static void CallUserSignalHandler(bool sigact, int sig, my_siginfo_t *info,
-    void *uctx) {
+static void CallUserSignalHandler(ThreadState *thr, bool sync, bool sigact,
+    int sig, my_siginfo_t *info, void *uctx) {
   // Ensure that the handler does not spoil errno.
   const int saved_errno = errno;
-  errno = 0;
+  errno = 99;
+  // Need to remember pc before the call, because the handler can reset it.
+  uptr pc = sigact ?
+     (uptr)sigactions[sig].sa_sigaction :
+     (uptr)sigactions[sig].sa_handler;
+  pc += 1;  // return address is expected, OutputReport() will undo this
   if (sigact)
     sigactions[sig].sa_sigaction(sig, info, uctx);
   else
     sigactions[sig].sa_handler(sig);
-  if (flags()->report_bugs && errno != 0) {
+  if (flags()->report_bugs && !sync && errno != 99) {
     Context *ctx = CTX();
     __tsan::StackTrace stack;
-    uptr pc = sigact ?
-        (uptr)sigactions[sig].sa_sigaction :
-        (uptr)sigactions[sig].sa_handler;
-    pc += 1;  // return address is expected, OutputReport() will undo this
-    stack.Init(&pc, 1);
+    stack.ObtainCurrent(thr, pc);
     ThreadRegistryLock l(ctx->thread_registry);
     ScopedReport rep(ReportTypeErrnoInSignal);
     if (!IsFiredSuppression(ctx, rep, stack)) {
@@ -1673,8 +1674,8 @@ void ProcessPendingSignals(ThreadState *
       signal->armed = false;
       if (sigactions[sig].sa_handler != SIG_DFL
           && sigactions[sig].sa_handler != SIG_IGN) {
-        CallUserSignalHandler(signal->sigaction, sig, &signal->siginfo,
-            &signal->ctx);
+        CallUserSignalHandler(thr, false, signal->sigaction,
+            sig, &signal->siginfo, &signal->ctx);
       }
     }
   }
@@ -1685,15 +1686,20 @@ void ProcessPendingSignals(ThreadState *
 
 }  // namespace __tsan
 
+static bool is_sync_signal(SignalContext *sctx, int sig) {
+  return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
+      sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
+      // If we are sending signal to ourselves, we must process it now.
+      (sctx && sig == sctx->int_signal_send);
+}
+
 void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
     my_siginfo_t *info, void *ctx) {
   ThreadState *thr = cur_thread();
   SignalContext *sctx = SigCtx(thr);
   // Don't mess with synchronous signals.
-  if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
-      sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
-      // If we are sending signal to ourselves, we must process it now.
-      (sctx && sig == sctx->int_signal_send) ||
+  const bool sync = is_sync_signal(sctx, sig);
+  if (sync ||
       // If we are in blocking function, we can safely process it now
       // (but check if we are in a recursive interceptor,
       // i.e. pthread_join()->munmap()).
@@ -1705,10 +1711,10 @@ void ALWAYS_INLINE rtl_generic_sighandle
       // temporary enbled them again while we are calling user function.
       int const i = thr->ignore_interceptors;
       thr->ignore_interceptors = 0;
-      CallUserSignalHandler(sigact, sig, info, ctx);
+      CallUserSignalHandler(thr, sync, sigact, sig, info, ctx);
       thr->ignore_interceptors = i;
     } else {
-      CallUserSignalHandler(sigact, sig, info, ctx);
+      CallUserSignalHandler(thr, sync, sigact, sig, info, ctx);
     }
     CHECK_EQ(thr->in_signal_handler, true);
     thr->in_signal_handler = false;

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface_atomic.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface_atomic.cc?rev=200304&r1=200303&r2=200304&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface_atomic.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface_atomic.cc Tue Jan 28 03:49:48 2014
@@ -71,11 +71,11 @@ class ScopedAtomic {
   ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
                morder mo, const char *func)
       : thr_(thr) {
-    ProcessPendingSignals(thr);
     FuncEntry(thr_, pc);
     DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
   }
   ~ScopedAtomic() {
+    ProcessPendingSignals(thr_);
     FuncExit(thr_);
   }
  private:





More information about the llvm-commits mailing list