tsan: cache pc's that cause suppressions (this way we do not need to symbolize the...
authorDmitry Vyukov <dvyukov@google.com>
Fri, 5 Oct 2012 15:51:32 +0000 (15:51 +0000)
committerDmitry Vyukov <dvyukov@google.com>
Fri, 5 Oct 2012 15:51:32 +0000 (15:51 +0000)
llvm-svn: 165317

compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
compiler-rt/lib/tsan/rtl/tsan_mman.cc
compiler-rt/lib/tsan/rtl/tsan_rtl.cc
compiler-rt/lib/tsan/rtl/tsan_rtl.h
compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
compiler-rt/lib/tsan/rtl/tsan_suppressions.cc
compiler-rt/lib/tsan/rtl/tsan_suppressions.h

index 387cfba..4e09d8e 100644 (file)
@@ -1324,6 +1324,7 @@ static void process_pending_signals(ThreadState *thr) {
   SignalContext *sctx = SigCtx(thr);
   if (sctx == 0 || sctx->pending_signal_count == 0 || thr->in_signal_handler)
     return;
+  Context *ctx = CTX();
   thr->in_signal_handler = true;
   sctx->pending_signal_count = 0;
   // These are too big for stack.
@@ -1351,8 +1352,10 @@ static void process_pending_signals(ThreadState *thr) {
               (uptr)sigactions[sig].sa_handler;
           stack.Init(&pc, 1);
           ScopedReport rep(ReportTypeErrnoInSignal);
-          rep.AddStack(&stack);
-          OutputReport(rep, rep.GetReport()->stacks[0]);
+          if (!IsFiredSuppression(ctx, rep, stack)) {
+            rep.AddStack(&stack);
+            OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
+          }
         }
         errno = saved_errno;
       }
index 6b33480..fcc3000 100644 (file)
@@ -45,11 +45,14 @@ void AlloctorThreadFinish(ThreadState *thr) {
 static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
   if (!thr->in_signal_handler || !flags()->report_signal_unsafe)
     return;
+  Context *ctx = CTX();
   StackTrace stack;
   stack.ObtainCurrent(thr, pc);
   ScopedReport rep(ReportTypeSignalUnsafe);
-  rep.AddStack(&stack);
-  OutputReport(rep, rep.GetReport()->stacks[0]);
+  if (!IsFiredSuppression(ctx, rep, stack)) {
+    rep.AddStack(&stack);
+    OutputReport(ctx, rep, rep.GetReport()->stacks[0]);
+  }
 }
 
 void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
index 1bbb367..c776193 100644 (file)
@@ -49,7 +49,8 @@ Context::Context()
   , nmissed_expected()
   , thread_mtx(MutexTypeThreads, StatMtxThreads)
   , racy_stacks(MBlockRacyStacks)
-  , racy_addresses(MBlockRacyAddresses) {
+  , racy_addresses(MBlockRacyAddresses)
+  , fired_suppressions(MBlockRacyAddresses) {
 }
 
 // The objects are allocated in TLS, so one may rely on zero-initialization.
index d2487ef..c4632c7 100644 (file)
@@ -362,6 +362,11 @@ struct RacyAddress {
   uptr addr_max;
 };
 
+struct FiredSuppression {
+  ReportType type;
+  uptr pc;
+};
+
 struct Context {
   Context();
 
@@ -385,6 +390,7 @@ struct Context {
 
   Vector<RacyStacks> racy_stacks;
   Vector<RacyAddress> racy_addresses;
+  Vector<FiredSuppression> fired_suppressions;
 
   Flags flags;
 
@@ -439,8 +445,12 @@ void InitializeInterceptors();
 void InitializeDynamicAnnotations();
 
 void ReportRace(ThreadState *thr);
-bool OutputReport(const ScopedReport &srep,
+bool OutputReport(Context *ctx,
+                  const ScopedReport &srep,
                   const ReportStack *suppress_stack = 0);
+bool IsFiredSuppression(Context *ctx,
+                        const ScopedReport &srep,
+                        const StackTrace &trace);
 bool IsExpectedReport(uptr addr, uptr size);
 
 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
index 3175f91..73320a0 100644 (file)
@@ -64,7 +64,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
     RestoreStack(last.tid(), last.epoch(), &trace);
     rep.AddStack(&trace);
     rep.AddLocation(s->addr, 1);
-    OutputReport(rep);
+    OutputReport(ctx, rep);
   }
   DestroyAndFree(s);
 }
index d179410..34eb450 100644 (file)
@@ -354,17 +354,36 @@ static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
   }
 }
 
-bool OutputReport(const ScopedReport &srep, const ReportStack *suppress_stack) {
+bool OutputReport(Context *ctx,
+                  const ScopedReport &srep,
+                  const ReportStack *suppress_stack) {
   const ReportDesc *rep = srep.GetReport();
-  bool suppressed = IsSuppressed(rep->typ, suppress_stack);
-  suppressed = OnReport(rep, suppressed);
-  if (suppressed)
+  const uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack);
+  if (suppress_pc != 0) {
+    FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
+    ctx->fired_suppressions.PushBack(supp);
+  }
+  if (OnReport(rep, suppress_pc != 0))
     return false;
   PrintReport(rep);
   CTX()->nreported++;
   return true;
 }
 
+bool IsFiredSuppression(Context *ctx,
+                        const ScopedReport &srep,
+                        const StackTrace &trace) {
+  for (uptr k = 0; k < ctx->fired_suppressions.Size(); k++) {
+    if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
+      continue;
+    for (uptr j = 0; j < trace.Size(); j++) {
+      if (trace.Get(j) == ctx->fired_suppressions[k].pc)
+        return true;
+    }
+  }
+  return false;
+}
+
 void ReportRace(ThreadState *thr) {
   ScopedInRtl in_rtl;
 
@@ -395,15 +414,13 @@ void ReportRace(ThreadState *thr) {
   ScopedReport rep(freed ? ReportTypeUseAfterFree : ReportTypeRace);
   const uptr kMop = 2;
   StackTrace traces[kMop];
-  for (uptr i = 0; i < kMop; i++) {
-    Shadow s(thr->racy_state[i]);
-    RestoreStack(s.tid(), s.epoch(), &traces[i]);
-  }
-  // Failure to restore stack of the current thread
-  // was observed on free() interceptor called from pthread.
-  // Just get the current shadow stack instead.
-  if (traces[0].IsEmpty())
-    traces[0].ObtainCurrent(thr, 0);
+  const uptr toppc = thr->trace.events[thr->fast_state.epoch() % kTraceSize]
+      & ((1ull << 61) - 1);
+  traces[0].ObtainCurrent(thr, toppc);
+  if (IsFiredSuppression(ctx, rep, traces[0]))
+    return;
+  Shadow s2(thr->racy_state[1]);
+  RestoreStack(s2.tid(), s2.epoch(), &traces[1]);
 
   if (HandleRacyStacks(thr, traces, addr_min, addr_max))
     return;
@@ -431,7 +448,7 @@ void ReportRace(ThreadState *thr) {
   }
 #endif
 
-  if (!OutputReport(rep, rep.GetReport()->mops[0]->stack))
+  if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack))
     return;
 
   AddRacyStacks(thr, traces, addr_min, addr_max);
index ee287cb..c52dd82 100644 (file)
@@ -35,7 +35,7 @@ static void MaybeReportThreadLeak(ThreadContext *tctx) {
     return;
   ScopedReport rep(ReportTypeThreadLeak);
   rep.AddThread(tctx);
-  OutputReport(rep);
+  OutputReport(CTX(), rep);
 }
 
 void ThreadFinalize(ThreadState *thr) {
index ef7b691..acb95e5 100644 (file)
@@ -134,9 +134,9 @@ void InitializeSuppressions() {
   g_suppressions = SuppressionParse(supp);
 }
 
-bool IsSuppressed(ReportType typ, const ReportStack *stack) {
+uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
   if (g_suppressions == 0 || stack == 0)
-    return false;
+    return 0;
   SuppressionType stype;
   if (typ == ReportTypeRace)
     stype = SuppressionRace;
@@ -147,17 +147,17 @@ bool IsSuppressed(ReportType typ, const ReportStack *stack) {
   else if (typ == ReportTypeSignalUnsafe)
     stype = SuppressionSignal;
   else
-    return false;
+    return 0;
   for (const ReportStack *frame = stack; frame; frame = frame->next) {
     for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
       if (stype == supp->type &&
           (SuppressionMatch(supp->templ, frame->func) ||
           SuppressionMatch(supp->templ, frame->file))) {
         DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
-        return true;
+        return frame->pc;
       }
     }
   }
-  return false;
+  return 0;
 }
 }  // namespace __tsan
index e576ff4..61a4cca 100644 (file)
@@ -19,7 +19,7 @@ namespace __tsan {
 
 void InitializeSuppressions();
 void FinalizeSuppressions();
-bool IsSuppressed(ReportType typ, const ReportStack *stack);
+uptr IsSuppressed(ReportType typ, const ReportStack *stack);
 
 // Exposed for testing.
 enum SuppressionType {