[compiler-rt] lib/tsan/go: add mechanism to skip frames (PR #174049)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 30 17:07:52 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-compiler-rt-sanitizer
Author: Keith Randall (randall77)
<details>
<summary>Changes</summary>
Some Go frames are wrapper functions that we don't want to report to users. Add a mechanism for the Go runtime to tell the tsan runtime not to report those frames.
For https://github.com/golang/go/issues/73915
@<!-- -->dvyukov
---
Full diff: https://github.com/llvm/llvm-project/pull/174049.diff
4 Files Affected:
- (modified) compiler-rt/lib/tsan/go/tsan_go.cpp (+35-15)
- (modified) compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp (+7-1)
- (modified) compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp (+1-1)
- (modified) compiler-rt/lib/tsan/rtl/tsan_symbolize.h (+1-1)
``````````diff
diff --git a/compiler-rt/lib/tsan/go/tsan_go.cpp b/compiler-rt/lib/tsan/go/tsan_go.cpp
index c689a51fb5e1d..c987ceacaaea0 100644
--- a/compiler-rt/lib/tsan/go/tsan_go.cpp
+++ b/compiler-rt/lib/tsan/go/tsan_go.cpp
@@ -49,30 +49,50 @@ struct SymbolizeCodeContext {
uptr res;
};
-SymbolizedStack *SymbolizeCode(uptr addr) {
- SymbolizedStack *first = SymbolizedStack::New(addr);
- SymbolizedStack *s = first;
+SymbolizedStack* SymbolizeCode(uptr addr, bool leaf) {
+ // addr is a single physical pc, and we return a set of
+ // virtual frames corresponding to that pc.
+ // Multiple virtual frames are possible because of inlining.
+ // Returned frames are ordered from newest to oldest.
+ //
+ // Note: stack walk order is weird here. Tsan calls this on physical
+ // frames from root to leaf (oldest to youngest frame).
+ // The loop within this function iterates through multiple virtual
+ // frames for a given physical frame. The loop iterates in the
+ // opposite direction, from youngest virtual frame to oldest
+ // virtual frame for the given single physical frame.
+ SymbolizedStack* first = nullptr;
+ SymbolizedStack* s = nullptr;
for (;;) {
SymbolizeCodeContext cbctx;
internal_memset(&cbctx, 0, sizeof(cbctx));
cbctx.pc = addr;
go_runtime_cb(CallbackSymbolizeCode, &cbctx);
- if (cbctx.res == 0)
+ if (cbctx.res == 0) // error of some sort
break;
- AddressInfo &info = s->info;
- info.module_offset = cbctx.off;
- info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
- info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
- info.line = cbctx.line;
- info.column = 0;
-
+ if (cbctx.res != 2 || leaf) {
+ // res == 2 means it is a wrapper function we don't want to
+ // display (unless it is the leaf frame).
+ if (first == nullptr) {
+ first = SymbolizedStack::New(addr);
+ s = first;
+ } else {
+ // Allocate a stack entry for the parent of the inlined function.
+ SymbolizedStack* s2 = SymbolizedStack::New(addr);
+ s->next = s2;
+ s = s2;
+ }
+ AddressInfo& info = s->info;
+ info.module_offset = cbctx.off;
+ info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
+ info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
+ info.line = cbctx.line;
+ info.column = 0;
+ }
if (cbctx.pc == addr) // outermost (non-inlined) function
break;
addr = cbctx.pc;
- // Allocate a stack entry for the parent of the inlined function.
- SymbolizedStack *s2 = SymbolizedStack::New(addr);
- s->next = s2;
- s = s2;
+ leaf = false;
}
return first;
}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
index 43aef30d2f3b3..4e58305b582d5 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
@@ -111,7 +111,13 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
// instruction.
if ((pc & kExternalPCBit) == 0)
pc1 = StackTrace::GetPreviousInstructionPc(pc);
- SymbolizedStack *ent = SymbolizeCode(pc1);
+ SymbolizedStack* ent = SymbolizeCode(pc1, si == trace.size - 1);
+#if SANITIZER_GO
+ if (ent == nullptr) {
+ // Go might have 0 frames for this PC (wrapper frames aren't reported).
+ continue;
+ }
+#endif
CHECK_NE(ent, 0);
SymbolizedStack *last = ent;
while (last->next) {
diff --git a/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp b/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp
index 2e2744d2eae78..b382b63247e8e 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_symbolize.cpp
@@ -79,7 +79,7 @@ static void AddFrame(void *ctx, const char *function_name, const char *file,
info->column = column;
}
-SymbolizedStack *SymbolizeCode(uptr addr) {
+SymbolizedStack* SymbolizeCode(uptr addr, bool leaf) {
// Check if PC comes from non-native land.
if (addr & kExternalPCBit) {
SymbolizedStackBuilder ssb = {nullptr, nullptr, addr};
diff --git a/compiler-rt/lib/tsan/rtl/tsan_symbolize.h b/compiler-rt/lib/tsan/rtl/tsan_symbolize.h
index 7adaa04dc273e..2fe34f00a32fc 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_symbolize.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_symbolize.h
@@ -19,7 +19,7 @@ namespace __tsan {
void EnterSymbolizer();
void ExitSymbolizer();
-SymbolizedStack *SymbolizeCode(uptr addr);
+SymbolizedStack* SymbolizeCode(uptr addr, bool leaf);
ReportLocation *SymbolizeData(uptr addr);
void SymbolizeFlush();
``````````
</details>
https://github.com/llvm/llvm-project/pull/174049
More information about the llvm-commits
mailing list