Skip to content

Panic recovery + defer inside defer + a blocking call causes incorrect execution resumption. #1083

@nevkontakte

Description

@nevkontakte

Reproduction example:

package main

func noop() {}

var block = make(chan bool)

func recoverAndBlock() {
	defer noop()
	err := recover()
	println("recovered:", err)
	block <- true
	println("unblocked")
}

func handle() {
	defer noop()

	panic("expected panic")
}

func serve() {
	defer recoverAndBlock()
	handle()
	panic("this line must never execute")
}

func main() {
	go func() {
		println("awaiting cookie")
		<-block
		println("got cookie")
	}()

	serve()
}

Under GopherJS panic("this line must never execute") gets executed despite the fact panic recovery happens in the deferred function of serve(). The exact sequence of events is hard to summarize, but in short the first panic() runs deferred function and eventually recovers. However, because recoverAndBlock() defers another function, GopherJS runtime incorrectly determines call stack level where panic got recovered and continues execution of serve().

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions