go 运行时:如果在panic期间以延迟函数调用者返回错误的文件和行 ```markdown 运行时:如果在panic期间以延迟函数调用者返回错误的文件和行 ```

xvw2m8pv  于 3个月前  发布在  Go
关注(0)|答案(6)|浏览(44)

你使用的Go版本是什么(go version)?

这个问题在最新版本中是否会重现?

b001ffb上测试过。

你做了什么?

https://play.golang.org/p/mqVHDikFu8D

你期望看到什么?

return: main.go:13
     panic: main.go:18

你看到了什么?

return: main.go:13
     panic: asm_amd64p32.s:459

这个bug是在讨论#26275时发现的。

oug3syen

oug3syen1#

Kindly paging @aclements@davidlazar

nwwlzxa7

nwwlzxa72#

这会有任何意义吗?这是在运行时实现panic的方式。
该框架的父级将是main.go:18

gudnpqoy

gudnpqoy3#

@randall77 看起来更好,因为没有提到装配文件,但在我看来,这仍然不是正确的行为。我认为printLinef1之间的调用之间不应该有任何区别。

7tofc5zh

7tofc5zh4#

https://golang.org/cl/152537提到了这个问题:cmd/compile,runtime: redo mid-stack inlining tracebacks

3b6akqbq

3b6akqbq5#

汇编功能现已不再报告。我们现在报告 panic.go 作为父级。
这里有一个更一般的问题,正如以下对您程序的修改所证明的那样:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	f1()
}

func f1() {
	defer printLine("f1")
	f2()
}
func f2() {
	defer printLine("f2")
	f3()
}
func f3() {
	defer printLine("f3")
	panic(nil)
}
func printLine(s string) {
	fmt.Printf("%s:\n", s)
	var pcs [10]uintptr
	n := runtime.Callers(1, pcs[:])
	iter := runtime.CallersFrames(pcs[:n])
	for {
		f, more := iter.Next()
		fmt.Printf("  %s %s:%d\n", f.Function, f.File, f.Line)
		if !more {
			break
		}
	}
}

这目前输出:

f3:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  runtime.gopanic /usr/local/google/home/khr/sandbox/readonly/src/runtime/panic.go:619
  main.f3 /usr/local/google/home/khr/gowork/issue26320b.go:22
  main.f2 /usr/local/google/home/khr/gowork/issue26320b.go:18
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
f2:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  runtime.gopanic /usr/local/google/home/khr/sandbox/readonly/src/runtime/panic.go:619
  main.f3 /usr/local/google/home/khr/gowork/issue26320b.go:22
  main.f2 /usr/local/google/home/khr/gowork/issue26320b.go:18
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
f1:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  runtime.gopanic /usr/local/google/home/khr/sandbox/readonly/src/runtime/panic.go:619
  main.f3 /usr/local/google/home/khr/gowork/issue26320b.go:22
  main.f2 /usr/local/google/home/khr/gowork/issue26320b.go:18
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
panic: nil

goroutine 1 [running]:
main.f3()
	/usr/local/google/home/khr/gowork/issue26320b.go:22 +0x5a
main.f2()
	/usr/local/google/home/khr/gowork/issue26320b.go:18 +0x53
main.f1()
	/usr/local/google/home/khr/gowork/issue26320b.go:14 +0x53
main.main()
	/usr/local/google/home/khr/gowork/issue26320b.go:9 +0x20
exit status 2

我认为问题的关键在于,在执行 defer printLine("f1") 时,我们是否仍然需要报告 gopanicf3f2 仍然在栈上?这是栈的实际状态。我们需要保留这种实际状态,以便在恐慌完全回溯到 goroutine 的顶部时打印恐慌堆栈跟踪(我假设每个人都同意 goroutine 1 之后的所有内容都是正确的)。
但是,对于 runtime.Callers 和朋友们,如果相关的 defer 恢复了,我们可以跳过已知已经死亡的帧。然后我们会得到:

f3:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  main.f3 /usr/local/google/home/khr/gowork/issue26320b.go:22
  main.f2 /usr/local/google/home/khr/gowork/issue26320b.go:18
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
f2:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  main.f2 /usr/local/google/home/khr/gowork/issue26320b.go:18
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
f1:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
panic: nil

goroutine 1 [running]:
main.f3()
	/usr/local/google/home/khr/gowork/issue26320b.go:22 +0x5a
main.f2()
	/usr/local/google/home/khr/gowork/issue26320b.go:18 +0x53
main.f1()
	/usr/local/google/home/khr/gowork/issue26320b.go:14 +0x53
main.main()
	/usr/local/google/home/khr/gowork/issue26320b.go:9 +0x20
exit status 2

我不确定实现这个机制的具体方法 - 我们需要在 gopanic 和当前 defer 的帧之间跳过帧(可能恢复,所以仍然是活动的)。我无法理解我们对于递归恐慌(由于恐慌而运行的 defers 中的恐慌)想要什么。
顺便说一下,如果我注解掉 panic 这一行,我们得到以下输出:

f3:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  main.f3 /usr/local/google/home/khr/gowork/issue26320b.go:23
  main.f2 /usr/local/google/home/khr/gowork/issue26320b.go:18
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
f2:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  main.f2 /usr/local/google/home/khr/gowork/issue26320b.go:19
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:14
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357
f1:
  main.printLine /usr/local/google/home/khr/gowork/issue26320b.go:27
  main.f1 /usr/local/google/home/khr/gowork/issue26320b.go:15
  main.main /usr/local/google/home/khr/gowork/issue26320b.go:9
  runtime.main /usr/local/google/home/khr/sandbox/readonly/src/runtime/proc.go:203
  runtime.goexit /usr/local/google/home/khr/sandbox/readonly/src/runtime/asm_amd64.s:1357

这确实为在回溯中隐藏中间函数提供了论据。
无论如何,将问题推迟到 1.14。

brvekthn

brvekthn6#

在我看来,当前的输出是正确的。在恐慌期间,延迟函数应该看到堆栈上的所有函数,而不仅仅是发生延迟的函数。

相关问题