mirror of
https://github.com/golang/go.git
synced 2025-10-19 19:13:18 +00:00
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 <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
8960970009
commit
8b45a3f78b
2 changed files with 13 additions and 3 deletions
|
@ -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
|
// 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 {
|
if debug.checkfinalizers != 0 && elemsize == 0 {
|
||||||
setTinyBlockContext(unsafe.Pointer(alignDown(uintptr(x), maxTinySize)))
|
setTinyBlockContext(unsafe.Pointer(alignDown(uintptr(x), maxTinySize)))
|
||||||
}
|
}
|
||||||
|
|
11
src/runtime/testdata/testprog/checkfinalizers.go
vendored
11
src/runtime/testdata/testprog/checkfinalizers.go
vendored
|
@ -7,6 +7,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -40,10 +41,16 @@ func DetectFinalizerAndCleanupLeaks() {
|
||||||
|
|
||||||
// Ensure we create an allocation into a tiny block that shares space among several values.
|
// Ensure we create an allocation into a tiny block that shares space among several values.
|
||||||
var ctLeak *tiny
|
var ctLeak *tiny
|
||||||
for i := 0; i < 18; i++ {
|
for {
|
||||||
tinySink = ctLeak
|
tinySink = ctLeak
|
||||||
ctLeak = new(tiny)
|
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{}{})
|
runtime.AddCleanup(ctLeak, func(_ struct{}) {}, struct{}{})
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue