From: Ian Lance Taylor Date: Thu, 20 Feb 2025 01:37:49 +0000 (-0800) Subject: [release-branch.go1.24] syscall: don't send child signal when testing pidfd X-Git-Tag: go1.24.1~10 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=d418e224ae3bc44c5a3c66a4955832e64179e16b;p=gostls13.git [release-branch.go1.24] syscall: don't send child signal when testing pidfd Avoid a spurious SIGCHLD the first time we start a process. For #71828 Fixes #71849 Change-Id: I744100d21bf6aaaaafc99bc5eec9f9f807a50682 Reviewed-on: https://go-review.googlesource.com/c/go/+/651035 Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- diff --git a/src/os/exec/exec_posix_test.go b/src/os/exec/exec_posix_test.go index 45604203dd..77c5fc11e4 100644 --- a/src/os/exec/exec_posix_test.go +++ b/src/os/exec/exec_posix_test.go @@ -11,12 +11,15 @@ import ( "internal/testenv" "io" "os" + "os/exec" + "os/signal" "os/user" "path/filepath" "runtime" "slices" "strconv" "strings" + "sync" "syscall" "testing" "time" @@ -24,6 +27,7 @@ import ( func init() { registerHelperCommand("pwd", cmdPwd) + registerHelperCommand("signaltest", cmdSignalTest) } func cmdPwd(...string) { @@ -274,3 +278,55 @@ func TestExplicitPWD(t *testing.T) { }) } } + +// Issue 71828. +func TestSIGCHLD(t *testing.T) { + cmd := helperCommand(t, "signaltest") + out, err := cmd.CombinedOutput() + t.Logf("%s", out) + if err != nil { + t.Error(err) + } +} + +// cmdSignaltest is for TestSIGCHLD. +// This runs in a separate process because the bug only happened +// the first time that a child process was started. +func cmdSignalTest(...string) { + chSig := make(chan os.Signal, 1) + signal.Notify(chSig, syscall.SIGCHLD) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + c := 0 + for range chSig { + c++ + fmt.Printf("SIGCHLD %d\n", c) + if c > 1 { + fmt.Println("too many SIGCHLD signals") + os.Exit(1) + } + } + }() + defer func() { + signal.Reset(syscall.SIGCHLD) + close(chSig) + wg.Wait() + }() + + exe, err := os.Executable() + if err != nil { + fmt.Printf("os.Executable failed: %v\n", err) + os.Exit(1) + } + + cmd := exec.Command(exe, "hang", "200ms") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Printf("failed to run child process: %v\n", err) + os.Exit(1) + } +} diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index 0009080d68..7730bc6496 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -818,7 +818,7 @@ func os_checkClonePidfd() error { // //go:noinline func doCheckClonePidfd(pidfd *int32) (pid uintptr, errno Errno) { - flags := uintptr(CLONE_VFORK | CLONE_VM | CLONE_PIDFD | SIGCHLD) + flags := uintptr(CLONE_VFORK | CLONE_VM | CLONE_PIDFD) if runtime.GOARCH == "s390x" { // On Linux/s390, the first two arguments of clone(2) are swapped. pid, errno = rawVforkSyscall(SYS_CLONE, 0, flags, uintptr(unsafe.Pointer(pidfd)))