[compiler-rt] [lsan] Add debug option to "deflake" leaks (PR #112037)

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 11 16:30:05 PDT 2024


https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/112037

>From 5c25ba3380966ccac5bd0caf2c39bc10c1571e42 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Fri, 11 Oct 2024 12:21:18 -0700
Subject: [PATCH 1/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
 =?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4

[skip ci]
---
 compiler-rt/lib/asan/asan_fuchsia.cpp         |  3 +-
 compiler-rt/lib/asan/asan_thread.cpp          | 16 ++--
 compiler-rt/lib/asan/asan_thread.h            | 11 +--
 compiler-rt/lib/hwasan/hwasan_thread.cpp      |  7 +-
 compiler-rt/lib/lsan/lsan_common.cpp          |  9 ++-
 compiler-rt/lib/lsan/lsan_common.h            |  1 +
 compiler-rt/lib/lsan/lsan_thread.cpp          |  4 +
 compiler-rt/lib/memprof/memprof_thread.cpp    |  9 +--
 compiler-rt/lib/memprof/memprof_thread.h      |  8 +-
 .../lib/sanitizer_common/CMakeLists.txt       |  1 +
 .../sanitizer_thread_history.cpp              | 73 +++++++++++++++++++
 .../sanitizer_thread_history.h                | 24 ++++++
 .../sanitizer_thread_registry.cpp             | 13 +++-
 .../sanitizer_thread_registry.h               |  9 ++-
 .../tests/sanitizer_thread_registry_test.cpp  | 23 ++++--
 15 files changed, 164 insertions(+), 47 deletions(-)
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h

diff --git a/compiler-rt/lib/asan/asan_fuchsia.cpp b/compiler-rt/lib/asan/asan_fuchsia.cpp
index dbc4342e83388c..96c41e9d42ba6a 100644
--- a/compiler-rt/lib/asan/asan_fuchsia.cpp
+++ b/compiler-rt/lib/asan/asan_fuchsia.cpp
@@ -121,8 +121,7 @@ static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
   // In lieu of AsanThread::Create.
   AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
 
-  AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
-  u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
+  u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, thread);
   asanThreadRegistry().SetThreadName(tid, name);
 
   return thread;
diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index c1a804b9fcccd3..37fb6f2b07f276 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 {
@@ -28,10 +29,7 @@ namespace __asan {
 // AsanThreadContext implementation.
 
 void AsanThreadContext::OnCreated(void *arg) {
-  CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs *>(arg);
-  if (args->stack)
-    stack_id = StackDepotPut(*args->stack);
-  thread = args->thread;
+  thread = static_cast<AsanThread *>(arg);
   thread->set_context(this);
 }
 
@@ -106,8 +104,8 @@ AsanThread *AsanThread::Create(const void *start_data, uptr data_size,
     CHECK_LE(data_size, availible_size);
     internal_memcpy(thread->start_data_, start_data, data_size);
   }
-  AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
-  asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
+  asanThreadRegistry().CreateThread(0, detached, parent_tid,
+                                    stack ? StackDepotPut(*stack) : 0, thread);
 
   return thread;
 }
@@ -558,6 +556,12 @@ void GetRunningThreadsLocked(InternalMmapVector<tid_t> *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/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h
index 62f1b5337fe4bf..ad9e03d68fe96a 100644
--- a/compiler-rt/lib/asan/asan_thread.h
+++ b/compiler-rt/lib/asan/asan_thread.h
@@ -36,21 +36,16 @@ class AsanThread;
 class AsanThreadContext final : public ThreadContextBase {
  public:
   explicit AsanThreadContext(int tid)
-      : ThreadContextBase(tid), announced(false),
-        destructor_iterations(GetPthreadDestructorIterations()), stack_id(0),
+      : ThreadContextBase(tid),
+        announced(false),
+        destructor_iterations(GetPthreadDestructorIterations()),
         thread(nullptr) {}
   bool announced;
   u8 destructor_iterations;
-  u32 stack_id;
   AsanThread *thread;
 
   void OnCreated(void *arg) override;
   void OnFinished() override;
-
-  struct CreateThreadContextArgs {
-    AsanThread *thread;
-    StackTrace *stack;
-  };
 };
 
 // AsanThreadContext objects are never freed, so we need many of them.
diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp
index 3e14a718513d7f..8b32e4e760e2fa 100644
--- a/compiler-rt/lib/hwasan/hwasan_thread.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp
@@ -218,6 +218,11 @@ void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
   __hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs);
 }
 
-void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {}
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *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 6776598651ae9b..b584d1e9723fc8 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 CheckForLeaks() {
diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
index c598b62105873e..f990c7850497a5 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<Range> *ranges);
 void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs);
 void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads);
+void PrintThreads();
 
 //// --------------------------------------------------------------------------
 //// Allocator prototypes.
diff --git a/compiler-rt/lib/lsan/lsan_thread.cpp b/compiler-rt/lib/lsan/lsan_thread.cpp
index 07c7b923623fa9..9e481e97ac4731 100644
--- a/compiler-rt/lib/lsan/lsan_thread.cpp
+++ b/compiler-rt/lib/lsan/lsan_thread.cpp
@@ -109,6 +109,10 @@ void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
       threads);
 }
 
+void PrintThreads() {
+  // TODO: implement.
+}
+
 void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
   GetThreadArgRetval().GetAllPtrsLocked(ptrs);
 }
diff --git a/compiler-rt/lib/memprof/memprof_thread.cpp b/compiler-rt/lib/memprof/memprof_thread.cpp
index 50072bb91ee74c..4b9665ffc3fcea 100644
--- a/compiler-rt/lib/memprof/memprof_thread.cpp
+++ b/compiler-rt/lib/memprof/memprof_thread.cpp
@@ -25,10 +25,7 @@ namespace __memprof {
 // MemprofThreadContext implementation.
 
 void MemprofThreadContext::OnCreated(void *arg) {
-  CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs *>(arg);
-  if (args->stack)
-    stack_id = StackDepotPut(*args->stack);
-  thread = args->thread;
+  thread = static_cast<MemprofThread *>(arg);
   thread->set_context(this);
 }
 
@@ -79,8 +76,8 @@ MemprofThread *MemprofThread::Create(thread_callback_t start_routine, void *arg,
   MemprofThread *thread = (MemprofThread *)MmapOrDie(size, __func__);
   thread->start_routine_ = start_routine;
   thread->arg_ = arg;
-  MemprofThreadContext::CreateThreadContextArgs args = {thread, stack};
-  memprofThreadRegistry().CreateThread(0, detached, parent_tid, &args);
+  memprofThreadRegistry().CreateThread(
+      0, detached, parent_tid, stack ? StackDepotPut(*stack) : 0, thread);
 
   return thread;
 }
diff --git a/compiler-rt/lib/memprof/memprof_thread.h b/compiler-rt/lib/memprof/memprof_thread.h
index 4c9313fcb369eb..fb90dbf328a430 100644
--- a/compiler-rt/lib/memprof/memprof_thread.h
+++ b/compiler-rt/lib/memprof/memprof_thread.h
@@ -34,20 +34,14 @@ class MemprofThread;
 struct MemprofThreadContext final : public ThreadContextBase {
   explicit MemprofThreadContext(int tid)
       : ThreadContextBase(tid), announced(false),
-        destructor_iterations(GetPthreadDestructorIterations()), stack_id(0),
+        destructor_iterations(GetPthreadDestructorIterations()),
         thread(nullptr) {}
   bool announced;
   u8 destructor_iterations;
-  u32 stack_id;
   MemprofThread *thread;
 
   void OnCreated(void *arg) override;
   void OnFinished() override;
-
-  struct CreateThreadContextArgs {
-    MemprofThread *thread;
-    StackTrace *stack;
-  };
 };
 
 // MemprofThreadContext objects are never freed, so we need many of them.
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 556a64f3017488..09391e4f5f3704 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -94,6 +94,7 @@ set(SANITIZER_SYMBOLIZER_SOURCES
   sanitizer_symbolizer_report.cpp
   sanitizer_symbolizer_report_fuchsia.cpp
   sanitizer_symbolizer_win.cpp
+  sanitizer_thread_history.cpp
   sanitizer_unwind_linux_libcdep.cpp
   sanitizer_unwind_fuchsia.cpp
   sanitizer_unwind_win.cpp
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp
new file mode 100644
index 00000000000000..6a4d9bf231811f
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp
@@ -0,0 +1,73 @@
+//===-- sanitizer_thread_history.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_thread_history.h"
+
+#include "sanitizer_stackdepot.h"
+namespace __sanitizer {
+
+void PrintThreadHistory(ThreadRegistry &registry, InternalScopedString &out) {
+  ThreadRegistryLock l(&registry);
+  // Stack traces are largest part of printout and they often the same for
+  // multiple threads, so we will deduplicate them.
+  InternalMmapVector<const ThreadContextBase *> stacks;
+
+  registry.RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *context, void *arg) {
+        static_cast<decltype(&stacks)>(arg)->push_back(context);
+      },
+      &stacks);
+
+  Sort(stacks.data(), stacks.size(),
+       [](const ThreadContextBase *a, const ThreadContextBase *b) {
+         if (a->stack_id < b->stack_id)
+           return true;
+         if (a->stack_id > b->stack_id)
+           return false;
+         return a->tid < b->tid;
+       });
+
+  auto describe_thread = [&](const ThreadContextBase *context) {
+    if (!context) {
+      out.Append("T-1");
+      return;
+    }
+    out.AppendF("T%llu/%llu", context->unique_id, context->os_id);
+    if (internal_strlen(context->name))
+      out.AppendF(" (%s)", context->name);
+  };
+
+  auto get_parent =
+      [&](const ThreadContextBase *context) -> const ThreadContextBase * {
+    if (!context)
+      return nullptr;
+    ThreadContextBase *parent = registry.GetThreadLocked(context->parent_tid);
+    if (!parent)
+      return nullptr;
+    if (parent->unique_id >= context->unique_id)
+      return nullptr;
+    return parent;
+  };
+
+  const ThreadContextBase *prev = nullptr;
+  for (const ThreadContextBase *context : stacks) {
+    if (prev->stack_id != context->stack_id) {
+      StackDepotGet(prev->stack_id).PrintTo(&out);
+      prev = context;
+    }
+    out.Append("Thread ");
+    describe_thread(context);
+    out.Append(" was created by ");
+    describe_thread(get_parent(context));
+    out.Append("\n");
+  }
+  if (prev)
+    StackDepotGet(prev->stack_id).PrintTo(&out);
+}
+
+}  // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h b/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h
new file mode 100644
index 00000000000000..2995f6015fe50e
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h
@@ -0,0 +1,24 @@
+//===-- sanitizer_thread_history.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility to print thread histroy from ThreadRegistry.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_THREAD_HISTORY_H
+#define SANITIZER_THREAD_HISTORY_H
+
+#include "sanitizer_thread_registry.h"
+
+namespace __sanitizer {
+
+void PrintThreadHistory(ThreadRegistry& registry, InternalScopedString& out);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_THREAD_HISTORY_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp
index df04822b28851c..cdc24f4a8869c7 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp
@@ -27,6 +27,7 @@ ThreadContextBase::ThreadContextBase(u32 tid)
       detached(false),
       thread_type(ThreadType::Regular),
       parent_tid(0),
+      stack_id(0),
       next(0) {
   name[0] = '\0';
   atomic_store(&thread_destroyed, 0, memory_order_release);
@@ -88,14 +89,17 @@ void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
 }
 
 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
-                                   bool _detached, u32 _parent_tid, void *arg) {
+                                   bool _detached, u32 _parent_tid,
+                                   u32 _stack_tid, void *arg) {
   status = ThreadStatusCreated;
   user_id = _user_id;
   unique_id = _unique_id;
   detached = _detached;
   // Parent tid makes no sense for the main thread.
-  if (tid != kMainTid)
+  if (tid != kMainTid) {
     parent_tid = _parent_tid;
+    stack_id = _stack_tid;
+  }
   OnCreated(arg);
 }
 
@@ -143,7 +147,7 @@ uptr ThreadRegistry::GetMaxAliveThreads() {
 }
 
 u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
-                                 void *arg) {
+                                 u32 stack_tid, void *arg) {
   ThreadRegistryLock l(this);
   u32 tid = kInvalidTid;
   ThreadContextBase *tctx = QuarantinePop();
@@ -181,7 +185,8 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
     // positives later (e.g. if we join a wrong thread).
     CHECK(live_.try_emplace(user_id, tid).second);
   }
-  tctx->SetCreated(user_id, total_threads_++, detached, parent_tid, arg);
+  tctx->SetCreated(user_id, total_threads_++, detached, parent_tid, stack_tid,
+                   arg);
   return tid;
 }
 
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
index bf492c17f7e107..e06abb3932da5c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -52,6 +52,7 @@ class ThreadContextBase {
   ThreadType thread_type;
 
   u32 parent_tid;
+  u32 stack_id;
   ThreadContextBase *next;  // For storing thread contexts in a list.
 
   atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished
@@ -63,7 +64,7 @@ class ThreadContextBase {
   void SetFinished();
   void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg);
   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
-                  u32 _parent_tid, void *arg);
+                  u32 _parent_tid, u32 _stack_tid, void *arg);
   void Reset();
 
   void SetDestroyed();
@@ -106,7 +107,11 @@ class SANITIZER_MUTEX ThreadRegistry {
 
   u32 NumThreadsLocked() const { return threads_.size(); }
 
-  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg);
+  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, u32 stack_tid,
+                   void *arg);
+  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg) {
+    return CreateThread(user_id, detached, parent_tid, 0, arg);
+  }
 
   typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
   // Invokes callback with a specified arg for each thread context.
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp
index 8c4b4ba5c58f7d..c3cac707f0a0b3 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp
@@ -64,11 +64,12 @@ static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
 
 static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
   // Create and start a main thread.
-  EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0));
+  EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0, nullptr));
   registry->StartThread(0, 0, ThreadType::Regular, 0);
   // Create a bunch of threads.
   for (u32 i = 1; i <= 10; i++) {
-    EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
+    EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 100 + i,
+                                        200 + i, nullptr));
   }
   CheckThreadQuantity(registry, 11, 1, 11);
   // Start some of them.
@@ -88,19 +89,27 @@ static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
   std::vector<u32> new_tids;
   for (u32 i = 11; i <= 15; i++) {
     new_tids.push_back(
-        registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
+        registry->CreateThread(get_uid(i), is_detached(i), 0, 0, nullptr));
   }
   ASSERT_LE(kRegistryQuarantine, 5U);
-  u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine  : 0);
+  u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine : 0);
   CheckThreadQuantity(registry, exp_total, 6, 11);
   // Test SetThreadName and FindThread.
   registry->SetThreadName(6, "six");
   registry->SetThreadName(7, "seven");
-  EXPECT_EQ(7U, registry->FindThread(HasName, (void*)"seven"));
+  EXPECT_EQ(7U, registry->FindThread(HasName, (void *)"seven"));
   EXPECT_EQ(kInvalidTid, registry->FindThread(HasName, (void *)"none"));
-  EXPECT_EQ(0U, registry->FindThread(HasUid, (void*)get_uid(0)));
-  EXPECT_EQ(10U, registry->FindThread(HasUid, (void*)get_uid(10)));
+  EXPECT_EQ(0U, registry->FindThread(HasUid, (void *)get_uid(0)));
+  EXPECT_EQ(10U, registry->FindThread(HasUid, (void *)get_uid(10)));
   EXPECT_EQ(kInvalidTid, registry->FindThread(HasUid, (void *)0x1234));
+  EXPECT_EQ(7U,
+            registry->FindThread([](ThreadContextBase *tctx,
+                                    void *) { return tctx->parent_tid == 107; },
+                                 nullptr));
+  EXPECT_EQ(8U,
+            registry->FindThread([](ThreadContextBase *tctx,
+                                    void *) { return tctx->stack_id == 208; },
+                                 nullptr));
   // Detach and finish and join remaining threads.
   for (u32 i = 6; i <= 10; i++) {
     registry->DetachThread(i, 0);

>From abee2b641366897f8905ac61c49ac70d2a4d2a99 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Fri, 11 Oct 2024 12:43:17 -0700
Subject: [PATCH 2/4] format

Created using spr 1.3.4
---
 compiler-rt/lib/lsan/lsan_common.cpp           | 3 +--
 compiler-rt/lib/lsan/lsan_flags.inc            | 3 ++-
 compiler-rt/test/lsan/TestCases/flag_retries.c | 8 ++++----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index 8ed2cfc63cbae9..c53e1e610054bf 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -833,8 +833,7 @@ static bool CheckForLeaksOnce() {
 
 static bool CheckForLeaks() {
   int with_leaks = 0;
-  for (int i = 0; i < flags()->retries; ++i)
-    with_leaks += CheckForLeaksOnce();
+  for (int i = 0; i < flags()->retries; ++i) with_leaks += CheckForLeaksOnce();
   return with_leaks == flags()->retries;
 }
 
diff --git a/compiler-rt/lib/lsan/lsan_flags.inc b/compiler-rt/lib/lsan/lsan_flags.inc
index 59edc0baa77d85..ae6057f171b825 100644
--- a/compiler-rt/lib/lsan/lsan_flags.inc
+++ b/compiler-rt/lib/lsan/lsan_flags.inc
@@ -43,7 +43,8 @@ LSAN_FLAG(bool, use_poisoned, false,
           "Consider pointers found in poisoned memory to be valid.")
 LSAN_FLAG(bool, log_pointers, false, "Debug logging")
 LSAN_FLAG(bool, log_threads, false, "Debug logging")
-LSAN_FLAG(int, retries, 1, "Debug option to repeat leak checking multiple times")
+LSAN_FLAG(int, retries, 1,
+          "Debug option to repeat leak checking multiple times")
 LSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
 LSAN_FLAG(int, thread_suspend_fail, 1,
           "Behaviour if thread suspendion all thread (0 - "
diff --git a/compiler-rt/test/lsan/TestCases/flag_retries.c b/compiler-rt/test/lsan/TestCases/flag_retries.c
index 3891a47bb0a566..de814bcab446c5 100644
--- a/compiler-rt/test/lsan/TestCases/flag_retries.c
+++ b/compiler-rt/test/lsan/TestCases/flag_retries.c
@@ -4,20 +4,20 @@
 // RUN: %env_lsan_opts=use_stacks=0:use_registers=0:symbolize=0:retries=12 %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK12
 
 #include <assert.h>
+#include <sanitizer/lsan_interface.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <sanitizer/lsan_interface.h>
 
 void *p;
 
 int main(int argc, char *argv[]) {
   fprintf(stderr, "Test alloc: %p.\n", malloc(1337));
-// CHECK: Test alloc:
+  // CHECK: Test alloc:
 
   assert(__lsan_do_recoverable_leak_check() == 1);
-// CHECK1-COUNT-1: SUMMARY: {{.*}}Sanitizer: 1337 byte
-// CHECK12-COUNT-12: SUMMARY: {{.*}}Sanitizer: 1337 byte
+  // CHECK1-COUNT-1: SUMMARY: {{.*}}Sanitizer: 1337 byte
+  // CHECK12-COUNT-12: SUMMARY: {{.*}}Sanitizer: 1337 byte
 
   _exit(0);
 }

>From 7a0b416c87601910e51525d5481f8921fd5eb31a Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Fri, 11 Oct 2024 14:39:29 -0700
Subject: [PATCH 3/4] tries

Created using spr 1.3.4
---
 compiler-rt/lib/lsan/lsan_common.cpp                        | 6 +++---
 compiler-rt/lib/lsan/lsan_flags.inc                         | 3 +--
 .../test/lsan/TestCases/{flag_retries.c => flag_tries.c}    | 2 +-
 3 files changed, 5 insertions(+), 6 deletions(-)
 rename compiler-rt/test/lsan/TestCases/{flag_retries.c => flag_tries.c} (90%)

diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index c53e1e610054bf..c05e0dd0a9332d 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -832,9 +832,9 @@ static bool CheckForLeaksOnce() {
 }
 
 static bool CheckForLeaks() {
-  int with_leaks = 0;
-  for (int i = 0; i < flags()->retries; ++i) with_leaks += CheckForLeaksOnce();
-  return with_leaks == flags()->retries;
+  int leaking_tries = 0;
+  for (int i = 0; i < flags()->tries; ++i) leaking_tries += CheckForLeaksOnce();
+  return leaking_tries == flags()->tries;
 }
 
 static bool has_reported_leaks = false;
diff --git a/compiler-rt/lib/lsan/lsan_flags.inc b/compiler-rt/lib/lsan/lsan_flags.inc
index ae6057f171b825..c97b021ba5c02f 100644
--- a/compiler-rt/lib/lsan/lsan_flags.inc
+++ b/compiler-rt/lib/lsan/lsan_flags.inc
@@ -43,8 +43,7 @@ LSAN_FLAG(bool, use_poisoned, false,
           "Consider pointers found in poisoned memory to be valid.")
 LSAN_FLAG(bool, log_pointers, false, "Debug logging")
 LSAN_FLAG(bool, log_threads, false, "Debug logging")
-LSAN_FLAG(int, retries, 1,
-          "Debug option to repeat leak checking multiple times")
+LSAN_FLAG(int, tries, 1, "Debug option to repeat leak checking multiple times")
 LSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
 LSAN_FLAG(int, thread_suspend_fail, 1,
           "Behaviour if thread suspendion all thread (0 - "
diff --git a/compiler-rt/test/lsan/TestCases/flag_retries.c b/compiler-rt/test/lsan/TestCases/flag_tries.c
similarity index 90%
rename from compiler-rt/test/lsan/TestCases/flag_retries.c
rename to compiler-rt/test/lsan/TestCases/flag_tries.c
index de814bcab446c5..d6af766d5ef282 100644
--- a/compiler-rt/test/lsan/TestCases/flag_retries.c
+++ b/compiler-rt/test/lsan/TestCases/flag_tries.c
@@ -1,7 +1,7 @@
 // Test retries option of lsan.
 // RUN: %clang_lsan %s -o %t
 // RUN: %env_lsan_opts=use_stacks=0:use_registers=0:symbolize=0 %run %t foo 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK1
-// RUN: %env_lsan_opts=use_stacks=0:use_registers=0:symbolize=0:retries=12 %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK12
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0:symbolize=0:tries=12 %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK12
 
 #include <assert.h>
 #include <sanitizer/lsan_interface.h>

>From e4752d63c55af5947e0669961f34cc6da6ffa8e7 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Fri, 11 Oct 2024 16:29:30 -0700
Subject: [PATCH 4/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
 =?UTF-8?q?anges=20introduced=20through=20rebase?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4

[skip ci]
---
 compiler-rt/lib/asan/asan_thread.cpp          |  7 --
 compiler-rt/lib/hwasan/hwasan_thread.cpp      |  7 +-
 compiler-rt/lib/lsan/lsan_common.cpp          |  9 ++-
 compiler-rt/lib/lsan/lsan_common.h            |  1 -
 compiler-rt/lib/lsan/lsan_thread.cpp          |  4 --
 .../lib/sanitizer_common/CMakeLists.txt       |  1 -
 .../sanitizer_thread_history.cpp              | 72 -------------------
 .../sanitizer_thread_history.h                | 24 -------
 .../tests/sanitizer_thread_registry_test.cpp  | 60 ----------------
 9 files changed, 5 insertions(+), 180 deletions(-)
 delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp
 delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h

diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 37fb6f2b07f276..0779daa107682b 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -21,7 +21,6 @@
 #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 {
@@ -556,12 +555,6 @@ void GetRunningThreadsLocked(InternalMmapVector<tid_t> *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 8b32e4e760e2fa..3e14a718513d7f 100644
--- a/compiler-rt/lib/hwasan/hwasan_thread.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp
@@ -218,11 +218,6 @@ void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
   __hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs);
 }
 
-void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
-  // TODO: implement.
-}
-void PrintThreads() {
-  // TODO: implement.
-}
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {}
 
 }  // namespace __lsan
diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index b584d1e9723fc8..6776598651ae9b 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -771,12 +771,11 @@ static bool PrintResults(LeakReport &report) {
   }
   if (common_flags()->print_suppressions)
     GetSuppressionContext()->PrintMatchedSuppressions();
-  if (unsuppressed_count)
+  if (unsuppressed_count > 0) {
     report.PrintSummary();
-  if ((unsuppressed_count && common_flags()->verbosity >= 2) ||
-      flags()->log_threads)
-    PrintThreads();
-  return unsuppressed_count;
+    return true;
+  }
+  return false;
 }
 
 static bool CheckForLeaks() {
diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h
index f990c7850497a5..c598b62105873e 100644
--- a/compiler-rt/lib/lsan/lsan_common.h
+++ b/compiler-rt/lib/lsan/lsan_common.h
@@ -111,7 +111,6 @@ void GetThreadExtraStackRangesLocked(tid_t os_id,
                                      InternalMmapVector<Range> *ranges);
 void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs);
 void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads);
-void PrintThreads();
 
 //// --------------------------------------------------------------------------
 //// Allocator prototypes.
diff --git a/compiler-rt/lib/lsan/lsan_thread.cpp b/compiler-rt/lib/lsan/lsan_thread.cpp
index 9e481e97ac4731..07c7b923623fa9 100644
--- a/compiler-rt/lib/lsan/lsan_thread.cpp
+++ b/compiler-rt/lib/lsan/lsan_thread.cpp
@@ -109,10 +109,6 @@ void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
       threads);
 }
 
-void PrintThreads() {
-  // TODO: implement.
-}
-
 void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
   GetThreadArgRetval().GetAllPtrsLocked(ptrs);
 }
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 09391e4f5f3704..556a64f3017488 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -94,7 +94,6 @@ set(SANITIZER_SYMBOLIZER_SOURCES
   sanitizer_symbolizer_report.cpp
   sanitizer_symbolizer_report_fuchsia.cpp
   sanitizer_symbolizer_win.cpp
-  sanitizer_thread_history.cpp
   sanitizer_unwind_linux_libcdep.cpp
   sanitizer_unwind_fuchsia.cpp
   sanitizer_unwind_win.cpp
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp
deleted file mode 100644
index 0f5bec3ca083e3..00000000000000
--- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//===-- sanitizer_thread_history.cpp --------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_thread_history.h"
-
-#include "sanitizer_stackdepot.h"
-namespace __sanitizer {
-
-void PrintThreadHistory(ThreadRegistry &registry, InternalScopedString &out) {
-  ThreadRegistryLock l(&registry);
-  // Stack traces are largest part of printout and they often the same for
-  // multiple threads, so we will deduplicate them.
-  InternalMmapVector<const ThreadContextBase *> stacks;
-
-  registry.RunCallbackForEachThreadLocked(
-      [](ThreadContextBase *context, void *arg) {
-        static_cast<decltype(&stacks)>(arg)->push_back(context);
-      },
-      &stacks);
-
-  Sort(stacks.data(), stacks.size(),
-       [](const ThreadContextBase *a, const ThreadContextBase *b) {
-         if (a->stack_id < b->stack_id)
-           return true;
-         if (a->stack_id > b->stack_id)
-           return false;
-         return a->unique_id < b->unique_id;
-       });
-
-  auto describe_thread = [&](const ThreadContextBase *context) {
-    if (!context) {
-      out.Append("T-1");
-      return;
-    }
-    out.AppendF("T%llu/%llu", context->unique_id, context->os_id);
-    if (internal_strlen(context->name))
-      out.AppendF(" (%s)", context->name);
-  };
-
-  auto get_parent =
-      [&](const ThreadContextBase *context) -> const ThreadContextBase * {
-    if (!context)
-      return nullptr;
-    ThreadContextBase *parent = registry.GetThreadLocked(context->parent_tid);
-    if (!parent)
-      return nullptr;
-    if (parent->unique_id >= context->unique_id)
-      return nullptr;
-    return parent;
-  };
-
-  const ThreadContextBase *prev = nullptr;
-  for (const ThreadContextBase *context : stacks) {
-    if (prev && prev->stack_id != context->stack_id)
-      StackDepotGet(prev->stack_id).PrintTo(&out);
-    prev = context;
-    out.Append("Thread ");
-    describe_thread(context);
-    out.Append(" was created by ");
-    describe_thread(get_parent(context));
-    out.Append("\n");
-  }
-  if (prev)
-    StackDepotGet(prev->stack_id).PrintTo(&out);
-}
-
-}  // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h b/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h
deleted file mode 100644
index 2995f6015fe50e..00000000000000
--- a/compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h
+++ /dev/null
@@ -1,24 +0,0 @@
-//===-- sanitizer_thread_history.h ------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Utility to print thread histroy from ThreadRegistry.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_THREAD_HISTORY_H
-#define SANITIZER_THREAD_HISTORY_H
-
-#include "sanitizer_thread_registry.h"
-
-namespace __sanitizer {
-
-void PrintThreadHistory(ThreadRegistry& registry, InternalScopedString& out);
-
-}  // namespace __sanitizer
-
-#endif  // SANITIZER_THREAD_HISTORY_H
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp
index 6e84ecdfeba683..c3cac707f0a0b3 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cpp
@@ -11,19 +11,11 @@
 //===----------------------------------------------------------------------===//
 #include "sanitizer_common/sanitizer_thread_registry.h"
 
-#include <iostream>
 #include <vector>
 
-#include "gmock/gmock.h"
 #include "gtest/gtest.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_stackdepot.h"
-#include "sanitizer_common/sanitizer_stacktrace.h"
-#include "sanitizer_common/sanitizer_thread_history.h"
 #include "sanitizer_pthread_wrappers.h"
 
-using testing::HasSubstr;
-
 namespace __sanitizer {
 
 static Mutex tctx_allocator_lock;
@@ -247,56 +239,4 @@ TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
   ThreadedTestRegistry(&registry);
 }
 
-TEST(SanitizerCommon, PrintThreadHistory) {
-  ThreadRegistry registry(GetThreadContext<TestThreadContext>,
-                          kThreadsPerShard * kNumShards + 1, 10, 0);
-
-  UNINITIALIZED BufferedStackTrace stack1;
-  stack1.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,
-                /*max_depth=*/1);
-
-  UNINITIALIZED BufferedStackTrace stack2;
-  stack2.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,
-                /*max_depth=*/1);
-
-  EXPECT_EQ(0U, registry.CreateThread(0, true, -1, 0, nullptr));
-  for (int i = 0; i < 5; i++) {
-    registry.CreateThread(0, true, 0, StackDepotPut(stack1), nullptr);
-    registry.CreateThread(0, true, 0, StackDepotPut(stack2), nullptr);
-  }
-
-  InternalScopedString out;
-  PrintThreadHistory(registry, out);
-
-  std::string substrings[] = {
-      "Thread T0/0 was created by T-1",
-      "<empty stack>",
-      "",
-      "Thread T1/0 was created by T0/0",
-      "Thread T3/0 was created by T0/0",
-      "Thread T5/0 was created by T0/0",
-      "Thread T7/0 was created by T0/0",
-      "Thread T9/0 was created by T0/0",
-      "#0 0x",
-      "",
-      "Thread T2/0 was created by T0/0",
-      "Thread T4/0 was created by T0/0",
-      "Thread T6/0 was created by T0/0",
-      "Thread T8/0 was created by T0/0",
-      "Thread T10/0 was created by T0/0",
-      "#0 0x",
-      "",
-  };
-
-  std::stringstream ss(out.data());
-  std::string line;
-
-  for (auto substr : substrings) {
-    std::getline(ss, line);
-    EXPECT_THAT(line, HasSubstr(substr)) << line;
-  }
-
-  EXPECT_FALSE(std::getline(ss, line)) << "Unmatched line: " << line;
-}
-
 }  // namespace __sanitizer



More information about the llvm-commits mailing list