@@ -354,6 +354,7 @@ func deferproc(fn func()) {
354354 d .link = gp ._defer
355355 gp ._defer = d
356356 d .fn = fn
357+ d .pc = sys .GetCallerPC ()
357358 // We must not be preempted between calling GetCallerSP and
358359 // storing it to d.sp because GetCallerSP's result is a
359360 // uintptr stack pointer.
@@ -457,6 +458,7 @@ func deferrangefunc() any {
457458 d := newdefer ()
458459 d .link = gp ._defer
459460 gp ._defer = d
461+ d .pc = sys .GetCallerPC ()
460462 // We must not be preempted between calling GetCallerSP and
461463 // storing it to d.sp because GetCallerSP's result is a
462464 // uintptr stack pointer.
@@ -516,6 +518,7 @@ func deferconvert(d0 *_defer) {
516518 }
517519 for d1 := d ; ; d1 = d1 .link {
518520 d1 .sp = d0 .sp
521+ d1 .pc = d0 .pc
519522 if d1 .link == nil {
520523 d1 .link = tail
521524 break
@@ -544,6 +547,7 @@ func deferprocStack(d *_defer) {
544547 d .heap = false
545548 d .rangefunc = false
546549 d .sp = sys .GetCallerSP ()
550+ d .pc = sys .GetCallerPC ()
547551 // The lines below implement:
548552 // d.link = gp._defer
549553 // d.head = nil
@@ -971,6 +975,8 @@ func (p *_panic) nextDefer() (func(), bool) {
971975
972976 fn := d .fn
973977
978+ p .retpc = d .pc
979+
974980 // Unlink and free.
975981 popDefer (gp )
976982
@@ -1010,12 +1016,6 @@ func (p *_panic) nextFrame() (ok bool) {
10101016 // it's non-zero.
10111017
10121018 if u .frame .sp == limit {
1013- f := u .frame .fn
1014- if f .deferreturn == 0 {
1015- throw ("no deferreturn" )
1016- }
1017- p .retpc = f .entry () + uintptr (f .deferreturn )
1018-
10191019 break // found a frame with linked defers
10201020 }
10211021
@@ -1271,6 +1271,15 @@ func recovery(gp *g) {
12711271 pc , sp , fp := p .retpc , uintptr (p .sp ), uintptr (p .fp )
12721272 p0 , saveOpenDeferState := p , p .deferBitsPtr != nil && * p .deferBitsPtr != 0
12731273
1274+ // The linker records the f-relative address of a call to deferreturn in f's funcInfo.
1275+ // Assuming a "normal" call to recover() inside one of f's deferred functions
1276+ // invoked for a panic, that is the desired PC for exiting f.
1277+ f := findfunc (pc )
1278+ if f .deferreturn == 0 {
1279+ throw ("no deferreturn" )
1280+ }
1281+ gotoPc := f .entry () + uintptr (f .deferreturn )
1282+
12741283 // Unwind the panic stack.
12751284 for ; p != nil && uintptr (p .startSP ) < sp ; p = p .link {
12761285 // Don't allow jumping past a pending Goexit.
@@ -1293,7 +1302,7 @@ func recovery(gp *g) {
12931302 // With how subtle defer handling is, this might not actually be
12941303 // worthwhile though.
12951304 if p .goexit {
1296- pc , sp = p .startPC , uintptr (p .startSP )
1305+ gotoPc , sp = p .startPC , uintptr (p .startSP )
12971306 saveOpenDeferState = false // goexit is unwinding the stack anyway
12981307 break
12991308 }
@@ -1356,7 +1365,7 @@ func recovery(gp *g) {
13561365
13571366 // branch directly to the deferreturn
13581367 gp .sched .sp = sp
1359- gp .sched .pc = pc
1368+ gp .sched .pc = gotoPc
13601369 gp .sched .lr = 0
13611370 // Restore the bp on platforms that support frame pointers.
13621371 // N.B. It's fine to not set anything for platforms that don't
0 commit comments