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时发现的。
oug3syen1#
Kindly paging @aclements@davidlazar
nwwlzxa72#
这会有任何意义吗?这是在运行时实现panic的方式。该框架的父级将是main.go:18。
panic
main.go:18
gudnpqoy3#
@randall77 看起来更好,因为没有提到装配文件,但在我看来,这仍然不是正确的行为。我认为printLine和f1之间的调用之间不应该有任何区别。
printLine
f1
7tofc5zh4#
https://golang.org/cl/152537提到了这个问题:cmd/compile,runtime: redo mid-stack inlining tracebacks
cmd/compile,runtime: redo mid-stack inlining tracebacks
3b6akqbq5#
汇编功能现已不再报告。我们现在报告 panic.go 作为父级。这里有一个更一般的问题,正如以下对您程序的修改所证明的那样:
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") 时,我们是否仍然需要报告 gopanic、f3 和 f2 仍然在栈上?这是栈的实际状态。我们需要保留这种实际状态,以便在恐慌完全回溯到 goroutine 的顶部时打印恐慌堆栈跟踪(我假设每个人都同意 goroutine 1 之后的所有内容都是正确的)。但是,对于 runtime.Callers 和朋友们,如果相关的 defer 恢复了,我们可以跳过已知已经死亡的帧。然后我们会得到:
defer printLine("f1")
gopanic
f3
f2
goroutine 1
runtime.Callers
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。
brvekthn6#
在我看来,当前的输出是正确的。在恐慌期间,延迟函数应该看到堆栈上的所有函数,而不仅仅是发生延迟的函数。
6条答案
按热度按时间oug3syen1#
Kindly paging @aclements@davidlazar
nwwlzxa72#
这会有任何意义吗?这是在运行时实现
panic
的方式。该框架的父级将是
main.go:18
。gudnpqoy3#
@randall77 看起来更好,因为没有提到装配文件,但在我看来,这仍然不是正确的行为。我认为
printLine
和f1
之间的调用之间不应该有任何区别。7tofc5zh4#
https://golang.org/cl/152537提到了这个问题:
cmd/compile,runtime: redo mid-stack inlining tracebacks
3b6akqbq5#
汇编功能现已不再报告。我们现在报告
panic.go
作为父级。这里有一个更一般的问题,正如以下对您程序的修改所证明的那样:
这目前输出:
我认为问题的关键在于,在执行
defer printLine("f1")
时,我们是否仍然需要报告gopanic
、f3
和f2
仍然在栈上?这是栈的实际状态。我们需要保留这种实际状态,以便在恐慌完全回溯到 goroutine 的顶部时打印恐慌堆栈跟踪(我假设每个人都同意goroutine 1
之后的所有内容都是正确的)。但是,对于
runtime.Callers
和朋友们,如果相关的 defer 恢复了,我们可以跳过已知已经死亡的帧。然后我们会得到:我不确定实现这个机制的具体方法 - 我们需要在 gopanic 和当前 defer 的帧之间跳过帧(可能恢复,所以仍然是活动的)。我无法理解我们对于递归恐慌(由于恐慌而运行的 defers 中的恐慌)想要什么。
顺便说一下,如果我注解掉 panic 这一行,我们得到以下输出:
这确实为在回溯中隐藏中间函数提供了论据。
无论如何,将问题推迟到 1.14。
brvekthn6#
在我看来,当前的输出是正确的。在恐慌期间,延迟函数应该看到堆栈上的所有函数,而不仅仅是发生延迟的函数。