Skip to content

debug/dwarf: readType can stack overflow on deeply nested type chains #77918

Description

@artahir-dev

Go version

go version go1.24.3 windows/amd64. Also verified present in tip (b5c2bd7) — src/debug/dwarf/type.go has had no depth-limit changes.

Output of go env in your module/workspace:

GOARCH="amd64"
GOOS="windows"
GOVERSION="go1.24.3"

What did you do?

Called (*dwarf.Data).Type() on a DWARF section containing a long linear chain of DW_TAG_typedef entries, each pointing to the next via DW_AT_type.

package main

import (
	"debug/dwarf"
	"encoding/binary"
	"fmt"
)

func main() {
	abbrev := []byte{
		0x01, 0x11, 0x01, 0x00, 0x00,
		0x02, 0x16, 0x00, 0x49, 0x13, 0x00, 0x00,
		0x03, 0x24, 0x00, 0x0b, 0x0b, 0x3e, 0x0b, 0x03, 0x08, 0x00, 0x00,
		0x00,
	}

	const depth = 1_000_000
	info := make([]byte, 0, 12+depth*5+8)
	var hdr [11]byte
	binary.LittleEndian.PutUint32(hdr[:4], uint32(16+depth*5))
	binary.LittleEndian.PutUint16(hdr[4:6], 2)
	hdr[10] = 4
	info = append(info, hdr[:]...)
	info = append(info, 0x01)
	for i := 0; i < depth; i++ {
		info = append(info, 0x02)
		var ref [4]byte
		if i < depth-1 {
			binary.LittleEndian.PutUint32(ref[:], uint32(12+(i+1)*5))
		} else {
			binary.LittleEndian.PutUint32(ref[:], uint32(12+depth*5))
		}
		info = append(info, ref[:]...)
	}
	info = append(info, 0x03, 4, 5, 'i', 'n', 't', 0, 0x00)

	d, _ := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, nil)
	_, err := d.Type(12)
	fmt.Println(err)
}

What did you see happen?

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc020ce1480 stack=[0xc020ce0000, 0xc040ce0000]
fatal error: stack overflow

goroutine 1 [running]:
debug/dwarf.(*Data).readType(...)
        .../debug/dwarf/type.go:412
debug/dwarf.(*Data).readType.func3(...)
        .../debug/dwarf/type.go:485
debug/dwarf.(*Data).readType(...)
        .../debug/dwarf/type.go:809
debug/dwarf.(*Data).readType.func3(...)
        .../debug/dwarf/type.go:485
... (repeating)

What did you expect to see?

An error returned, not a fatal crash. readType calls itself recursively through the typeOf closure (type.go:485) with no depth counter. The typeCache map only prevents revisiting the same offset, so it stops cycles but not linear chains of distinct offsets.

go/parser had the same issue fixed in #53616 by adding a nestLev counter. The same approach would work here — add a depth parameter to readType and return a DecodeError when it exceeds a reasonable limit (e.g. 1000).

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.compiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    Status
    Todo

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions