[compiler-rt] [NFC][TSan] Remove redundant ThreadRegistryLock debug check in ShouldReport (PR #228815)
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 6 09:59:38 PDT 2026
https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/228815
>From 6b38839ddc637773820b25383e14b8cbc1b806be Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Sat, 3 Oct 2026 20:15:00 -0700
Subject: [PATCH 1/2] =?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.7
[skip ci]
---
.../lib/tsan/rtl/tsan_interceptors_posix.cpp | 24 +---
.../lib/tsan/rtl/tsan_interface_ann.cpp | 26 ++--
compiler-rt/lib/tsan/rtl/tsan_mman.cpp | 16 +--
compiler-rt/lib/tsan/rtl/tsan_report.cpp | 22 +--
compiler-rt/lib/tsan/rtl/tsan_report.h | 64 +++++----
compiler-rt/lib/tsan/rtl/tsan_rtl.cpp | 4 +-
compiler-rt/lib/tsan/rtl/tsan_rtl.h | 2 +
compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp | 98 +++++--------
compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp | 133 +++++++++---------
compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp | 18 +--
10 files changed, 168 insertions(+), 239 deletions(-)
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index b2ba666741e891..b0eb92fbd6a507 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -2176,24 +2176,12 @@ static void ReportErrnoSpoiling(ThreadState *thr, uptr pc, int sig) {
// StackTrace::GetNestInstructionPc(pc) is used because return address is
// expected, OutputReport() will undo this.
ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack);
- // Use alloca, because malloc during signal handling deadlocks
- ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport));
- bool suppressed;
- // Release locks before symbolizing and outputting the report to avoid
- // deadlocks.
- {
- ThreadRegistryLock l(&ctx->thread_registry);
- new (rep) ScopedReport(ReportTypeErrnoInSignal);
- rep->SetSigNum(sig);
- suppressed = IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack);
- if (!suppressed)
- rep->AddStack(stack, true);
- }
- if (!suppressed)
- OutputReport(thr, *rep);
-
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ if (IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack))
+ return;
+ ScopedReport rep(ReportTypeErrnoInSignal);
+ rep.SetSigNum(sig);
+ rep.AddStack(stack, true);
+ OutputReport(thr, rep);
}
static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cpp b/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cpp
index 526dc5a753c24f..445e84c843237b 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interface_ann.cpp
@@ -441,25 +441,15 @@ void __tsan_mutex_post_divert(void *addr, unsigned flagz) {
}
static void ReportMutexHeldWrongContext(ThreadState *thr, uptr pc) {
- // 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 l(&ctx->thread_registry);
- new (rep) ScopedReport(ReportTypeMutexHeldWrongContext);
- for (uptr i = 0; i < thr->mset.Size(); ++i) {
- MutexSet::Desc desc = thr->mset.Get(i);
- rep->AddMutex(desc.addr, desc.stack_id);
- }
- VarSizeStackTrace trace;
- ObtainCurrentStack(thr, pc, &trace);
- rep->AddStack(trace, true);
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
+ ScopedReport rep(ReportTypeMutexHeldWrongContext);
+ for (uptr i = 0; i < thr->mset.Size(); ++i) {
+ MutexSet::Desc desc = thr->mset.Get(i);
+ rep.AddMutex(desc.addr, desc.stack_id);
}
- OutputReport(thr, *rep);
-
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ rep.AddStack(trace, true);
+ OutputReport(thr, rep);
}
INTERFACE_ATTRIBUTE
diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
index cea833054551d3..fda49d9fb8f428 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp
@@ -182,19 +182,9 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
ObtainCurrentStack(thr, pc, &stack);
if (IsFiredSuppression(ctx, ReportTypeSignalUnsafe, stack))
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 l(&ctx->thread_registry);
- new (rep) ScopedReport(ReportTypeSignalUnsafe);
- rep->AddStack(stack, true);
- }
- OutputReport(thr, *rep);
-
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ ScopedReport rep(ReportTypeSignalUnsafe);
+ rep.AddStack(stack, true);
+ OutputReport(thr, rep);
}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_report.cpp
index 17fd3064fb85a1..ca04f9e1faf074 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_report.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_report.cpp
@@ -29,25 +29,13 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator {
const char *Mutex() { return Magenta(); }
};
-ReportDesc::ReportDesc()
- : tag(kExternalTagNone)
- , stacks()
- , mops()
- , locs()
- , mutexes()
- , threads()
- , unique_tids()
- , sleep()
- , count() {
-}
+ReportDesc::ReportDesc() = default;
-ReportMop::ReportMop()
- : mset() {
-}
+ReportMop::ReportMop() = default;
+ReportMop::~ReportMop() = default;
-ReportDesc::~ReportDesc() {
- // FIXME(dvyukov): it must be leaking a lot of memory.
-}
+// FIXME(dvyukov): it must be leaking a lot of memory.
+ReportDesc::~ReportDesc() = default;
#if !SANITIZER_GO
diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.h b/compiler-rt/lib/tsan/rtl/tsan_report.h
index 53bb21964dbba9..13171aa2706843 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_report.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_report.h
@@ -46,22 +46,23 @@ struct ReportStack {
};
struct ReportMopMutex {
- int id;
- bool write;
+ int id = 0;
+ bool write = false;
};
struct ReportMop {
- int tid;
- uptr addr;
- int size;
- bool write;
- bool atomic;
- uptr external_tag;
+ int tid = kInvalidTid;
+ uptr addr = 0;
+ int size = 0;
+ bool write = false;
+ bool atomic = false;
+ uptr external_tag = 0;
Vector<ReportMopMutex> mset;
StackTrace stack_trace;
- ReportStack *stack;
+ ReportStack* stack = nullptr;
ReportMop();
+ ~ReportMop();
};
enum ReportLocationType {
@@ -87,42 +88,49 @@ struct ReportLocation {
};
struct ReportThread {
- Tid id;
- ThreadID os_id;
- bool running;
- ThreadType thread_type;
- char *name;
- Tid parent_tid;
- StackID stack_id;
- ReportStack *stack;
- bool suppressable;
+ Tid id = kInvalidTid;
+ ThreadID os_id = 0;
+ bool running = false;
+ ThreadType thread_type = ThreadType::Regular;
+ char* name = nullptr;
+ Tid parent_tid = kInvalidTid;
+ StackID stack_id = 0;
+ ReportStack* stack = nullptr;
+ bool suppressable = false;
};
struct ReportMutex {
- int id;
- uptr addr;
- StackID stack_id;
- ReportStack *stack;
+ int id = 0;
+ uptr addr = 0;
+ StackID stack_id = 0;
+ ReportStack* stack = nullptr;
};
struct AddedLocationAddr {
- uptr addr;
- usize locs_idx;
+ uptr addr = 0;
+ usize locs_idx = 0;
+};
+
+struct AddedStack {
+ StackTrace stack_trace;
+ bool suppressable = false;
};
class ReportDesc {
public:
- ReportType typ;
- uptr tag;
+ ReportType typ = ReportTypeRace;
+ uptr tag = kExternalTagNone;
Vector<ReportStack*> stacks;
+ Vector<AddedStack> added_stacks;
Vector<ReportMop*> mops;
Vector<ReportLocation*> locs;
Vector<AddedLocationAddr> added_location_addrs;
Vector<ReportMutex*> mutexes;
Vector<ReportThread*> threads;
Vector<Tid> unique_tids;
- ReportStack *sleep;
- int count;
+ ReportStack* sleep = nullptr;
+ StackID sleep_stack_id = 0;
+ int count = 0;
int signum = 0;
ReportDesc();
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index c6e7dce5ecb181..7328caab0a9186 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -841,10 +841,10 @@ void ForkBefore(ThreadState* thr, uptr pc) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
// Detaching from the slot makes OnUserFree skip writing to the shadow.
// The slot will be locked so any attempts to use it will deadlock anyway.
SlotDetach(thr);
+ ScopedErrorReportLock::Lock();
for (auto& slot : ctx->slots) slot.mtx.Lock();
ctx->thread_registry.Lock();
ctx->slot_mtx.Lock();
- ScopedErrorReportLock::Lock();
AllocatorLockBeforeFork();
// Suppress all reports in the pthread_atfork callbacks.
// Reports may deadlock.
@@ -871,10 +871,10 @@ static void ForkAfter(ThreadState* thr,
thr->ignore_interceptors--;
thr->ignore_reads_and_writes--;
AllocatorUnlockAfterFork(child);
- ScopedErrorReportLock::Unlock();
ctx->slot_mtx.Unlock();
ctx->thread_registry.Unlock();
for (auto& slot : ctx->slots) slot.mtx.Unlock();
+ ScopedErrorReportLock::Unlock();
SlotAttachAndLock(thr);
SlotUnlock(thr);
GlobalProcessorUnlock();
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index a4bf790d5980bc..5b4e5362779e78 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -440,6 +440,8 @@ class ScopedReport {
ScopedIgnoreInterceptors ignore_interceptors_;
ScopedErrorReportLock lock_;
+ void AddThreadLocked(const ThreadContext* tctx, bool suppressable = false);
+
ScopedReport(const ScopedReport&) = delete;
void operator=(const ScopedReport&) = delete;
};
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
index 271412f4c40885..8d5bad370a5a0e 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
@@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//
#include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
-#include <sanitizer_common/sanitizer_placement_new.h>
#include <sanitizer_common/sanitizer_stackdepot.h>
#include "tsan_flags.h"
@@ -56,23 +55,13 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
return;
if (!ShouldReport(thr, typ))
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 l(&ctx->thread_registry);
- new (rep) ScopedReport(typ);
- rep->AddMutex(addr, creation_stack_id);
- VarSizeStackTrace trace;
- ObtainCurrentStack(thr, pc, &trace);
- rep->AddStack(trace, true);
- rep->AddLocation(addr, 1);
- }
- OutputReport(thr, *rep);
-
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
+ ScopedReport rep(typ);
+ rep.AddMutex(addr, creation_stack_id);
+ rep.AddStack(trace, true);
+ rep.AddLocation(addr, 1);
+ OutputReport(thr, rep);
}
static void RecordMutexLock(ThreadState *thr, uptr pc, uptr addr,
@@ -538,38 +527,28 @@ void AfterSleep(ThreadState *thr, uptr pc) {
void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock))
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 l(&ctx->thread_registry);
- new (rep) ScopedReport(ReportTypeDeadlock);
- for (int i = 0; i < r->n; i++) {
- rep->AddMutex(r->loop[i].mtx_ctx0, r->loop[i].stk[0]);
- rep->AddUniqueTid((int)r->loop[i].thr_ctx);
- rep->AddThread((int)r->loop[i].thr_ctx);
- }
- uptr dummy_pc = 0x42;
- for (int i = 0; i < r->n; i++) {
- for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
- u32 stk = r->loop[i].stk[j];
- StackTrace stack;
- if (stk && stk != kInvalidStackID) {
- stack = StackDepotGet(stk);
- } else {
- // Sometimes we fail to extract the stack trace (FIXME: investigate),
- // but we should still produce some stack trace in the report.
- stack = StackTrace(&dummy_pc, 1);
- }
- rep->AddStack(stack, true);
+ uptr dummy_pc = 0x42;
+ ScopedReport rep(ReportTypeDeadlock);
+ for (int i = 0; i < r->n; i++) {
+ rep.AddMutex(r->loop[i].mtx_ctx0, r->loop[i].stk[0]);
+ rep.AddUniqueTid((int)r->loop[i].thr_ctx);
+ rep.AddThread((int)r->loop[i].thr_ctx);
+ }
+ for (int i = 0; i < r->n; i++) {
+ for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
+ u32 stk = r->loop[i].stk[j];
+ StackTrace stack;
+ if (stk && stk != kInvalidStackID) {
+ stack = StackDepotGet(stk);
+ } else {
+ // Sometimes we fail to extract the stack trace (FIXME: investigate),
+ // but we should still produce some stack trace in the report.
+ stack = StackTrace(&dummy_pc, 1);
}
+ rep.AddStack(stack, true);
}
}
- OutputReport(thr, *rep);
-
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ OutputReport(thr, rep);
}
void ReportDestroyLocked(ThreadState *thr, uptr pc, uptr addr,
@@ -590,24 +569,15 @@ void ReportDestroyLocked(ThreadState *thr, uptr pc, uptr addr,
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);
+ VarSizeStackTrace trace;
+ ObtainCurrentStack(thr, pc, &trace);
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ ScopedReport rep(ReportTypeMutexDestroyLocked);
+ rep.AddMutex(addr, creation_stack_id);
+ rep.AddStack(trace, true);
+ rep.AddStack(last_lock_stack, true);
+ rep.AddLocation(addr, 1);
+ OutputReport(thr, rep);
}
} // namespace __tsan
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
index be444eec3a4b78..1d76a886dc5361 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
@@ -164,7 +164,7 @@ bool ShouldReport(ThreadState *thr, ReportType typ) {
}
ScopedReport::ScopedReport(ReportType typ, uptr tag) {
- ctx->thread_registry.CheckLocked();
+ CheckedMutex::CheckNoLocks();
rep_ = New<ReportDesc>();
rep_->typ = typ;
rep_->tag = tag;
@@ -173,9 +173,7 @@ ScopedReport::ScopedReport(ReportType typ, uptr tag) {
ScopedReport::~ScopedReport() { DestroyAndFree(rep_); }
void ScopedReport::AddStack(StackTrace stack, bool suppressable) {
- ReportStack **rs = rep_->stacks.PushBack();
- *rs = SymbolizeStack(stack);
- (*rs)->suppressable = suppressable;
+ rep_->added_stacks.PushBack({stack, suppressable});
}
void ScopedReport::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s,
@@ -202,6 +200,15 @@ void ScopedReport::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s,
}
void ScopedReport::SymbolizeStackElems() {
+ // symbolize stacks
+ for (usize i = 0, size = rep_->added_stacks.Size(); i < size; i++) {
+ AddedStack& as = rep_->added_stacks[i];
+ ReportStack* rs = SymbolizeStack(as.stack_trace);
+ if (rs)
+ rs->suppressable = as.suppressable;
+ rep_->stacks.PushBack(rs);
+ }
+
// symbolize memory ops
for (usize i = 0, size = rep_->mops.Size(); i < size; i++) {
ReportMop *mop = rep_->mops[i];
@@ -249,6 +256,10 @@ void ScopedReport::SymbolizeStackElems() {
ReportMutex *rm = rep_->mutexes[i];
rm->stack = SymbolizeStackId(rm->stack_id);
}
+
+#if !SANITIZER_GO
+ rep_->sleep = SymbolizeStackId(rep_->sleep_stack_id);
+#endif
}
void ScopedReport::AddUniqueTid(Tid unique_tid) {
@@ -256,6 +267,13 @@ void ScopedReport::AddUniqueTid(Tid unique_tid) {
}
void ScopedReport::AddThread(const ThreadContext* tctx, bool suppressable) {
+ ThreadRegistryLock l(&ctx->thread_registry);
+ AddThreadLocked(tctx, suppressable);
+}
+
+void ScopedReport::AddThreadLocked(const ThreadContext* tctx,
+ bool suppressable) {
+ ctx->thread_registry.CheckLocked();
for (uptr i = 0; i < rep_->threads.Size(); i++) {
if ((u32)rep_->threads[i]->id == tctx->tid)
return;
@@ -273,12 +291,6 @@ void ScopedReport::AddThread(const ThreadContext* tctx, bool suppressable) {
}
#if !SANITIZER_GO
-static ThreadContext *FindThreadByTidLocked(Tid tid) {
- ctx->thread_registry.CheckLocked();
- return static_cast<ThreadContext *>(
- ctx->thread_registry.GetThreadLocked(tid));
-}
-
static bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) {
uptr addr = (uptr)arg;
ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
@@ -305,10 +317,10 @@ ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
#endif
void ScopedReport::AddThread(Tid tid, bool suppressable) {
-#if !SANITIZER_GO
- if (const ThreadContext *tctx = FindThreadByTidLocked(tid))
- AddThread(tctx, suppressable);
-#endif
+ ThreadRegistryLock l(&ctx->thread_registry);
+ if (const auto* tctx = static_cast<ThreadContext*>(
+ ctx->thread_registry.GetThreadLocked(tid)))
+ AddThreadLocked(tctx, suppressable);
}
int ScopedReport::AddMutex(uptr addr, StackID creation_stack_id) {
@@ -366,12 +378,15 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
return;
}
bool is_stack = false;
- if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
- auto *loc = New<ReportLocation>();
- loc->type = is_stack ? ReportLocationStack : ReportLocationTLS;
- loc->tid = tctx->tid;
- rep_->locs.PushBack(loc);
- AddThread(tctx);
+ {
+ ThreadRegistryLock l(&ctx->thread_registry);
+ if (ThreadContext* tctx = IsThreadStackOrTls(addr, &is_stack)) {
+ auto* loc = New<ReportLocation>();
+ loc->type = is_stack ? ReportLocationStack : ReportLocationTLS;
+ loc->tid = tctx->tid;
+ rep_->locs.PushBack(loc);
+ AddThreadLocked(tctx);
+ }
}
#endif
rep_->added_location_addrs.PushBack({addr, rep_->locs.Size()});
@@ -380,7 +395,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
#if !SANITIZER_GO
void ScopedReport::AddSleep(StackID stack_id) {
- rep_->sleep = SymbolizeStackId(stack_id);
+ rep_->sleep_stack_id = stack_id;
}
#endif
@@ -671,6 +686,7 @@ static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2]) {
}
bool OutputReport(ThreadState *thr, ScopedReport &srep) {
+ CheckedMutex::CheckNoLocks();
// These should have been checked in ShouldReport.
// It's too late to check them here, we have already taken locks.
CHECK(flags()->report_bugs);
@@ -804,10 +820,6 @@ void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
DynamicMutexSet mset1;
MutexSet *mset[kMop] = {&thr->mset, mset1};
- // 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.
{
// We need to lock the slot during RestoreStack because it protects
// the slot journal.
@@ -821,57 +833,48 @@ void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
StoreShadow(&ctx->last_spurious_race, old.raw());
return;
}
+ }
- if (IsFiredSuppression(ctx, rep_typ, traces[1]))
- return;
+ if (IsFiredSuppression(ctx, rep_typ, traces[1]))
+ return;
- if (HandleRacyStacks(thr, traces))
- return;
+ if (HandleRacyStacks(thr, traces))
+ return;
- // If any of the accesses has a tag, treat this as an "external" race.
- uptr tag = kExternalTagNone;
- for (uptr i = 0; i < kMop; i++) {
- if (tags[i] != kExternalTagNone) {
- rep_typ = ReportTypeExternalRace;
- tag = tags[i];
- break;
- }
+ // If any of the accesses has a tag, treat this as an "external" race.
+ uptr tag = kExternalTagNone;
+ for (uptr i = 0; i < kMop; i++) {
+ if (tags[i] != kExternalTagNone) {
+ rep_typ = ReportTypeExternalRace;
+ tag = tags[i];
+ break;
}
+ }
- new (rep) ScopedReport(rep_typ, tag);
- for (uptr i = 0; i < kMop; i++)
- rep->AddMemoryAccess(addr, tags[i], s[i], tids[i], traces[i], mset[i]);
+ ScopedReport rep(rep_typ, tag);
+ for (uptr i = 0; i < kMop; i++)
+ rep.AddMemoryAccess(addr, tags[i], s[i], tids[i], traces[i], mset[i]);
- for (uptr i = 0; i < kMop; i++) {
- ThreadContext *tctx = static_cast<ThreadContext *>(
- ctx->thread_registry.GetThreadLocked(tids[i]));
- rep->AddThread(tctx);
- }
+ for (uptr i = 0; i < kMop; i++) rep.AddThread(tids[i]);
- 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<ThreadContext *>(
- ctx->thread_registry.GetThreadLocked(parent_tid));
- rep->AddThread(parent_tctx);
- }
+ 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;
+ rep.AddThread(parent_tid);
}
+ }
#if !SANITIZER_GO
- if (!((typ0 | typ1) & kAccessFree) &&
- s[1].epoch() <= thr->last_sleep_clock.Get(s[1].sid()))
- rep->AddSleep(thr->last_sleep_stack_id);
+ if (!((typ0 | typ1) & kAccessFree) &&
+ s[1].epoch() <= thr->last_sleep_clock.Get(s[1].sid()))
+ rep.AddSleep(thr->last_sleep_stack_id);
#endif
- }
- OutputReport(thr, *rep);
-
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ OutputReport(thr, rep);
}
void PrintCurrentStack(ThreadState *thr, uptr pc) {
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
index afc6b8d4a0b1cd..da9e56a5b8f8d6 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
@@ -96,20 +96,10 @@ void ThreadFinalize(ThreadState *thr) {
}
for (uptr i = 0; i < leaks.Size(); i++) {
- // 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 l(&ctx->thread_registry);
- new (rep) ScopedReport(ReportTypeThreadLeak);
- rep->AddThread(leaks[i].tctx, true);
- rep->SetCount(leaks[i].count);
- }
- OutputReport(thr, *rep);
-
- // Need to manually destroy this because we used placement new to allocate
- rep->~ScopedReport();
+ ScopedReport rep(ReportTypeThreadLeak);
+ rep.AddThread(leaks[i].tctx, true);
+ rep.SetCount(leaks[i].count);
+ OutputReport(thr, rep);
}
#endif
}
>From 35887d5baac4fd7eae56506e827cccb4634cef17 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Sat, 3 Oct 2026 22:00:32 -0700
Subject: [PATCH 2/2] Address review: drop EnterSymbolizer CheckNoLocks, fix
commit messages
Created using spr 1.3.7
---
compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp b/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp
index 51028e9ce59415..b382b63247e8ed 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp
@@ -22,7 +22,6 @@
namespace __tsan {
void EnterSymbolizer() {
- CheckedMutex::CheckNoLocks();
ThreadState *thr = cur_thread();
CHECK(!thr->in_symbolizer);
thr->in_symbolizer = true;
More information about the llvm-commits
mailing list