gocore: skip nil largeType when discovering pointers

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 <aktau@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/internal/gocore/process.go b/internal/gocore/process.go
index 74e71c0..926dc4b 100644
--- a/internal/gocore/process.go
+++ b/internal/gocore/process.go
@@ -499,6 +499,8 @@
 						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
 					}
@@ -522,16 +524,22 @@
 				// 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)))
+						}
 					}
 				}
 			}