mirror of
https://github.com/golang/go
synced 2024-11-11 12:49:30 +00:00
8dfb447231
Fix two defer bugs related to adding/removing open defer entries. The bugs relate to the way that we add and remove open defer entries from the defer chain. At the point of a panic, when we want to start processing defer entries in order during the panic process, we need to add entries to the defer chain for stack frames with open defers, since the normal fast-defer code does not add these entries. We do this by calling addOneOpenDeferFrame() at the beginning of each time around the defer loop in gopanic(). Those defer entries get sorted with other open and non-open-coded defer frames. However, the tricky part is that we also need to remove defer entries if they end not being needed because of a recover (which means we are back to executing the defer code inline at function exits). But we need to deal with multiple panics and in-process defers on the stack, so we can't just remove all open-coded defers from the the defer chain during a recover. The fix (and new invariant) is that we should not add any open-coded defers to the defer chain that are higher up the stack than an open-coded defer that is in progress. We know that open-coded defer will still be run until completed, and when it is completed, then a more outer frame will be added (if there is one). This fits with existing code in gopanic that only removes open-coded defer entries up to any defer in progress. These bugs were because of the previous inconsistency between adding and removing open defer entries, which meant that stale defer entries could be left on the list, in these unusual cases with both recursive panics plus multiple independent (non-nested) cases of panic & recover. The test for #48898 was difficult to add to defer_test.go (while keeping the failure mode), so I added as a go/test/fixedbug test instead. Fixes #43920 Updates #43941 Fixes #48898 Change-Id: I593b77033e08c33094315abf8089fbc4cab07376 Reviewed-on: https://go-review.googlesource.com/c/go/+/356011 Trust: Dan Scales <danscales@google.com> Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Austin Clements <austin@google.com>
41 lines
666 B
Go
41 lines
666 B
Go
// run
|
|
|
|
// Copyright 2021 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
func main() {
|
|
defer func() {
|
|
println(recover().(int))
|
|
}()
|
|
func() {
|
|
func() (_ [2]int) { type _ int; return }()
|
|
func() {
|
|
defer func() {
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
defer panic(3)
|
|
panic(2)
|
|
}()
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
panic(1)
|
|
}()
|
|
defer func() {}()
|
|
}()
|
|
|
|
var x = 123
|
|
func() {
|
|
// in the original issue, this defer was not executed (which is incorrect)
|
|
defer print(x)
|
|
func() {
|
|
defer func() {}()
|
|
panic(4)
|
|
}()
|
|
}()
|
|
}
|