diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp index 0779daa107682..37fb6f2b07f27 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -21,6 +21,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#include "sanitizer_common/sanitizer_thread_history.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" namespace __asan { @@ -555,6 +556,12 @@ void GetRunningThreadsLocked(InternalMmapVector *threads) { threads); } +void PrintThreads() { + InternalScopedString out; + PrintThreadHistory(__asan::asanThreadRegistry(), out); + Report("%s\n", out.data()); +} + } // namespace __lsan // ---------------------- Interface ---------------- {{{1 diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index 3e14a718513d7..8b32e4e760e2f 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -218,6 +218,11 @@ void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { __hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs); } -void GetRunningThreadsLocked(InternalMmapVector *threads) {} +void GetRunningThreadsLocked(InternalMmapVector *threads) { + // TODO: implement. +} +void PrintThreads() { + // TODO: implement. +} } // namespace __lsan diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp index 52d0a8c3c96ae..c05e0dd0a9332 100644 --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -771,11 +771,12 @@ static bool PrintResults(LeakReport &report) { } if (common_flags()->print_suppressions) GetSuppressionContext()->PrintMatchedSuppressions(); - if (unsuppressed_count > 0) { + if (unsuppressed_count) report.PrintSummary(); - return true; - } - return false; + if ((unsuppressed_count && common_flags()->verbosity >= 2) || + flags()->log_threads) + PrintThreads(); + return unsuppressed_count; } static bool CheckForLeaksOnce() { diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h index c598b62105873..f990c7850497a 100644 --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -111,6 +111,7 @@ void GetThreadExtraStackRangesLocked(tid_t os_id, InternalMmapVector *ranges); void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs); void GetRunningThreadsLocked(InternalMmapVector *threads); +void PrintThreads(); //// -------------------------------------------------------------------------- //// Allocator prototypes. diff --git a/compiler-rt/lib/lsan/lsan_thread.cpp b/compiler-rt/lib/lsan/lsan_thread.cpp index 07c7b923623fa..b66ea61a2de4e 100644 --- a/compiler-rt/lib/lsan/lsan_thread.cpp +++ b/compiler-rt/lib/lsan/lsan_thread.cpp @@ -18,6 +18,7 @@ #include "lsan_common.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_thread_history.h" #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" @@ -109,6 +110,12 @@ void GetRunningThreadsLocked(InternalMmapVector *threads) { threads); } +void PrintThreads() { + InternalScopedString out; + PrintThreadHistory(*thread_registry, out); + Report("%s\n", out.data()); +} + void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { GetThreadArgRetval().GetAllPtrsLocked(ptrs); } diff --git a/compiler-rt/test/lsan/TestCases/print_threads.c b/compiler-rt/test/lsan/TestCases/print_threads.c new file mode 100644 index 0000000000000..b3072da93fab6 --- /dev/null +++ b/compiler-rt/test/lsan/TestCases/print_threads.c @@ -0,0 +1,33 @@ +// RUN: %clang_lsan %s -o %t && %env_lsan_opts=log_threads=1 %run %t 2>&1 | FileCheck %s + +// XFAIL: hwasan + +#include +#include +#include +#include +#include +#include + +pthread_barrier_t bar; + +void *threadfn(void *arg) { + pthread_barrier_wait(&bar); + sleep(10000); + return 0; +} + +int main(int argc, char *argv[]) { + pthread_t thread_id; + pthread_barrier_init(&bar, 0, 3); + + pthread_create(&thread_id, 0, threadfn, 0); + pthread_create(&thread_id, 0, threadfn, 0); + + pthread_barrier_wait(&bar); + return 0; +} + +// CHECK: Thread T0/{{[0-9]+}} was created by T-1 +// CHECK: Thread T1/{{[0-9]+}} was created by T0/ +// CHECK: Thread T2/{{[0-9]+}} was created by T0/