Index: compiler-rt/lib/tsan/rtl/tsan_flags.inc =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_flags.inc +++ compiler-rt/lib/tsan/rtl/tsan_flags.inc @@ -81,3 +81,6 @@ "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: compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp +++ compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp @@ -823,6 +823,18 @@ 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( + 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())) Index: compiler-rt/test/tsan/print_full_thread_history.cpp =================================================================== --- /dev/null +++ compiler-rt/test/tsan/print_full_thread_history.cpp @@ -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{{.*}}