diff options
| author | Tobias Grieger <tobias.b.grieger@gmail.com> | 2026-03-26 07:47:30 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-26 10:04:11 -0700 |
| commit | 1cfd0dc9a3416c1077acfcd44ad0084dd508116a (patch) | |
| tree | f4a1c0b1098406e1a1a638d70d5797d07d5aba1b /src/runtime | |
| parent | 5e17860e1b177b146c965f4ab1cb7d7ea51b91ed (diff) | |
| download | go-1cfd0dc9a3416c1077acfcd44ad0084dd508116a.tar.xz | |
runtime: truncate trace strings before inserting into trace map
traceStringTable.put inserted the full user-supplied string into the
trace map, then only truncated it to MaxEventTrailerDataSize (1024
bytes) when writing to the trace buffer. If the string exceeded the
traceRegionAlloc block size (~64KB), this caused a fatal
"traceRegion: alloc too large" crash.
Move the truncation to the top of put, before the map insertion, so
that the map key, map entry, and written output are all consistent
and bounded.
The existing truncation in writeString is retained: the emit method
also calls writeString without going through the map, so writeString
still needs its own guard.
TestStartRegionLongString reproduces the crash before the fix.
Observed in production at CockroachDB: Stopper.RunTask passes
singleflight keys (up to ~450KB) as trace region names via
trace.StartRegion. See:
https://github.com/cockroachdb/cockroach/pull/166669 for context
on the trigger.
Change-Id: I95d0b2f0bd2e806840b83a0b675ce6d2f0e2c2c5
GitHub-Last-Rev: 3c53061685d5237f9f2fc4522fce6d774776fede
GitHub-Pull-Request: golang/go#78348
Reviewed-on: https://go-review.googlesource.com/c/go/+/759140
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/trace/annotation_test.go | 13 | ||||
| -rw-r--r-- | src/runtime/tracestring.go | 5 |
2 files changed, 18 insertions, 0 deletions
diff --git a/src/runtime/trace/annotation_test.go b/src/runtime/trace/annotation_test.go index ea10843230..63e01fab9c 100644 --- a/src/runtime/trace/annotation_test.go +++ b/src/runtime/trace/annotation_test.go @@ -8,9 +8,22 @@ import ( "context" "io" . "runtime/trace" + "strings" "testing" ) +func TestStartRegionLongString(t *testing.T) { + // Regression test: a region name longer than the trace region + // allocator's block size (~64KB) used to crash with + // "traceRegion: alloc too large" because traceStringTable.put + // inserted the full string into the trace map before truncation. + Start(io.Discard) + defer Stop() + + big := strings.Repeat("x", 70_000) + StartRegion(context.Background(), big).End() +} + func BenchmarkStartRegion(b *testing.B) { b.ReportAllocs() ctx, task := NewTask(context.Background(), "benchmark") diff --git a/src/runtime/tracestring.go b/src/runtime/tracestring.go index bd31f06a67..d85299441b 100644 --- a/src/runtime/tracestring.go +++ b/src/runtime/tracestring.go @@ -25,6 +25,11 @@ type traceStringTable struct { // put adds a string to the table, emits it, and returns a unique ID for it. func (t *traceStringTable) put(gen uintptr, s string) uint64 { + // Truncate the string now to avoid wasting space in the + // traceMap and to stay within traceRegionAlloc's block size limit. + if len(s) > tracev2.MaxEventTrailerDataSize { + s = s[:tracev2.MaxEventTrailerDataSize] + } // Put the string in the table. ss := stringStructOf(&s) id, added := t.tab.put(ss.str, uintptr(ss.len)) |
