[compiler-rt] [NFC][TSan] Move RestoreStack before ScopedReport in ReportDestroyLocked (PR #228643)

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 3 19:03:26 PDT 2026


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

>From 110a401351437ed785d13b9bf0d83c72ac050118 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Fri, 2 Oct 2026 20:06:49 -0700
Subject: [PATCH] [NFC][TSan] Move RestoreStack before ScopedReport in
 ReportDestroyLocked

Run RestoreStack in its own lock scope before constructing ScopedReport
in ReportDestroyLocked (matching ReportRace). This avoids acquiring
ScopedErrorReportLock or symbolizing the current stack if RestoreStack
fails, and avoids holding slot_lock and slot_mtx while populating the
ScopedReport.

Assisted-by: Gemini

Pull Request: https://github.com/llvm/llvm-project/pull/228643
---
 compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp | 29 ++++++++++++---------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
index da3604a2b840d..3809aab95e1e5 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
@@ -574,31 +574,34 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
 
 void ReportDestroyLocked(ThreadState *thr, uptr pc, uptr addr,
                          FastState last_lock, StackID creation_stack_id) {
-  // Use alloca, because malloc during signal handling deadlocks
-  ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport));
-  // Release locks before symbolizing and outputting the report to avoid
-  // deadlocks.
+  VarSizeStackTrace last_lock_stack;
   {
     // We need to lock the slot during RestoreStack because it protects
     // the slot journal.
     Lock slot_lock(&ctx->slots[static_cast<uptr>(last_lock.sid())].mtx);
     ThreadRegistryLock l0(&ctx->thread_registry);
     Lock slots_lock(&ctx->slot_mtx);
-    new (rep) ScopedReport(ReportTypeMutexDestroyLocked);
-    rep->AddMutex(addr, creation_stack_id);
-    VarSizeStackTrace trace;
-    ObtainCurrentStack(thr, pc, &trace);
-    rep->AddStack(trace, true);
-
     Tid tid;
     DynamicMutexSet mset;
     uptr tag;
     if (!RestoreStack(EventType::kLock, last_lock.sid(), last_lock.epoch(),
-                      addr, 0, kAccessWrite, &tid, &trace, mset, &tag)) {
-      rep->~ScopedReport();
+                      addr, 0, kAccessWrite, &tid, &last_lock_stack, mset,
+                      &tag))
       return;
-    }
+  }
+
+  // Use alloca, because malloc during signal handling deadlocks
+  ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport));
+  // Release locks before symbolizing and outputting the report to avoid
+  // deadlocks.
+  {
+    ThreadRegistryLock l0(&ctx->thread_registry);
+    new (rep) ScopedReport(ReportTypeMutexDestroyLocked);
+    rep->AddMutex(addr, creation_stack_id);
+    VarSizeStackTrace trace;
+    ObtainCurrentStack(thr, pc, &trace);
     rep->AddStack(trace, true);
+    rep->AddStack(last_lock_stack, true);
     rep->AddLocation(addr, 1);
   }
   OutputReport(thr, *rep);



More information about the llvm-commits mailing list