From: Michael Anthony Knyszek Date: Tue, 20 May 2025 20:26:56 +0000 (+0000) Subject: runtime: guarantee checkfinalizers test allocates in a shared tiny block X-Git-Tag: go1.25rc1~157 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8b45a3f78b178ce66f419038a664cbd6a82ada54;p=gostls13.git runtime: guarantee checkfinalizers test allocates in a shared tiny block Currently the checkfinalizers test (TestDetectCleanupOrFinalizerLeak) only *tries* to ensure the tiny alloc with a cleanup attached shares a block with other objects. However, what it does is insufficient, because it could get unlucky and have the last object allocated be the first object of a new block. This change changes the test to guarantee that a tiny object is not at the start of a fresh block by looking at the alignment of the object's pointer. If the object's pointer is odd, then that's good enough to know that it shares a block with something else, since the blocks themselves are aligned to a much higher power of two. This fixes a failure I've seen on the builders. Fixes #73810. Change-Id: Ieafdbb9cccb0d2dc3659a9a5d9d9233718461635 Reviewed-on: https://go-review.googlesource.com/c/go/+/674655 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 25caf0625b..abd94fda08 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -1672,7 +1672,10 @@ func postMallocgcDebug(x unsafe.Pointer, elemsize uintptr, typ *_type) { } // N.B. elemsize == 0 indicates a tiny allocation, since no new slot was - // allocated to fulfill this call to mallocgc. + // allocated to fulfill this call to mallocgc. This means checkfinalizer + // will only flag an error if there is actually any risk. If an allocation + // has the tiny block to itself, it will not get flagged, because we won't + // mark the block as a tiny block. if debug.checkfinalizers != 0 && elemsize == 0 { setTinyBlockContext(unsafe.Pointer(alignDown(uintptr(x), maxTinySize))) } diff --git a/src/runtime/testdata/testprog/checkfinalizers.go b/src/runtime/testdata/testprog/checkfinalizers.go index b542f575fe..a2fe104462 100644 --- a/src/runtime/testdata/testprog/checkfinalizers.go +++ b/src/runtime/testdata/testprog/checkfinalizers.go @@ -7,6 +7,7 @@ package main import ( "runtime" "runtime/debug" + "unsafe" ) func init() { @@ -40,10 +41,16 @@ func DetectFinalizerAndCleanupLeaks() { // Ensure we create an allocation into a tiny block that shares space among several values. var ctLeak *tiny - for i := 0; i < 18; i++ { + for { tinySink = ctLeak ctLeak = new(tiny) - *ctLeak = tiny(i) + *ctLeak = tiny(55) + // Make sure the address is an odd value. This is sufficient to + // be certain that we're sharing a block with another value and + // trip the detector. + if uintptr(unsafe.Pointer(ctLeak))%2 != 0 { + break + } } runtime.AddCleanup(ctLeak, func(_ struct{}) {}, struct{}{})