Skip to content

Commit 3b364d9

Browse files
mknyszekdmitshur
authored andcommitted
[release-branch.go1.14] 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. For #41296. Fixes #41322. 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]> (cherry picked from commit 34835df) Reviewed-on: https://go-review.googlesource.com/c/go/+/253922 Run-TryBot: Dmitri Shuralyov <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent 77029b7 commit 3b364d9

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

src/runtime/export_test.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,11 @@ func ReadMemStatsSlow() (base, slow MemStats) {
360360
}
361361

362362
for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
363-
pg := mheap_.pages.chunkOf(i).scavenged.popcntRange(0, pallocChunkPages)
363+
chunk := mheap_.pages.tryChunkOf(i)
364+
if chunk == nil {
365+
continue
366+
}
367+
pg := chunk.scavenged.popcntRange(0, pallocChunkPages)
364368
slow.HeapReleased += uint64(pg) * pageSize
365369
}
366370
for _, p := range allp {
@@ -753,11 +757,7 @@ func (p *PageAlloc) InUse() []AddrRange {
753757
// Returns nil if the PallocData's L2 is missing.
754758
func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData {
755759
ci := chunkIdx(i)
756-
l2 := (*pageAlloc)(p).chunks[ci.l1()]
757-
if l2 == nil {
758-
return nil
759-
}
760-
return (*PallocData)(&l2[ci.l2()])
760+
return (*PallocData)((*pageAlloc)(p).tryChunkOf(ci))
761761
}
762762

763763
// AddrRange represents a range over addresses.
@@ -896,7 +896,10 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) {
896896
lock(&mheap_.lock)
897897
chunkLoop:
898898
for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
899-
chunk := mheap_.pages.chunkOf(i)
899+
chunk := mheap_.pages.tryChunkOf(i)
900+
if chunk == nil {
901+
continue
902+
}
900903
for j := 0; j < pallocChunkPages/64; j++ {
901904
// Run over each 64-bit bitmap section and ensure
902905
// scavenged is being cleared properly on allocation.

src/runtime/mpagealloc.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,20 @@ func (s *pageAlloc) compareSearchAddrTo(addr uintptr) int {
331331
return 0
332332
}
333333

334+
// tryChunkOf returns the bitmap data for the given chunk.
335+
//
336+
// Returns nil if the chunk data has not been mapped.
337+
func (s *pageAlloc) tryChunkOf(ci chunkIdx) *pallocData {
338+
l2 := s.chunks[ci.l1()]
339+
if l2 == nil {
340+
return nil
341+
}
342+
return &l2[ci.l2()]
343+
}
344+
334345
// chunkOf returns the chunk at the given chunk index.
346+
//
347+
// The chunk index must be valid or this method may throw.
335348
func (s *pageAlloc) chunkOf(ci chunkIdx) *pallocData {
336349
return &s.chunks[ci.l1()][ci.l2()]
337350
}

0 commit comments

Comments
 (0)