Skip to content

Commit 28f650a

Browse files
runtime: don't call libc sigaction function in forked child
If we are using vfork, and if something (such as TSAN) is intercepting the sigaction function, then we must call the system call, not the libc function. Otherwise the intercepted sigaction call in the child may trash the data structures in the parent. Change-Id: Id9588bfeaa934f32c920bf829c5839be5cacf243 Reviewed-on: https://go-review.googlesource.com/50251 Reviewed-by: Joe Tsai <[email protected]> Reviewed-by: Austin Clements <[email protected]>
1 parent 5125a96 commit 28f650a

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

src/runtime/cgo_sigaction.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32 {
3030

3131
var ret int32
3232

33-
if _cgo_sigaction == nil {
33+
if _cgo_sigaction == nil || inForkedChild {
3434
ret = sysSigaction(sig, new, old, size)
3535
} else {
3636
// We need to call _cgo_sigaction, which means we need a big enough stack

src/runtime/proc.go

+17
Original file line numberDiff line numberDiff line change
@@ -2851,18 +2851,35 @@ func syscall_runtime_AfterFork() {
28512851
systemstack(afterfork)
28522852
}
28532853

2854+
// inForkedChild is true while manipulating signals in the child process.
2855+
// This is used to avoid calling libc functions in case we are using vfork.
2856+
var inForkedChild bool
2857+
28542858
// Called from syscall package after fork in child.
28552859
// It resets non-sigignored signals to the default handler, and
28562860
// restores the signal mask in preparation for the exec.
2861+
//
2862+
// Because this might be called during a vfork, and therefore may be
2863+
// temporarily sharing address space with the parent process, this must
2864+
// not change any global variables or calling into C code that may do so.
2865+
//
28572866
//go:linkname syscall_runtime_AfterForkInChild syscall.runtime_AfterForkInChild
28582867
//go:nosplit
28592868
//go:nowritebarrierrec
28602869
func syscall_runtime_AfterForkInChild() {
2870+
// It's OK to change the global variable inForkedChild here
2871+
// because we are going to change it back. There is no race here,
2872+
// because if we are sharing address space with the parent process,
2873+
// then the parent process can not be running concurrently.
2874+
inForkedChild = true
2875+
28612876
clearSignalHandlers()
28622877

28632878
// When we are the child we are the only thread running,
28642879
// so we know that nothing else has changed gp.m.sigmask.
28652880
msigrestore(getg().m.sigmask)
2881+
2882+
inForkedChild = false
28662883
}
28672884

28682885
// Called from syscall package before Exec.

0 commit comments

Comments
 (0)