[TSan] Add a runtime flag to print full thread creation stacks up to the main thread
authorDmitry Vyukov <dvyukov@google.com>
Thu, 24 Mar 2022 16:07:32 +0000 (17:07 +0100)
committerDmitry Vyukov <dvyukov@google.com>
Thu, 24 Mar 2022 16:30:27 +0000 (17:30 +0100)
Currently, we only print how threads involved in data race are created from their parent threads.
Add a runtime flag 'print_full_thread_history' to print thread creation stacks for the threads involved in the data race and their ancestors up to the main thread.

Reviewed By: dvyukov

Differential Revision: https://reviews.llvm.org/D122131

compiler-rt/lib/tsan/rtl/tsan_flags.inc
compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
compiler-rt/test/tsan/print_full_thread_history.cpp [new file with mode: 0644]

index b169145..32cf3bb 100644 (file)
@@ -81,3 +81,6 @@ TSAN_FLAG(bool, ignore_noninstrumented_modules, SANITIZER_MAC ? true : false,
           "modules.")
 TSAN_FLAG(bool, shared_ptr_interceptor, true,
           "Track atomic reference counting in libc++ shared_ptr and weak_ptr.")
+TSAN_FLAG(bool, print_full_thread_history, false,
+          "If set, prints thread creation stacks for the threads involved in "
+          "the report and their ancestors up to the main thread.")
index 8f28b75..4cf8816 100644 (file)
@@ -823,6 +823,18 @@ void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
 
   rep.AddLocation(addr_min, addr_max - addr_min);
 
+  if (flags()->print_full_thread_history) {
+    const ReportDesc *rep_desc = rep.GetReport();
+    for (uptr i = 0; i < rep_desc->threads.Size(); i++) {
+      Tid parent_tid = rep_desc->threads[i]->parent_tid;
+      if (parent_tid == kMainTid || parent_tid == kInvalidTid)
+        continue;
+      ThreadContext *parent_tctx = static_cast<ThreadContext *>(
+          ctx->thread_registry.GetThreadLocked(parent_tid));
+      rep.AddThread(parent_tctx);
+    }
+  }
+
 #if !SANITIZER_GO
   if (!((typ0 | typ1) & kAccessFree) &&
       s[1].epoch() <= thr->last_sleep_clock.Get(s[1].sid()))
diff --git a/compiler-rt/test/tsan/print_full_thread_history.cpp b/compiler-rt/test/tsan/print_full_thread_history.cpp
new file mode 100644 (file)
index 0000000..ff341f6
--- /dev/null
@@ -0,0 +1,40 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=print_full_thread_history=true %deflake %run %t 2>&1 | FileCheck %s
+
+#include "test.h"
+
+int Global;
+
+void *Thread2(void *x) {
+  barrier_wait(&barrier);
+  Global++;
+  return NULL;
+}
+
+void *Thread3(void *x) {
+  Global--;
+  barrier_wait(&barrier);
+  return NULL;
+}
+
+void *Thread1(void *x) {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread2, NULL);
+  pthread_create(&t[1], NULL, Thread3, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return NULL;
+}
+
+int main() {
+  barrier_init(&barrier, 2);
+  pthread_t t;
+  pthread_create(&t, NULL, Thread1, NULL);
+  pthread_join(t, NULL);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:        Thread T2 {{.*}} created by thread T1 at
+// CHECK:        Thread T3 {{.*}} created by thread T1 at:
+// CHECK:        Thread T1 {{.*}} created by main thread at:
+// CHECK: SUMMARY: ThreadSanitizer: data race{{.*}}