aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2025-11-19 03:51:20 +0000
committerGopher Robot <gobot@golang.org>2025-11-24 13:20:09 -0800
commit0bc192368ac603614dc3f240e751f539d91a1db2 (patch)
tree9151ab8162d8dfb2f49dda957aaaeb13847fb81e /src/runtime
parentd4f5650cc5cdc5fa559491991208f8563bd6f3b8 (diff)
downloadgo-0bc192368ac603614dc3f240e751f539d91a1db2.tar.xz
runtime: don't write unique string to trace if it's length zero
While we're here, document that ID 0 is implicitly assigned to an empty set of data for both stacks and strings. Change-Id: Ic52ff3a1132abc5a8f6f6c4e4357e31e6e7799fc Reviewed-on: https://go-review.googlesource.com/c/go/+/723061 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/tracemap.go7
-rw-r--r--src/runtime/tracestack.go9
-rw-r--r--src/runtime/tracestring.go5
3 files changed, 18 insertions, 3 deletions
diff --git a/src/runtime/tracemap.go b/src/runtime/tracemap.go
index 9efa325c11..1d6aabb431 100644
--- a/src/runtime/tracemap.go
+++ b/src/runtime/tracemap.go
@@ -23,6 +23,13 @@ import (
"unsafe"
)
+// traceMap is a map of a variable-sized array of bytes to a unique ID.
+//
+// Because traceMap just operates on raw bytes, this type is used as the
+// backing store for both the trace string table and trace stack table,
+// the latter of which is just an array of PCs.
+//
+// ID 0 is reserved for arrays of bytes of size zero.
type traceMap struct {
root atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap)
_ cpu.CacheLinePad
diff --git a/src/runtime/tracestack.go b/src/runtime/tracestack.go
index 51f3c29445..0da217fba9 100644
--- a/src/runtime/tracestack.go
+++ b/src/runtime/tracestack.go
@@ -136,8 +136,9 @@ func traceStack(skip int, gp *g, tab *traceStackTable) uint64 {
return id
}
-// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids.
-// It is lock-free for reading.
+// traceStackTable maps stack traces (arrays of PC's) to unique IDs.
+//
+// ID 0 is reserved for a zero-length stack.
type traceStackTable struct {
tab traceMap
}
@@ -145,8 +146,10 @@ type traceStackTable struct {
// put returns a unique id for the stack trace pcs and caches it in the table,
// if it sees the trace for the first time.
func (t *traceStackTable) put(pcs []uintptr) uint64 {
+ // Even though put will handle this for us, taking the address of pcs forces a bounds check
+ // that will fail if len(pcs) == 0.
if len(pcs) == 0 {
- return 0
+ return 0 // ID 0 is reserved for zero-length stacks.
}
id, _ := t.tab.put(noescape(unsafe.Pointer(&pcs[0])), uintptr(len(pcs))*unsafe.Sizeof(uintptr(0)))
return id
diff --git a/src/runtime/tracestring.go b/src/runtime/tracestring.go
index d486f9efbd..bd31f06a67 100644
--- a/src/runtime/tracestring.go
+++ b/src/runtime/tracestring.go
@@ -12,6 +12,8 @@ import "internal/trace/tracev2"
// traceStringTable is map of string -> unique ID that also manages
// writing strings out into the trace.
+//
+// ID 0 is reserved for the empty string.
type traceStringTable struct {
// lock protects buf.
lock mutex
@@ -37,6 +39,9 @@ func (t *traceStringTable) put(gen uintptr, s string) uint64 {
// emit emits a string and creates an ID for it, but doesn't add it to the table. Returns the ID.
func (t *traceStringTable) emit(gen uintptr, s string) uint64 {
+ if len(s) == 0 {
+ return 0 // Empty strings are implicitly assigned ID 0 already.
+ }
// Grab an ID and write the string to the buffer.
id := t.tab.stealID()
systemstack(func() {