mirror of
https://github.com/golang/go
synced 2024-11-13 17:00:22 -07:00
7e97d39879
Deferred functions are not run by a call instruction. They are run by the runtime editing registers to make the call start with a caller PC returning to a CALL deferreturn instruction. That instruction has always had the line number of the function's closing brace, but that instruction's line number is irrelevant. Stack traces show the line number of the instruction before the return PC, because normally that's what started the call. Not so here. The instruction before the CALL deferreturn could be almost anywhere in the function; it's unrelated and its line number is incorrect to show. Fix the line number by inserting a true hardware no-op with the right line number before the returned-to CALL instruction. That is, the deferred calls now appear to start with a caller PC returning to the second instruction in this sequence: NOP CALL deferreturn The traceback will show the line number of the NOP, which we've set to be the line number of the function's closing brace. The NOP here is not the usual pseudo-instruction, which would be elided by the linker. Instead it is the real hardware instruction: XCHG AX, AX on 386 and amd64, and AND.EQ R0, R0, R0 on ARM. Fixes #5856. R=ken2, ken CC=golang-dev https://golang.org/cl/11223043
39 lines
587 B
Go
39 lines
587 B
Go
// run
|
|
|
|
// Copyright 2013 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
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
f()
|
|
panic("deferred function not run")
|
|
}
|
|
|
|
var x = 1
|
|
|
|
func f() {
|
|
if x == 0 {
|
|
return
|
|
}
|
|
defer g()
|
|
panic("panic")
|
|
}
|
|
|
|
func g() {
|
|
_, file, line, _ := runtime.Caller(2)
|
|
if !strings.HasSuffix(file, "issue5856.go") || line != 28 {
|
|
fmt.Printf("BUG: defer called from %s:%d, want issue5856.go:28\n", file, line)
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(0)
|
|
}
|