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,5 @@ "modules.") TSAN_FLAG(bool, shared_ptr_interceptor, true, "Track atomic reference counting in libc++ shared_ptr and weak_ptr.") +TSAN_FLAG(bool, report_full_thread_create_stack, false, + "Report full thread creation stack.") 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,29 @@ rep.AddLocation(addr_min, addr_max - addr_min); + if (flags()->report_full_thread_create_stack) { + const ReportDesc *rep_desc = rep.GetReport(); + Vector worklist; + worklist.Resize(rep_desc->threads.Size()); + for (uptr i = 0; i < worklist.Size(); i++) { + Tid parent_tid = rep_desc->threads[i]->parent_tid; + ThreadContext *tctx = static_cast( + ctx->thread_registry.GetThreadLocked(parent_tid)); + worklist[i] = tctx; + } + + while (worklist.Size() != 0) { + ThreadContext* tctx = worklist[worklist.Size() - 1]; + worklist.PopBack(); + if (tctx->tid == kMainTid || tctx->tid == kInvalidTid) + continue; + rep.AddThread(tctx); + ThreadContext *parent_tctx = static_cast( + ctx->thread_registry.GetThreadLocked(tctx->parent_tid)); + worklist.PushBack(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/report_full_thread_create_stack.cpp =================================================================== --- /dev/null +++ compiler-rt/test/tsan/report_full_thread_create_stack.cpp @@ -0,0 +1,45 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=report_full_thread_create_stack=true %deflake %run %t 2>&1 | FileCheck %s + +#include + +int Global; + +void *ThreadC1(void *x) { + Global++; + return NULL; +} + +void *ThreadC2(void *x) { + Global--; + return NULL; +} + +void *ThreadP1(void *x) { + pthread_t t; + pthread_create(&t, NULL, ThreadC1, NULL); + pthread_join(t, NULL); + return NULL; +} + +void *ThreadP2(void *x) { + pthread_t t; + pthread_create(&t, NULL, ThreadC2, NULL); + pthread_join(t, NULL); + return NULL; +} + +int main() { + pthread_t t[2]; + pthread_create(&t[0], NULL, ThreadP1, NULL); + pthread_create(&t[1], NULL, ThreadP2, NULL); + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); + return 0; +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Thread {{.*}} created by {{.*}} +// CHECK: Thread {{.*}} created by {{.*}} +// CHECK: Thread {{.*}} created by {{.*}} +// CHECK: Thread {{.*}} created by {{.*}} +// CHECK: SUMMARY: ThreadSanitizer: data race{{.*}}