@@ -212,32 +212,53 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
212
212
}
213
213
214
214
// If some non-Go code called sigaltstack, adjust.
215
+ setStack := false
216
+ var gsignalStack gsignalStack
215
217
sp := uintptr (unsafe .Pointer (& sig ))
216
218
if sp < g .m .gsignal .stack .lo || sp >= g .m .gsignal .stack .hi {
217
- var st stackt
218
- sigaltstack (nil , & st )
219
- if st .ss_flags & _SS_DISABLE != 0 {
220
- setg (nil )
221
- needm (0 )
222
- noSignalStack (sig )
223
- dropm ()
224
- }
225
- stsp := uintptr (unsafe .Pointer (st .ss_sp ))
226
- if sp < stsp || sp >= stsp + st .ss_size {
227
- setg (nil )
228
- needm (0 )
229
- sigNotOnStack (sig )
230
- dropm ()
219
+ if sp >= g .m .g0 .stack .lo && sp < g .m .g0 .stack .hi {
220
+ // The signal was delivered on the g0 stack.
221
+ // This can happen when linked with C code
222
+ // using the thread sanitizer, which collects
223
+ // signals then delivers them itself by calling
224
+ // the signal handler directly when C code,
225
+ // including C code called via cgo, calls a
226
+ // TSAN-intercepted function such as malloc.
227
+ st := stackt {ss_size : g .m .g0 .stack .hi - g .m .g0 .stack .lo }
228
+ setSignalstackSP (& st , g .m .g0 .stack .lo )
229
+ setGsignalStack (& st , & gsignalStack )
230
+ g .m .gsignal .stktopsp = getcallersp (unsafe .Pointer (& sig ))
231
+ setStack = true
232
+ } else {
233
+ var st stackt
234
+ sigaltstack (nil , & st )
235
+ if st .ss_flags & _SS_DISABLE != 0 {
236
+ setg (nil )
237
+ needm (0 )
238
+ noSignalStack (sig )
239
+ dropm ()
240
+ }
241
+ stsp := uintptr (unsafe .Pointer (st .ss_sp ))
242
+ if sp < stsp || sp >= stsp + st .ss_size {
243
+ setg (nil )
244
+ needm (0 )
245
+ sigNotOnStack (sig )
246
+ dropm ()
247
+ }
248
+ setGsignalStack (& st , & gsignalStack )
249
+ g .m .gsignal .stktopsp = getcallersp (unsafe .Pointer (& sig ))
250
+ setStack = true
231
251
}
232
- setGsignalStack (& st )
233
- g .m .gsignal .stktopsp = getcallersp (unsafe .Pointer (& sig ))
234
252
}
235
253
236
254
setg (g .m .gsignal )
237
255
c := & sigctxt {info , ctx }
238
256
c .fixsigcode (sig )
239
257
sighandler (sig , info , ctx , g )
240
258
setg (g )
259
+ if setStack {
260
+ restoreGsignalStack (& gsignalStack )
261
+ }
241
262
}
242
263
243
264
// sigpanic turns a synchronous signal into a run-time panic.
@@ -585,7 +606,7 @@ func minitSignalStack() {
585
606
signalstack (& _g_ .m .gsignal .stack )
586
607
_g_ .m .newSigstack = true
587
608
} else {
588
- setGsignalStack (& st )
609
+ setGsignalStack (& st , nil )
589
610
_g_ .m .newSigstack = false
590
611
}
591
612
}
@@ -618,14 +639,32 @@ func unminitSignals() {
618
639
}
619
640
}
620
641
642
+ // gsignalStack saves the fields of the gsignal stack changed by
643
+ // setGsignalStack.
644
+ type gsignalStack struct {
645
+ stack stack
646
+ stackguard0 uintptr
647
+ stackguard1 uintptr
648
+ stackAlloc uintptr
649
+ stktopsp uintptr
650
+ }
651
+
621
652
// setGsignalStack sets the gsignal stack of the current m to an
622
653
// alternate signal stack returned from the sigaltstack system call.
654
+ // It saves the old values in *old for use by restoreGsignalStack.
623
655
// This is used when handling a signal if non-Go code has set the
624
656
// alternate signal stack.
625
657
//go:nosplit
626
658
//go:nowritebarrierrec
627
- func setGsignalStack (st * stackt ) {
659
+ func setGsignalStack (st * stackt , old * gsignalStack ) {
628
660
g := getg ()
661
+ if old != nil {
662
+ old .stack = g .m .gsignal .stack
663
+ old .stackguard0 = g .m .gsignal .stackguard0
664
+ old .stackguard1 = g .m .gsignal .stackguard1
665
+ old .stackAlloc = g .m .gsignal .stackAlloc
666
+ old .stktopsp = g .m .gsignal .stktopsp
667
+ }
629
668
stsp := uintptr (unsafe .Pointer (st .ss_sp ))
630
669
g .m .gsignal .stack .lo = stsp
631
670
g .m .gsignal .stack .hi = stsp + st .ss_size
@@ -634,6 +673,19 @@ func setGsignalStack(st *stackt) {
634
673
g .m .gsignal .stackAlloc = st .ss_size
635
674
}
636
675
676
+ // restoreGsignalStack restores the gsignal stack to the value it had
677
+ // before entering the signal handler.
678
+ //go:nosplit
679
+ //go:nowritebarrierrec
680
+ func restoreGsignalStack (st * gsignalStack ) {
681
+ gp := getg ().m .gsignal
682
+ gp .stack = st .stack
683
+ gp .stackguard0 = st .stackguard0
684
+ gp .stackguard1 = st .stackguard1
685
+ gp .stackAlloc = st .stackAlloc
686
+ gp .stktopsp = st .stktopsp
687
+ }
688
+
637
689
// signalstack sets the current thread's alternate signal stack to s.
638
690
//go:nosplit
639
691
func signalstack (s * stack ) {
0 commit comments