golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
121.48k stars 17.4k forks source link

x/tools/go/types/objectpath: stack overflow trying to find inaccessible object in package with recursive interface #68046

Open adonovan opened 1 month ago

adonovan commented 1 month ago

This stack wgsP2A was reported by telemetry:

crash/crash
golang.org/x/tools/go/types/objectpath.find:+0
golang.org/x/tools/go/types/objectpath.find:+23
golang.org/x/tools/go/types/objectpath.find:+58
golang.org/x/tools/go/types/objectpath.find:+46
golang.org/x/tools/go/types/objectpath.find:+26
golang.org/x/tools/go/types/objectpath.find:+58
golang.org/x/tools/go/types/objectpath.find:+46
golang.org/x/tools/go/types/objectpath.find:+26
golang.org/x/tools/go/types/objectpath.find:+58
golang.org/x/tools/go/types/objectpath.find:+46
golang.org/x/tools/go/types/objectpath.find:+26
golang.org/x/tools/go/types/objectpath.find:+58
golang.org/x/tools/go/types/objectpath.find:+46
golang.org/x/tools/go/types/objectpath.find:+26
golang.org/x/tools/go/types/objectpath.find:+58
golang.org/x/tools/go/types/objectpath.find:+46
golang.org/x/tools/gopls@v0.15.3 devel darwin/amd64 vscode (9)

Issue created by golang.org/x/tools/gopls/internal/telemetry/cmd/stacks.

gabyhelp commented 1 month ago

Similar Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

adonovan commented 1 month ago

Translating these line numbers into source, this is the recursion:

golang.org/x/tools/go/types/objectpath.find:+23  Signature.Params
...
golang.org/x/tools/go/types/objectpath.find:+58  Interface.Method
golang.org/x/tools/go/types/objectpath.find:+46  Tuple.At
golang.org/x/tools/go/types/objectpath.find:+26  Signature.Results
...

So it looks an interface method whose result is (or embeds) the same interface, e.g. type I interface{ f() I }.

[Update: my first draft was wrong because the lines had moved since gopls/v0.15.3]

adonovan commented 1 month ago

I can reproduce the crash by fruitlessly trying to search for an inaccessible dummy object (a types.Var) within a package that contains this recursive interface type:

type Issue68046 interface { f() interface{Issue68046} }

Here's the diff:

diff --git a/go/types/objectpath/objectpath_test.go b/go/types/objectpath/objectpath_test.go
index 238ebb20c8..d20ff4c7ae 100644
--- a/go/types/objectpath/objectpath_test.go
+++ b/go/types/objectpath/objectpath_test.go
@@ -60,6 +60,8 @@ type Int int

 type T struct{x, y int}

+type Issue68046 interface { f() interface{Issue68046} }
+
 `},
        }
        paths := []pathTest{
@@ -131,6 +133,9 @@ type T struct{x, y int}
                }
        }

+       dummy := types.NewVar(token.NoPos, prog.Imported["a"].Pkg, "dummy", types.Typ[types.String])
+       objectpath.For(dummy)
+
        // bad objects
        bInfo := prog.Imported["b"]
        for _, test := range []struct {

and here's the crash:

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0x14020170450 stack=[0x14020170000, 0x14040170000]
fatal error: stack overflow

runtime stack:
runtime.throw({0x104b472e7?, 0x0?})
    /Users/adonovan/w/goroot/src/runtime/panic.go:1067 +0x38 fp=0x16b616d90 sp=0x16b616d60 pc=0x104969a48
runtime.newstack()
    /Users/adonovan/w/goroot/src/runtime/stack.go:1117 +0x460 fp=0x16b616ed0 sp=0x16b616d90 pc=0x10494dac0
runtime.morestack()
    /Users/adonovan/w/goroot/src/runtime/asm_arm64.s:342 +0x70 fp=0x16b616ed0 sp=0x16b616ed0 pc=0x10496f9e0

goroutine 3 gp=0x14000002fc0 m=2 mp=0x14000054808 [running]:
go/types.computeInterfaceTypeSet(0x0, 0x0?, 0x14000096370)
    /Users/adonovan/w/goroot/src/go/types/typeset.go:156 +0x914 fp=0x14020170450 sp=0x14020170450 pc=0x104ac8264
go/types.(*Interface).typeSet(...)
    /Users/adonovan/w/goroot/src/go/types/interface.go:29
go/types.(*Interface).NumMethods(...)
    /Users/adonovan/w/goroot/src/go/types/interface.go:113
golang.org/x/tools/go/types/objectpath.find({0x104c2c778, 0x140000943c0}, {0x104c28740?, 0x14000096370}, {0x14000e28000, 0x232313, 0x2a0000}, 0x0)
    /Users/adonovan/w/xtools/go/types/objectpath/objectpath.go:497 +0x788 fp=0x14020170670 sp=0x14020170450 pc=0x104adcce8
golang.org/x/tools/go/types/objectpath.find({0x104c2c778, 0x140000943c0}, {0x104c286a0?, 0x140000a40c0}, {0x14000e28000, 0x232310, 0x2a0000}, 0x0)
    /Users/adonovan/w/xtools/go/types/objectpath/objectpath.go:491 +0xc28 fp=0x14020170890 sp=0x14020170670 pc=0x104add188
golang.org/x/tools/go/types/objectpath.find({0x104c2c778, 0x140000943c0}, {0x104c28678?, 0x140000a6400}, {0x14000e28000, 0x23230f, 0x2a0000}, 0x0)
    /Users/adonovan/w/xtools/go/types/objectpath/objectpath.go:471 +0x6d0 fp=0x14020170ab0 sp=0x14020170890 pc=0x104adcc30
golang.org/x/tools/go/types/objectpath.find({0x104c2c778, 0x140000943c0}, {0x104c28740?, 0x14000096370}, {0x14000e28000, 0x23230c, 0x2a0000}, 0x0)
    /Users/adonovan/w/xtools/go/types/objectpath/objectpath.go:503 +0x8d8 fp=0x14020170cd0 sp=0x14020170ab0 pc=0x104adce38
golang.org/x/tools/go/types/objectpath.find({0x104c2c778, 0x140000943c0}, {0x104c286a0?, 0x140000a40c0}, {0x14000e28000, 0x232309, 0x2a0000}, 0x0)
    /Users/adonovan/w/xtools/go/types/objectpath/objectpath.go:491 +0xc28 fp=0x14020170ef0 sp=0x14020170cd0 pc=0x104add188
golang.org/x/tools/go/types/objectpath.find({0x104c2c778, 0x140000943c0}, {0x104c28678?, 0x140000a6400}, {0x14000e28000, 0x232308, 0x2a0000}, 0x0)
    /Users/adonovan/w/xtools/go/types/objectpath/objectpath.go:471 +0x6d0 fp=0x14020171110 sp=0x14020170ef0 pc=0x104adcc30
golang.org/x/tools/go/types/objectpath.find({0x104c2c778, 0x140000943c0}, {0x104c28740?, 0x14000096370}, {0x14000e28000, 0x232305, 0x2a0000}, 0x0)
    /Users/adonovan/w/xtools/go/types/objectpath/objectpath.go:503 +0x8d8 fp=0x14020171330 sp=0x14020171110 pc=0x104adce38
...