Skip to content

Commit

Permalink
gocore: skip nil largeType when discovering pointers
Browse files Browse the repository at this point in the history
If a core is taken while a goroutine is allocating a large object (which
is more likely than smaller objects, because zeroing is delayed and
takes longer than for smaller objects) gocore might observe a nil
largeType in the span, which is left nil to prevent the GC from trying
to scan the partially-initialized object.

Fixes golang/go#71182.

Change-Id: Iafa7aed29466dc8ad6eac8f10171885421e10f76
Reviewed-on: https://go-review.googlesource.com/c/debug/+/641515
Reviewed-by: Nicolas Hillegeer <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
  • Loading branch information
mknyszek committed Jan 10, 2025
1 parent b341049 commit bb5bb24
Showing 1 changed file with 18 additions and 10 deletions.
28 changes: 18 additions & 10 deletions internal/gocore/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ func readHeap0(p *Process, mheap region, arenas []arena, arenaBaseOffset int64)
continue
}
typeAddr := p.proc.ReadPtr(min.Add(off))
// Note: typeAddr might be nil if the core was taken while a goroutine was
// actively allocating a large object.
if typeAddr == 0 {
continue
}
Expand All @@ -522,16 +524,22 @@ func readHeap0(p *Process, mheap region, arenas []arena, arenaBaseOffset int64)
// is not valid if the object is dead. However, because large objects are
// 1:1 with spans, we can be certain largeType is valid as long as the span
// is in use.
typ := s.Field("largeType").Deref()
nptrs := int64(typ.Field("PtrBytes").Uintptr()) / int64(heap.ptrSize)
kindGCProg, hasGCProgs := p.rtConsts.find("internal/abi.KindGCProg")
if hasGCProgs && typ.Field("Kind_").Uint8()&uint8(kindGCProg) != 0 {
panic("large object's GCProg was not unrolled")
}
gcdata := typ.Field("GCData").Address()
for i := int64(0); i < nptrs; i++ {
if p.proc.ReadUint8(gcdata.Add(i/8))>>uint(i%8)&1 != 0 {
heap.setIsPointer(min.Add(i * int64(heap.ptrSize)))
//
// Note: largeType might be nil if the core was taken while a goroutine was
// actively allocating a large object.
typPtr := s.Field("largeType")
if typPtr.Address() != 0 {
typ := typPtr.Deref()
nptrs := int64(typ.Field("PtrBytes").Uintptr()) / int64(heap.ptrSize)
kindGCProg, hasGCProgs := p.rtConsts.find("internal/abi.KindGCProg")
if hasGCProgs && typ.Field("Kind_").Uint8()&uint8(kindGCProg) != 0 {
panic("large object's GCProg was not unrolled")
}
gcdata := typ.Field("GCData").Address()
for i := int64(0); i < nptrs; i++ {
if p.proc.ReadUint8(gcdata.Add(i/8))>>uint(i%8)&1 != 0 {
heap.setIsPointer(min.Add(i * int64(heap.ptrSize)))
}
}
}
}
Expand Down

0 comments on commit bb5bb24

Please sign in to comment.