mirror of
https://github.com/golang/go
synced 2024-11-26 08:27:56 -07:00
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>
This commit is contained in:
parent
0fa2302ee5
commit
a63cded5e4
@ -292,11 +292,35 @@ func (d *Data) Type(off Offset) (Type, error) {
|
|||||||
return d.readType("info", d.Reader(), off, d.typeCache, nil)
|
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
|
// 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
|
// type cache, appends new typedef types to typedefs, and computes the
|
||||||
// sizes of types. Callers should pass nil for typedefs; this is used
|
// sizes of types. Callers should pass nil for typedefs; this is used
|
||||||
// for internal recursion.
|
// 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 {
|
if t, ok := typeCache[off]; ok {
|
||||||
return t, nil
|
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
|
// If this is the root of the recursion, prepare to resolve
|
||||||
// typedef sizes once the recursion is done. This must be done
|
// typedef sizes and perform other fixups once the recursion is
|
||||||
// after the type graph is constructed because it may need to
|
// done. This must be done after the type graph is constructed
|
||||||
// resolve cycles in a different order than readType
|
// because it may need to resolve cycles in a different order than
|
||||||
// encounters them.
|
// readType encounters them.
|
||||||
if typedefs == nil {
|
if fixups == nil {
|
||||||
var typedefList []*TypedefType
|
var fixer typeFixer
|
||||||
defer func() {
|
defer func() {
|
||||||
for _, t := range typedefList {
|
fixer.apply()
|
||||||
t.Common().ByteSize = t.Type.Size()
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
typedefs = &typedefList
|
fixups = &fixer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse type from Entry.
|
// Parse type from Entry.
|
||||||
@ -376,7 +398,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
|
|||||||
var t Type
|
var t Type
|
||||||
switch toff := tval.(type) {
|
switch toff := tval.(type) {
|
||||||
case Offset:
|
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
|
return nil
|
||||||
}
|
}
|
||||||
case uint64:
|
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" {
|
if bito == lastFieldBitOffset && t.Kind != "union" {
|
||||||
// Last field was zero width. Fix array length.
|
// Last field was zero width. Fix array length.
|
||||||
// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
|
// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
|
||||||
zeroArray(lastFieldType)
|
fixups.recordArrayType(lastFieldType)
|
||||||
}
|
}
|
||||||
lastFieldType = &f.Type
|
lastFieldType = &f.Type
|
||||||
lastFieldBitOffset = bito
|
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)
|
b, ok := e.Val(AttrByteSize).(int64)
|
||||||
if ok && b*8 == lastFieldBitOffset {
|
if ok && b*8 == lastFieldBitOffset {
|
||||||
// Final field must be zero width. Fix array length.
|
// 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
|
// Record that we need to resolve this
|
||||||
// type's size once the type graph is
|
// type's size once the type graph is
|
||||||
// constructed.
|
// constructed.
|
||||||
*typedefs = append(*typedefs, t)
|
fixups.typedefs = append(fixups.typedefs, t)
|
||||||
case *PtrType:
|
case *PtrType:
|
||||||
b = int64(addressSize)
|
b = int64(addressSize)
|
||||||
}
|
}
|
||||||
@ -737,11 +759,8 @@ Error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func zeroArray(t *Type) {
|
func zeroArray(t *Type) {
|
||||||
if t == nil {
|
at := (*t).(*ArrayType)
|
||||||
return
|
if at.Type.Size() == 0 {
|
||||||
}
|
|
||||||
at, ok := (*t).(*ArrayType)
|
|
||||||
if !ok || at.Type.Size() == 0 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Make a copy to avoid invalidating typeCache.
|
// Make a copy to avoid invalidating typeCache.
|
||||||
|
Loading…
Reference in New Issue
Block a user