Skip to content

Commit d29c14f

Browse files
runtime: factor signal stack code out of sigtrampgo
This reduces the required nosplit stack size, which permits building on Solaris with -gcflags=all=-N -l. Fixes #35046 Change-Id: Icb3a421bb791c73e2f670ecfadbe32daea79789f Reviewed-on: https://go-review.googlesource.com/c/go/+/202446 Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 4f364be commit d29c14f

File tree

1 file changed

+48
-36
lines changed

1 file changed

+48
-36
lines changed

src/runtime/signal_unix.go

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -333,43 +333,10 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
333333
}
334334

335335
// If some non-Go code called sigaltstack, adjust.
336-
setStack := false
337336
var gsignalStack gsignalStack
338-
sp := uintptr(unsafe.Pointer(&sig))
339-
if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
340-
if sp >= g.m.g0.stack.lo && sp < g.m.g0.stack.hi {
341-
// The signal was delivered on the g0 stack.
342-
// This can happen when linked with C code
343-
// using the thread sanitizer, which collects
344-
// signals then delivers them itself by calling
345-
// the signal handler directly when C code,
346-
// including C code called via cgo, calls a
347-
// TSAN-intercepted function such as malloc.
348-
st := stackt{ss_size: g.m.g0.stack.hi - g.m.g0.stack.lo}
349-
setSignalstackSP(&st, g.m.g0.stack.lo)
350-
setGsignalStack(&st, &gsignalStack)
351-
g.m.gsignal.stktopsp = getcallersp()
352-
setStack = true
353-
} else {
354-
var st stackt
355-
sigaltstack(nil, &st)
356-
if st.ss_flags&_SS_DISABLE != 0 {
357-
setg(nil)
358-
needm(0)
359-
noSignalStack(sig)
360-
dropm()
361-
}
362-
stsp := uintptr(unsafe.Pointer(st.ss_sp))
363-
if sp < stsp || sp >= stsp+st.ss_size {
364-
setg(nil)
365-
needm(0)
366-
sigNotOnStack(sig)
367-
dropm()
368-
}
369-
setGsignalStack(&st, &gsignalStack)
370-
g.m.gsignal.stktopsp = getcallersp()
371-
setStack = true
372-
}
337+
setStack := adjustSignalStack(sig, g.m, &gsignalStack)
338+
if setStack {
339+
g.m.gsignal.stktopsp = getcallersp()
373340
}
374341

375342
setg(g.m.gsignal)
@@ -386,6 +353,51 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
386353
}
387354
}
388355

356+
// adjustSignalStack adjusts the current stack guard based on the
357+
// stack pointer that is actually in use while handling a signal.
358+
// We do this in case some non-Go code called sigaltstack.
359+
// This reports whether the stack was adjusted, and if so stores the old
360+
// signal stack in *gsigstack.
361+
//go:nosplit
362+
func adjustSignalStack(sig uint32, mp *m, gsigStack *gsignalStack) bool {
363+
sp := uintptr(unsafe.Pointer(&sig))
364+
if sp >= mp.gsignal.stack.lo && sp < mp.gsignal.stack.hi {
365+
return false
366+
}
367+
368+
if sp >= mp.g0.stack.lo && sp < mp.g0.stack.hi {
369+
// The signal was delivered on the g0 stack.
370+
// This can happen when linked with C code
371+
// using the thread sanitizer, which collects
372+
// signals then delivers them itself by calling
373+
// the signal handler directly when C code,
374+
// including C code called via cgo, calls a
375+
// TSAN-intercepted function such as malloc.
376+
st := stackt{ss_size: mp.g0.stack.hi - mp.g0.stack.lo}
377+
setSignalstackSP(&st, mp.g0.stack.lo)
378+
setGsignalStack(&st, gsigStack)
379+
return true
380+
}
381+
382+
var st stackt
383+
sigaltstack(nil, &st)
384+
if st.ss_flags&_SS_DISABLE != 0 {
385+
setg(nil)
386+
needm(0)
387+
noSignalStack(sig)
388+
dropm()
389+
}
390+
stsp := uintptr(unsafe.Pointer(st.ss_sp))
391+
if sp < stsp || sp >= stsp+st.ss_size {
392+
setg(nil)
393+
needm(0)
394+
sigNotOnStack(sig)
395+
dropm()
396+
}
397+
setGsignalStack(&st, gsigStack)
398+
return true
399+
}
400+
389401
// crashing is the number of m's we have waited for when implementing
390402
// GOTRACEBACK=crash when a signal is received.
391403
var crashing int32

0 commit comments

Comments
 (0)