From cd2fa3b48dc059203aa724474e19096928b3f71f Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 17 Mar 2026 11:13:16 -0700 Subject: runtime: fix memclrNoHeapPointersPreemptible memclrNoHeapPointersChunked was originally written for clearing fresh allocations. It converts to uintptr early and thus doesn't handle the case where the pointer points to the stack. At the preemption point, the buffer being pointed to might be on the stack and copied to a new location. Then we'd end up zeroing random heap memory when we return from preemption. Fix it to keep the pointer to the allocation in an unsafe.Pointer, so it gets updated correctly on a stack copy. Update #78081 (Fixes?) Change-Id: Id25c7faf45f201929cb8c8bbcc7c8bd4f67c31ac Reviewed-on: https://go-review.googlesource.com/c/go/+/756122 Auto-Submit: Keith Randall Reviewed-by: Michael Pratt Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/runtime/malloc.go | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'src/runtime/malloc.go') diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 2144ea602a..44b4b3bc57 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -2184,22 +2184,27 @@ func reusableSize(size uintptr) bool { // Use this with care; if the data being cleared is tagged to contain // pointers, this allows the GC to run before it is all cleared. func memclrNoHeapPointersChunked(size uintptr, x unsafe.Pointer) { - v := uintptr(x) + if getg().preempt { + // TODO: no need for this, except to test that + // the preemption point is ok for small zeroings. + // (The pre-CL-756122 allowed preemption in this case, + // which is probably why we noticed 78081 at all.) + // Remove once we think 78081 is fixed. + // may hold locks, e.g., profiling + goschedguarded() + } // got this from benchmarking. 128k is too small, 512k is too large. const chunkBytes = 256 * 1024 - vsize := v + size - for voff := v; voff < vsize; voff = voff + chunkBytes { + for size > chunkBytes { + memclrNoHeapPointers(x, chunkBytes) + x = add(x, chunkBytes) + size -= chunkBytes if getg().preempt { // may hold locks, e.g., profiling goschedguarded() } - // clear min(avail, lump) bytes - n := vsize - voff - if n > chunkBytes { - n = chunkBytes - } - memclrNoHeapPointers(unsafe.Pointer(voff), n) } + memclrNoHeapPointers(x, size) } // memclrNoHeapPointersPreemptible is the compiler-callable entry point -- cgit v1.3