2

I am confused about this part of runtime.gopanic. Below is my test golang code and its plan9 compilation.

package main

func main() {
    a := func() {
        b := func() {
            recover()
        }
        defer b()
    }
    defer a()
    panic(1)
}

        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

In golang, defer will call runtime.deferprocStack, so that the current g._defer should point to the innermost defer. panic will call runtime.gopanic.

In my test code, when calling runtime.gopanic, the current g._defer.fn is main.a. Just like this:

g._defer = &_defer{ fn: `main.a`, link: nil }

So in panic.go:890, main.a() will be executed, and in main.a, another _defer whose fn is main.a.b will be g._defer pointed to, previous defer will assign to this one's link. Just like this:

g._defer = &_defer{ fn: `main.a.b`, link: &_defer{ fn: `main.a`, link: nil } }

Howerer, in panic.go:895, gp._defer != d is still true. Am I overlooking something in the whole process?

I use dlv to debug my code, my golang version is 1.20.1, my machine is 64-bit macOS 11.7.2, and the kernel version is Darwin 20.6.0.

I'd really like to know the reason, I'd really appreciate it if you could explain!

Appenix

Here's what I see when debug with dlv. enter image description here enter image description here

Maybe not the same goroutine execute runtime.gopanic and runtime.deferprocStack during the whole process?

spin
  • 47
  • 4

0 Answers0