From 465b85eb760bfdb114f6b6ebccf374aba3977929 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 17 Sep 2025 21:04:56 +0000 Subject: [PATCH] runtime: fix CheckScavengedBitsCleared with randomized heap base We cannot easily determine the base address of the arena we added the random padding pages to, which can cause confusing TestScavengedBitsCleared failures when the arena we padded does not have the lowest address of all of the arenas. Instead of attempting to determine the correct arena to ignore when checking the scav and alloc bits, switch to just tolerating _one_ arena having mismatches, which is expected when randomizedHeapBase64 is enabled. Any other number of arenas having mismatches is likely a real error. Fixes #75502 Change-Id: Iacc445b2905824f9f71970c7abd33f187793cf39 Reviewed-on: https://go-review.googlesource.com/c/go/+/704855 Reviewed-by: Michael Knyszek Auto-Submit: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- src/runtime/export_test.go | 41 ++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 1f55717f0a..99c665c6d0 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -1122,8 +1122,6 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) { // Lock so that we can safely access the bitmap. lock(&mheap_.lock) - heapBase := mheap_.pages.inUse.ranges[0].base.addr() - secondArenaBase := arenaBase(arenaIndex(heapBase) + 1) chunkLoop: for i := mheap_.pages.start; i < mheap_.pages.end; i++ { chunk := mheap_.pages.tryChunkOf(i) @@ -1140,14 +1138,6 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) { want := chunk.scavenged[j] &^ chunk.pallocBits[j] got := chunk.scavenged[j] if want != got { - // When goexperiment.RandomizedHeapBase64 is set we use a - // series of padding pages to generate randomized heap base - // address which have both the alloc and scav bits set. If - // we see this for a chunk between the address of the heap - // base, and the address of the second arena continue. - if goexperiment.RandomizedHeapBase64 && (cb >= heapBase && cb < secondArenaBase) { - continue - } ok = false if n >= len(mismatches) { break chunkLoop @@ -1165,6 +1155,37 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) { getg().m.mallocing-- }) + + if goexperiment.RandomizedHeapBase64 && len(mismatches) > 0 { + // When goexperiment.RandomizedHeapBase64 is set we use a series of + // padding pages to generate randomized heap base address which have + // both the alloc and scav bits set. Because of this we expect exactly + // one arena will have mismatches, so check for that explicitly and + // remove the mismatches if that property holds. If we see more than one + // arena with this property, that is an indication something has + // actually gone wrong, so return the mismatches. + // + // We do this, instead of ignoring the mismatches in the chunkLoop, because + // it's not easy to determine which arena we added the padding pages to + // programmatically, without explicitly recording the base address somewhere + // in a global variable (which we'd rather not do as the address of that variable + // is likely to be somewhat predictable, potentially defeating the purpose + // of our randomization). + affectedArenas := map[arenaIdx]bool{} + for _, mismatch := range mismatches { + if mismatch.Base > 0 { + affectedArenas[arenaIndex(mismatch.Base)] = true + } + } + if len(affectedArenas) == 1 { + ok = true + // zero the mismatches + for i := range n { + mismatches[i] = BitsMismatch{} + } + } + } + return } -- 2.52.0