aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/callers_test.go34
-rw-r--r--src/runtime/panic.go6
2 files changed, 37 insertions, 3 deletions
diff --git a/src/runtime/callers_test.go b/src/runtime/callers_test.go
index 3cd1b40ec9..302e33deeb 100644
--- a/src/runtime/callers_test.go
+++ b/src/runtime/callers_test.go
@@ -254,9 +254,8 @@ func TestCallersDivZeroPanic(t *testing.T) {
func TestCallersDeferNilFuncPanic(t *testing.T) {
// Make sure we don't have any extra frames on the stack. We cut off the check
// at runtime.sigpanic, because non-open-coded defers (which may be used in
- // non-opt or race checker mode) include an extra 'jmpdefer' frame (which is
- // where the nil pointer deref happens). We could consider hiding jmpdefer in
- // tracebacks.
+ // non-opt or race checker mode) include an extra 'deferreturn' frame (which is
+ // where the nil pointer deref happens).
state := 1
want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanic.func1",
"runtime.gopanic", "runtime.panicmem", "runtime.sigpanic"}
@@ -279,3 +278,32 @@ func TestCallersDeferNilFuncPanic(t *testing.T) {
// function exit, rather than at the defer statement.
state = 2
}
+
+// Same test, but forcing non-open-coded defer by putting the defer in a loop. See
+// issue #36050
+func TestCallersDeferNilFuncPanicWithLoop(t *testing.T) {
+ state := 1
+ want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanicWithLoop.func1",
+ "runtime.gopanic", "runtime.panicmem", "runtime.sigpanic", "runtime.deferreturn", "runtime_test.TestCallersDeferNilFuncPanicWithLoop"}
+
+ defer func() {
+ if r := recover(); r == nil {
+ t.Fatal("did not panic")
+ }
+ pcs := make([]uintptr, 20)
+ pcs = pcs[:runtime.Callers(0, pcs)]
+ testCallersEqual(t, pcs, want)
+ if state == 1 {
+ t.Fatal("nil defer func panicked at defer time rather than function exit time")
+ }
+
+ }()
+
+ for i := 0; i < 1; i++ {
+ var f func()
+ defer f()
+ }
+ // Use the value of 'state' to make sure nil defer func f causes panic at
+ // function exit, rather than at the defer statement.
+ state = 2
+}
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 0823f11e98..4cb6c8a360 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -561,6 +561,12 @@ func deferreturn(arg0 uintptr) {
d.fn = nil
gp._defer = d.link
freedefer(d)
+ // If the defer function pointer is nil, force the seg fault to happen
+ // here rather than in jmpdefer. gentraceback() throws an error if it is
+ // called with a callback on an LR architecture and jmpdefer is on the
+ // stack, because the stack trace can be incorrect in that case - see
+ // issue #8153).
+ _ = fn.fn
jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
}