@@ -274,19 +274,56 @@ func sigpipe() {
274
274
dieFromSignal (_SIGPIPE )
275
275
}
276
276
277
- // sigFetchG fetches the value of G safely when running in a signal handler.
278
277
// On some architectures, the g value may be clobbered when running in a VDSO.
279
278
// See issue #32912.
280
279
//
281
280
//go:nosplit
282
- func sigFetchG (c * sigctxt ) * g {
281
+ func sigClobbered (c * sigctxt ) bool {
283
282
switch GOARCH {
284
283
case "arm" , "arm64" :
285
- if inVDSOPage (c .sigpc ()) {
286
- return nil
284
+ return inVDSOPage (c .sigpc ());
285
+ }
286
+ return false
287
+ }
288
+
289
+ // sigpending stores signals during the Go signal handler when the g value is clobbered.
290
+ // See issue #34391.
291
+ var sigpending [(_NSIG + 31 ) / 32 ]uint32
292
+
293
+ func sigAddPending (s uint32 ) {
294
+ for {
295
+ p := sigpending [s / 32 ]
296
+ q := p | (1 << (s & 31 ))
297
+ if atomic .Cas (& sigpending [s / 32 ], p , q ) {
298
+ return
287
299
}
288
300
}
289
- return getg ()
301
+ }
302
+
303
+ // sigClearPending is called from outside the signal handler context.
304
+ // It should be called just after the clobbered G value is restored.
305
+ //go:nosplit
306
+ //go:nowritebarrierrec
307
+ func sigClearPending () {
308
+ for s := 0 ; s < _NSIG ; s ++ {
309
+ // steal signal from pending queue
310
+ steal := false
311
+ for {
312
+ p := sigpending [s / 32 ]
313
+ if p & (1 << (s & 31 )) == 0 {
314
+ break
315
+ }
316
+ q := p &^ (1 << (s & 31 ))
317
+ if atomic .Cas (& sigpending [s / 32 ], p , q ) {
318
+ steal = true
319
+ break
320
+ }
321
+ }
322
+ if ! steal {
323
+ continue
324
+ }
325
+ raise (uint32 (s ))
326
+ }
290
327
}
291
328
292
329
// sigtrampgo is called from the signal handler function, sigtramp,
@@ -305,7 +342,16 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
305
342
return
306
343
}
307
344
c := & sigctxt {info , ctx }
308
- g := sigFetchG (c )
345
+ if sigClobbered (c ) {
346
+ if sig == _SIGPROF {
347
+ sigprofNonGoPC (c .sigpc ())
348
+ return
349
+ }
350
+ // at this point iscgo must be true
351
+ sigAddPending (sig )
352
+ return
353
+ }
354
+ g := getg ()
309
355
if g == nil {
310
356
if sig == _SIGPROF {
311
357
sigprofNonGoPC (c .sigpc ())
@@ -670,13 +716,19 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
670
716
if (c .sigcode () == _SI_USER || flags & _SigPanic == 0 ) && sig != _SIGPIPE {
671
717
return false
672
718
}
673
- // Determine if the signal occurred inside Go code. We test that:
674
- // (1) we weren't in VDSO page,
675
- // (2) we were in a goroutine (i.e., m.curg != nil), and
676
- // (3) we weren't in CGO.
677
- g := sigFetchG (c )
678
- if g != nil && g .m != nil && g .m .curg != nil && ! g .m .incgo {
679
- return false
719
+ if sigClobbered (c ) {
720
+ // There is no handler to be forwarded to.
721
+ if ! iscgo {
722
+ return false
723
+ }
724
+ } else {
725
+ // Determine if the signal occurred inside Go code. We test that:
726
+ // (1) we were in a goroutine (i.e., m.curg != nil), and
727
+ // (2) we weren't in CGO.
728
+ g := getg ()
729
+ if g != nil && g .m != nil && g .m .curg != nil && ! g .m .incgo {
730
+ return false
731
+ }
680
732
}
681
733
682
734
// Signal not handled by Go, forward it.
0 commit comments