aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTobias Grieger <tobias.b.grieger@gmail.com>2026-03-26 07:47:30 +0000
committerGopher Robot <gobot@golang.org>2026-03-26 10:04:11 -0700
commit1cfd0dc9a3416c1077acfcd44ad0084dd508116a (patch)
treef4a1c0b1098406e1a1a638d70d5797d07d5aba1b /src
parent5e17860e1b177b146c965f4ab1cb7d7ea51b91ed (diff)
downloadgo-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')
-rw-r--r--src/runtime/trace/annotation_test.go13
-rw-r--r--src/runtime/tracestring.go5
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))