]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix CheckScavengedBitsCleared with randomized heap base
authorRoland Shoemaker <bracewell@google.com>
Wed, 17 Sep 2025 21:04:56 +0000 (21:04 +0000)
committerGopher Robot <gobot@golang.org>
Thu, 18 Sep 2025 00:10:11 +0000 (17:10 -0700)
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 <mknyszek@google.com>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/runtime/export_test.go

index 1f55717f0a1a6019f91245b56805fa9fc8d9744f..99c665c6d007e21bb1d592c007206a3ddcd3bf6f 100644 (file)
@@ -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
 }