Skip to content

Commit a63cded

Browse files
committed
debug/dwarf: delay array type fixup to handle type cycles
A user encountered a debug/dwarf crash when running the dwarf2json tool (https://github.com/volatilityfoundation/dwarf2json) on a debug-built copy of the linux kernel. In this crash, the DWARF type reader was trying to examine the contents of an array type while that array type was still in the process of being constructed (due to cycles in the type graph). To avoid such situations, this patch extends the mechanism introduced in https://go-review.googlesource.com/18459 (which handles typedef types) to delay fixup of array types as well. Change-Id: I303f6ce5db1ca4bd79da3581957dfc2bfc17cc01 Reviewed-on: https://go-review.googlesource.com/c/go/+/319329 Trust: Than McIntosh <thanm@google.com> Run-TryBot: Than McIntosh <thanm@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Yi Chou <yich@google.com> TryBot-Result: Go Bot <gobot@golang.org>
1 parent 0fa2302 commit a63cded

File tree

1 file changed

+39
-20
lines changed

1 file changed

+39
-20
lines changed

src/debug/dwarf/type.go

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,35 @@ func (d *Data) Type(off Offset) (Type, error) {
292292
return d.readType("info", d.Reader(), off, d.typeCache, nil)
293293
}
294294

295+
type typeFixer struct {
296+
typedefs []*TypedefType
297+
arraytypes []*Type
298+
}
299+
300+
func (tf *typeFixer) recordArrayType(t *Type) {
301+
if t == nil {
302+
return
303+
}
304+
_, ok := (*t).(*ArrayType)
305+
if ok {
306+
tf.arraytypes = append(tf.arraytypes, t)
307+
}
308+
}
309+
310+
func (tf *typeFixer) apply() {
311+
for _, t := range tf.typedefs {
312+
t.Common().ByteSize = t.Type.Size()
313+
}
314+
for _, t := range tf.arraytypes {
315+
zeroArray(t)
316+
}
317+
}
318+
295319
// readType reads a type from r at off of name. It adds types to the
296320
// type cache, appends new typedef types to typedefs, and computes the
297321
// sizes of types. Callers should pass nil for typedefs; this is used
298322
// for internal recursion.
299-
func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, typedefs *[]*TypedefType) (Type, error) {
323+
func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, fixups *typeFixer) (Type, error) {
300324
if t, ok := typeCache[off]; ok {
301325
return t, nil
302326
}
@@ -311,18 +335,16 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
311335
}
312336

313337
// If this is the root of the recursion, prepare to resolve
314-
// typedef sizes once the recursion is done. This must be done
315-
// after the type graph is constructed because it may need to
316-
// resolve cycles in a different order than readType
317-
// encounters them.
318-
if typedefs == nil {
319-
var typedefList []*TypedefType
338+
// typedef sizes and perform other fixups once the recursion is
339+
// done. This must be done after the type graph is constructed
340+
// because it may need to resolve cycles in a different order than
341+
// readType encounters them.
342+
if fixups == nil {
343+
var fixer typeFixer
320344
defer func() {
321-
for _, t := range typedefList {
322-
t.Common().ByteSize = t.Type.Size()
323-
}
345+
fixer.apply()
324346
}()
325-
typedefs = &typedefList
347+
fixups = &fixer
326348
}
327349

328350
// Parse type from Entry.
@@ -376,7 +398,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
376398
var t Type
377399
switch toff := tval.(type) {
378400
case Offset:
379-
if t, err = d.readType(name, r.clone(), toff, typeCache, typedefs); err != nil {
401+
if t, err = d.readType(name, r.clone(), toff, typeCache, fixups); err != nil {
380402
return nil
381403
}
382404
case uint64:
@@ -567,7 +589,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
567589
if bito == lastFieldBitOffset && t.Kind != "union" {
568590
// Last field was zero width. Fix array length.
569591
// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
570-
zeroArray(lastFieldType)
592+
fixups.recordArrayType(lastFieldType)
571593
}
572594
lastFieldType = &f.Type
573595
lastFieldBitOffset = bito
@@ -576,7 +598,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
576598
b, ok := e.Val(AttrByteSize).(int64)
577599
if ok && b*8 == lastFieldBitOffset {
578600
// Final field must be zero width. Fix array length.
579-
zeroArray(lastFieldType)
601+
fixups.recordArrayType(lastFieldType)
580602
}
581603
}
582604

@@ -719,7 +741,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
719741
// Record that we need to resolve this
720742
// type's size once the type graph is
721743
// constructed.
722-
*typedefs = append(*typedefs, t)
744+
fixups.typedefs = append(fixups.typedefs, t)
723745
case *PtrType:
724746
b = int64(addressSize)
725747
}
@@ -737,11 +759,8 @@ Error:
737759
}
738760

739761
func zeroArray(t *Type) {
740-
if t == nil {
741-
return
742-
}
743-
at, ok := (*t).(*ArrayType)
744-
if !ok || at.Type.Size() == 0 {
762+
at := (*t).(*ArrayType)
763+
if at.Type.Size() == 0 {
745764
return
746765
}
747766
// Make a copy to avoid invalidating typeCache.

0 commit comments

Comments
 (0)