internal/version: ignore signals intended for the child process

Since the underlying toolchain is run as a child process (and not
exec'd), signals that are sent to this process (for example, an
interrupt sent by a shell) will be handled by both the parent and the
child. This poses a problem for signals like SIGQUIT, where both
processes' runtimes attempt to write out information to the same output.

Before running the final command, start a signal handler that will
ignore a signal sent to the parent, emulating the behavior of go run.

This code is a modified version of cmd/go/internal/base.

Fixes golang/go#36976.

Change-Id: I29aa699dc059fd448aa9478f729ed8d90379616b
Reviewed-on: https://go-review.googlesource.com/c/dl/+/217765
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
diff --git a/internal/version/signal_notunix.go b/internal/version/signal_notunix.go
new file mode 100644
index 0000000..506655d
--- /dev/null
+++ b/internal/version/signal_notunix.go
@@ -0,0 +1,14 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build plan9 || windows
+// +build plan9 windows
+
+package version
+
+import (
+	"os"
+)
+
+var signalsToIgnore = []os.Signal{os.Interrupt}
diff --git a/internal/version/signal_unix.go b/internal/version/signal_unix.go
new file mode 100644
index 0000000..e9b9fb9
--- /dev/null
+++ b/internal/version/signal_unix.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || darwin || dragonfly || freebsd || js || linux || netbsd || openbsd || solaris
+// +build aix darwin dragonfly freebsd js linux netbsd openbsd solaris
+
+package version
+
+import (
+	"os"
+	"syscall"
+)
+
+var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
diff --git a/internal/version/version.go b/internal/version/version.go
index 866e4ad..98e5d4a 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -18,6 +18,7 @@
 	"net/http"
 	"os"
 	"os/exec"
+	"os/signal"
 	"os/user"
 	"path"
 	"path/filepath"
@@ -64,6 +65,9 @@
 		newPath += string(filepath.ListSeparator) + p
 	}
 	cmd.Env = dedupEnv(caseInsensitiveEnv, append(os.Environ(), "GOROOT="+root, "PATH="+newPath))
+
+	handleSignals()
+
 	if err := cmd.Run(); err != nil {
 		// TODO: return the same exit status maybe.
 		os.Exit(1)
@@ -500,3 +504,9 @@
 	}
 	return out
 }
+
+func handleSignals() {
+	// Ensure that signals intended for the child process are not handled by
+	// this process' runtime (e.g. SIGQUIT). See issue #36976.
+	signal.Notify(make(chan os.Signal), signalsToIgnore...)
+}