关于runtime.gopanic中g._defer.fn无法影响g._defer的疑问
关于Go 1.20.1中
runtime.gopanic代码逻辑的疑问 我对Go 1.20.1版本里runtime.gopanic的这段代码(对应panic.go第890-897行)存在疑问。
测试代码及编译结果
测试Go代码
package main func main() { a := func() { b := func() { recover() } defer b() } defer a() panic(1) }
plan9编译结果
main.go:3 0x105a100 493b6610 cmp rsp, qword ptr [r14+0x10] main.go:3 0x105a104 7651 jbe 0x105a157 => main.go:3 0x105a106* 4883ec68 sub rsp, 0x68 main.go:3 0x105a10a 48896c2460 mov qword ptr [rsp+0x60], rbp main.go:3 0x105a10f 488d6c2460 lea rbp, ptr [rsp+0x60] main.go:4 0x105a114 488d0dc50e0100 lea rcx, ptr [rip+0x10ec5] main.go:4 0x105a11b 48894c2458 mov qword ptr [rsp+0x58], rcx main.go:10 0x105a120 48894c2428 mov qword ptr [rsp+0x28], rcx main.go:10 0x105a125 488d442410 lea rax, ptr [rsp+0x10] main.go:10 0x105a12a e89136fdff call $runtime.deferprocStack main.go:10 0x105a12f 85c0 test eax, eax main.go:10 0x105a131 7515 jnz 0x105a148 main.go:10 0x105a133 eb00 jmp 0x105a135 main.go:11 0x105a135 488d05043f0000 lea rax, ptr [rip+0x3f04] main.go:11 0x105a13c 488d1d8d3a0100 lea rbx, ptr [rip+0x13a8d] main.go:11 0x105a143 e83847fdff call $runtime.gopanic main.go:10 0x105a148 e8533cfdff call $runtime.deferreturn main.go:10 0x105a14d 488b6c2460 mov rbp, qword ptr [rsp+0x60] main.go:10 0x105a152 4883c468 add rsp, 0x68 main.go:10 0x105a156 c3 ret main.go:3 0x105a157 e8c4cfffff call $runtime.morestack_noctxt .:0 0x105a15c eba2 jmp $main.main
问题分析
在Go中,defer会调用runtime.deferprocStack,让当前g._defer指向最内层的defer;panic会调用runtime.gopanic。
我的测试代码里,调用runtime.gopanic时,当前g._defer的结构如下:
g._defer = &_defer{ fn: `main.a`, link: nil }
因此在panic.go第890行处会执行main.a(),而main.a内部会创建一个fn为main.a.b的新_defer,此时g._defer会指向这个新defer,原defer会被赋值为它的link,结构变为:
g._defer = &_defer{ fn: `main.a.b`, link: &_defer{ fn: `main.a`, link: nil } }
但实际调试中,panic.go第895行的gp._defer != d依然成立。我是不是忽略了整个过程里的某些细节?
调试环境
- Go版本:1.20.1
- 机器:64位macOS 11.7.2
- 内核版本:Darwin 20.6.0
- 调试工具:dlv
附录:调试截图


会不会是执行runtime.gopanic和runtime.deferprocStack的不是同一个goroutine?
内容的提问来源于stack exchange,提问作者spin
相关产品推荐
相关产品推荐

