#!stacks
"runtime.gopanic" &&
"types.(*Checker).handleBailout:+7" &&
 /* unfortunately there is no way to express bailout-within-bailout
     so we must subtract all other patterns that use bailout */
 !("go/types.setDefType:+7") // #71029

Issue created by stacks.

Well this is a weird one. Checker.Files. defers a function to recover from certain expected panics; that function re-panics for all other cases. However, the re-panic causes the deferred function to execute a second time (!). Presumably this means the defer bookkeeping (e.g. *_panic.deferBitsPtr) has become corrupted.

func (check *Checker) handleBailout(err *error) {
    switch p := recover().(type) {
    case nil, bailout:
        // normal return or early exit
        *err = check.firstErr
    default:
        // re-panic
        panic(p) <-- causes deferred call to check.handleBailout to execute again!
    }
}

// Files checks the provided files as part of the checker's package.
func (check *Checker) Files(files []*ast.File) (err error) {
...
    defer check.handleBailout(&err) <-- this closure is called repeatedly
    check.checkFiles(files)
    return
}

This stack k7voyQ was reported by telemetry:

golang.org/x/tools/gopls@v0.18.1 go1.23.7 darwin/arm64 other (2)

Dups: 5qvnIw UFUvMw

Comment From: adonovan

cc: @golang/runtime

Comment From: gabyhelp

Related Issues

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

Comment From: adonovan

This stack PrtfKQ was reported by telemetry:

golang.org/x/tools/gopls@v0.18.1 go1.23.7 darwin/arm64 other (1)

Comment From: mknyszek

In triage, @randall77 notes that it looks like the defer isn't properly taken off of the defer list, so it gets run twice. But what's weird is the first time defer is called is as an open-coded defer, and we only create the defer record the second time.

Comment From: randall77

I looked into this for a while, nothing obvious. All the compiler-generated metadata looks good. There are various defer wrappers that complicate things, but nothing obviously wrong.

My only guess is that a stack copy happens at exactly the wrong time, causing defer selection to fail. But that would, I think, only cause defers to be missed, not duplicated. But who knows. We're probably going to need a reproducer to make more progress.

Comment From: adonovan

We're probably going to need a reproducer to make more progress.

I suspect this just another the of many varied symptoms of a single bug causing memory corruption; see label. Unfortunately we haven't been able to (knowingly) reproduce any of them even once.

Comment From: adonovan

This stack 5qvnIw was reported by telemetry:

golang.org/x/tools/gopls@v0.18.1 go1.23.8 darwin/arm64 vscode (1)

Comment From: adonovan

This stack UFUvMw was reported by telemetry:

golang.org/x/tools/gopls@v0.18.1 go1.24.1 linux/amd64 vscode (1)

Comment From: adonovan

That last stack has a different cause, though clearly yet more memory corruption.