diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2025-09-30 23:54:07 +0000 |
|---|---|---|
| committer | Michael Knyszek <mknyszek@google.com> | 2025-10-20 13:32:29 -0700 |
| commit | dc9a3e2a658176fe1884d65d5a0e7516145404eb (patch) | |
| tree | 6c2dd4a9a3f039ac371814d81fd0a2a8e2efe93a /src/runtime | |
| parent | df33c170919faca6ea849ee23fb0af6971fddc5b (diff) | |
| download | go-dc9a3e2a658176fe1884d65d5a0e7516145404eb.tar.xz | |
runtime: fix generation skew with trace reentrancy
Currently when performing multiple nested traceAcquires, we re-read
trace.gen on subsequent reads. But this is invalid, since a generation
transition may happen in between a traceAcquire and a nested
traceAcquire. The first one will produce a traceLocker with a gen from
the previous generation, and the second will produce a traceLocker from
the next generation. (Note: generations cannot _complete_ advancement
under traceAcquire, but trace.gen can move forward.) The end result is
earlier events, from the nested traceAcquire, will write to a future
generation, and then previous events will write to a past generation.
This can break the trace.
(There are also a lot of comments left over talking about the
non-reentrancy of the tracer; we should look at those again.)
Change-Id: I08ac8cc86d41ab3e6061c5de58d657b6ad0d19d8
Reviewed-on: https://go-review.googlesource.com/c/go/+/708397
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/traceruntime.go | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/src/runtime/traceruntime.go b/src/runtime/traceruntime.go index 06e36fd802..7df6f68b70 100644 --- a/src/runtime/traceruntime.go +++ b/src/runtime/traceruntime.go @@ -29,6 +29,7 @@ type mTraceState struct { buf [2][tracev2.NumExperiments]*traceBuf // Per-M traceBuf for writing. Indexed by trace.gen%2. link *m // Snapshot of alllink or freelink. reentered uint32 // Whether we've reentered tracing from within tracing. + entryGen uintptr // The generation value on first entry. oldthrowsplit bool // gp.throwsplit upon calling traceLocker.writer. For debugging. } @@ -212,7 +213,7 @@ func traceAcquireEnabled() traceLocker { // that it is. if mp.trace.seqlock.Load()%2 == 1 { mp.trace.reentered++ - return traceLocker{mp, trace.gen.Load()} + return traceLocker{mp, mp.trace.entryGen} } // Acquire the trace seqlock. This prevents traceAdvance from moving forward @@ -240,6 +241,7 @@ func traceAcquireEnabled() traceLocker { releasem(mp) return traceLocker{} } + mp.trace.entryGen = gen return traceLocker{mp, gen} } |
