Skip to content

Commit ee1aff7

Browse files
mknyszekclaucece
authored andcommitted
[release-branch.go1.15] 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 golang#41296. Fixes golang#41317. 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/+/253917
1 parent bf131b7 commit ee1aff7

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
@@ -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 {
@@ -758,11 +762,7 @@ func (p *PageAlloc) InUse() []AddrRange {
758762
// Returns nil if the PallocData's L2 is missing.
759763
func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData {
760764
ci := chunkIdx(i)
761-
l2 := (*pageAlloc)(p).chunks[ci.l1()]
762-
if l2 == nil {
763-
return nil
764-
}
765-
return (*PallocData)(&l2[ci.l2()])
765+
return (*PallocData)((*pageAlloc)(p).tryChunkOf(ci))
766766
}
767767

768768
// AddrRange represents a range over addresses.
@@ -902,7 +902,10 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) {
902902
lock(&mheap_.lock)
903903
chunkLoop:
904904
for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
905-
chunk := mheap_.pages.chunkOf(i)
905+
chunk := mheap_.pages.tryChunkOf(i)
906+
if chunk == nil {
907+
continue
908+
}
906909
for j := 0; j < pallocChunkPages/64; j++ {
907910
// Run over each 64-bit bitmap section and ensure
908911
// 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)