diff --git a/src/runtime/tracemap.go b/src/runtime/tracemap.go index 9efa325c112..1d6aabb4310 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 51f3c29445c..0da217fba98 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 d486f9efbdf..bd31f06a670 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() {