Skip to content

Commit 34835df

Browse files
committed
runtime: fix ReadMemStatsSlow's and CheckScavengedBits' chunk iteration
Both ReadMemStatsSlow and CheckScavengedBits iterate over the page allocator's chunks but don't actually check if they exist. During the development process the chunks index became sparse, so now this was a possibility. If the runtime tests' heap is sparse we might end up segfaulting in either one of these functions, though this will generally be very rare. The pattern here to return nil for a nonexistent chunk is also useful elsewhere, so this change introduces tryChunkOf which won't throw, but might return nil. It also updates the documentation of chunkOf. Fixes #41296. Change-Id: Id5ae0ca3234480de1724fdf2e3677eeedcf76fa0 Reviewed-on: https://go-review.googlesource.com/c/go/+/253777 Run-TryBot: Michael Knyszek <[email protected]> Reviewed-by: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 9ef3ee3 commit 34835df

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

src/runtime/export_test.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,11 @@ func ReadMemStatsSlow() (base, slow MemStats) {
358358
}
359359

360360
for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
361-
pg := mheap_.pages.chunkOf(i).scavenged.popcntRange(0, pallocChunkPages)
361+
chunk := mheap_.pages.tryChunkOf(i)
362+
if chunk == nil {
363+
continue
364+
}
365+
pg := chunk.scavenged.popcntRange(0, pallocChunkPages)
362366
slow.HeapReleased += uint64(pg) * pageSize
363367
}
364368
for _, p := range allp {
@@ -756,11 +760,7 @@ func (p *PageAlloc) InUse() []AddrRange {
756760
// Returns nil if the PallocData's L2 is missing.
757761
func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData {
758762
ci := chunkIdx(i)
759-
l2 := (*pageAlloc)(p).chunks[ci.l1()]
760-
if l2 == nil {
761-
return nil
762-
}
763-
return (*PallocData)(&l2[ci.l2()])
763+
return (*PallocData)((*pageAlloc)(p).tryChunkOf(ci))
764764
}
765765

766766
// AddrRange represents a range over addresses.
@@ -900,7 +900,10 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) {
900900
lock(&mheap_.lock)
901901
chunkLoop:
902902
for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
903-
chunk := mheap_.pages.chunkOf(i)
903+
chunk := mheap_.pages.tryChunkOf(i)
904+
if chunk == nil {
905+
continue
906+
}
904907
for j := 0; j < pallocChunkPages/64; j++ {
905908
// Run over each 64-bit bitmap section and ensure
906909
// scavenged is being cleared properly on allocation.

src/runtime/mpagealloc.go

+13
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,20 @@ func (s *pageAlloc) init(mheapLock *mutex, sysStat *uint64) {
326326
s.scav.scavLWM = maxSearchAddr
327327
}
328328

329+
// tryChunkOf returns the bitmap data for the given chunk.
330+
//
331+
// Returns nil if the chunk data has not been mapped.
332+
func (s *pageAlloc) tryChunkOf(ci chunkIdx) *pallocData {
333+
l2 := s.chunks[ci.l1()]
334+
if l2 == nil {
335+
return nil
336+
}
337+
return &l2[ci.l2()]
338+
}
339+
329340
// chunkOf returns the chunk at the given chunk index.
341+
//
342+
// The chunk index must be valid or this method may throw.
330343
func (s *pageAlloc) chunkOf(ci chunkIdx) *pallocData {
331344
return &s.chunks[ci.l1()][ci.l2()]
332345
}

0 commit comments

Comments
 (0)