]> Cypherpunks repositories - gostls13.git/commitdiff
debug/dwarf: delay array type fixup to handle type cycles
authorThan McIntosh <thanm@google.com>
Wed, 12 May 2021 15:03:48 +0000 (11:03 -0400)
committerThan McIntosh <thanm@google.com>
Thu, 13 May 2021 12:32:21 +0000 (12:32 +0000)
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>

src/debug/dwarf/type.go

index 316db258f654412406a63153411bfd6253298fd3..eb5a666ed38d3bcaf1cc42a0b54c5e28ef63453a 100644 (file)
@@ -292,11 +292,35 @@ func (d *Data) Type(off Offset) (Type, error) {
        return d.readType("info", d.Reader(), off, d.typeCache, nil)
 }
 
+type typeFixer struct {
+       typedefs   []*TypedefType
+       arraytypes []*Type
+}
+
+func (tf *typeFixer) recordArrayType(t *Type) {
+       if t == nil {
+               return
+       }
+       _, ok := (*t).(*ArrayType)
+       if ok {
+               tf.arraytypes = append(tf.arraytypes, t)
+       }
+}
+
+func (tf *typeFixer) apply() {
+       for _, t := range tf.typedefs {
+               t.Common().ByteSize = t.Type.Size()
+       }
+       for _, t := range tf.arraytypes {
+               zeroArray(t)
+       }
+}
+
 // readType reads a type from r at off of name. It adds types to the
 // type cache, appends new typedef types to typedefs, and computes the
 // sizes of types. Callers should pass nil for typedefs; this is used
 // for internal recursion.
-func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, typedefs *[]*TypedefType) (Type, error) {
+func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, fixups *typeFixer) (Type, error) {
        if t, ok := typeCache[off]; ok {
                return t, nil
        }
@@ -311,18 +335,16 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
        }
 
        // If this is the root of the recursion, prepare to resolve
-       // typedef sizes once the recursion is done. This must be done
-       // after the type graph is constructed because it may need to
-       // resolve cycles in a different order than readType
-       // encounters them.
-       if typedefs == nil {
-               var typedefList []*TypedefType
+       // typedef sizes and perform other fixups once the recursion is
+       // done. This must be done after the type graph is constructed
+       // because it may need to resolve cycles in a different order than
+       // readType encounters them.
+       if fixups == nil {
+               var fixer typeFixer
                defer func() {
-                       for _, t := range typedefList {
-                               t.Common().ByteSize = t.Type.Size()
-                       }
+                       fixer.apply()
                }()
-               typedefs = &typedefList
+               fixups = &fixer
        }
 
        // Parse type from Entry.
@@ -376,7 +398,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                var t Type
                switch toff := tval.(type) {
                case Offset:
-                       if t, err = d.readType(name, r.clone(), toff, typeCache, typedefs); err != nil {
+                       if t, err = d.readType(name, r.clone(), toff, typeCache, fixups); err != nil {
                                return nil
                        }
                case uint64:
@@ -567,7 +589,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                        if bito == lastFieldBitOffset && t.Kind != "union" {
                                // Last field was zero width. Fix array length.
                                // (DWARF writes out 0-length arrays as if they were 1-length arrays.)
-                               zeroArray(lastFieldType)
+                               fixups.recordArrayType(lastFieldType)
                        }
                        lastFieldType = &f.Type
                        lastFieldBitOffset = bito
@@ -576,7 +598,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                        b, ok := e.Val(AttrByteSize).(int64)
                        if ok && b*8 == lastFieldBitOffset {
                                // Final field must be zero width. Fix array length.
-                               zeroArray(lastFieldType)
+                               fixups.recordArrayType(lastFieldType)
                        }
                }
 
@@ -719,7 +741,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                                // Record that we need to resolve this
                                // type's size once the type graph is
                                // constructed.
-                               *typedefs = append(*typedefs, t)
+                               fixups.typedefs = append(fixups.typedefs, t)
                        case *PtrType:
                                b = int64(addressSize)
                        }
@@ -737,11 +759,8 @@ Error:
 }
 
 func zeroArray(t *Type) {
-       if t == nil {
-               return
-       }
-       at, ok := (*t).(*ArrayType)
-       if !ok || at.Type.Size() == 0 {
+       at := (*t).(*ArrayType)
+       if at.Type.Size() == 0 {
                return
        }
        // Make a copy to avoid invalidating typeCache.