Skip to content

DWARF: break recursive type cycles in DI generation #2116

Description

@cpunion

Summary

LLGo's existing DWARF generator recursively expands named pointer/typedef cycles until the host Go process overflows its stack. This becomes a broad native-build blocker whenever DWARF is enabled by default.

This was found while validating #2112 and must be fixed in a dedicated DWARF PR rather than in the pclntab packaging implementation.

Reproduction

Host: Darwin/arm64, Go 1.24.11, LLVM 19.

go test ./test/go -run '^TestRecursivePointerTypeBuilds$' -count=1 -v

The standalone probe contains recursive named pointer types such as:

type Link *Link
type Peano *Peano

The same failure class appeared in the default-DWARF CI run https://github.com/xgo-dev/llgo/actions/runs/29549966202 while compiling the standard recursive named-type case:

type recursiveNamedT18 *[10]recursiveNamedT19
type recursiveNamedT19 recursiveNamedT18

The host compiler repeatedly enters the aDIBuilder type-construction path and ends in a Go stack overflow. Both programs build and run when DWARF is omitted (-ldflags=-w).

Analysis

ssa/di.go currently checks b.types[t], calls createType, and only stores the returned DI node after createType finishes. A cycle such as named typedef → pointer/array → named typedef therefore re-enters diTypeEx before the first node is cached. This is a pclntab-independent DI construction bug; runtime line lookup is never reached.

The fix needs an in-progress placeholder/replaceable composite node inserted into the cache before descending. It should then complete or replace that node after members, pointees, and typedef underlyings are resolved. Merely adding the type to a visited set would avoid the stack overflow but leave references without valid DI metadata.

Expected behavior

DI type construction should memoize a placeholder before descending through recursive members/pointees, then complete the node after its dependencies are visited. Recursive legal Go types must never crash the compiler.

The eventual fix should add direct tests for:

  • named pointer cycles (Link, Peano);
  • the T18/T19 named pointer-array/typedef cycle;
  • mutually recursive aggregate types;
  • repeated references to an in-progress DI node.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggo-compatCompatibility with Go commands, flags, and toolchain behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions