-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Go version
go version go1.25.0 linux/amd64
Output of go env
in your module/workspace:
AR='ar' CC='gcc' CGO_CFLAGS='-O2 -g' CGO_CPPFLAGS='' CGO_CXXFLAGS='-O2 -g' CGO_ENABLED='1' CGO_FFLAGS='-O2 -g' CGO_LDFLAGS='-O2 -g' CXX='g++' GCCGO='gccgo' GO111MODULE='' GOAMD64='v1' GOARCH='amd64' GOAUTH='netrc' GOBIN='' GOCACHE='/home/agis/.cache/go-build' GOCACHEPROG='' GODEBUG='' GOENV='/home/agis/.config/go/env' GOEXE='' GOEXPERIMENT='' GOFIPS140='off' GOFLAGS='' GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2541113073=/tmp/go-build -gno-record-gcc-switches' GOHOSTARCH='amd64' GOHOSTOS='linux' GOINSECURE='' GOMOD='/home/agis/dev/x/go.mod' GOMODCACHE='/home/agis/go/pkg/mod' GONOPROXY='' GONOSUMDB='' GOOS='linux' GOPATH='/home/agis/go' GOPRIVATE='' GOPROXY='https://proxy.golang.org,direct' GOROOT='/home/agis/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.0.linux-amd64' GOSUMDB='sum.golang.org' GOTELEMETRY='local' GOTELEMETRYDIR='/home/agis/.config/go/telemetry' GOTMPDIR='' GOTOOLCHAIN='auto' GOTOOLDIR='/home/agis/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.0.linux-amd64/pkg/tool/linux_amd64' GOVCS='' GOVERSION='go1.25.0' GOWORK='' PKG_CONFIG='pkg-config'
What did you do?
Brief
The way go tool
traps and forwards signals might cause tools that stay in the foreground to misbehave.
Note: I'm not sure if this is considered a bug or a "work as intended" situation. If there's intention of changing the behavior, I'd be happy to take a stab at it.
Description
go tool
traps signals and forwards them to the spawned tool:
go/src/cmd/go/internal/tool/tool.go
Lines 374 to 383 in cdd8cf4
However, if the spawned tool is a process that's in the foreground of the TTY, hitting Ctrl-C in the terminal will cause 2 SIGINT
signals to be delivered to the spawned tool: one from the kernel (the tool is in the same process group ID as go tool
) and one from go tool
itself.
This is problematic for tools that assign special meaning to a second SIGINT
. overmind (a process supervisor) is an example of this. The second signal causes it to forcefully kill all its processes.
Reproduction
// main.go package main func main() {}
// go.mod module foo go 1.25 toolchain go1.25.0 tool github.com/agis/gotool-sig require github.com/agis/gotool-sig v0.0.0-20250826124522-e922fff2b3fb // indirect
Run go tool gotool-sig 1
and then hit Ctrl-C in the terminal. You'll get the following output:
$ go tool gotool-sig 1
PID: 176199, PPID: 176162, PGID: 176162
Signal monitor started with buffer size 1...
^CReceived signal: interrupt (2)
Received signal: interrupt (2)
You'll notice that 2 interrupt signals were delivered to the tool, instead of one.
What did you see happen?
N/A (see above)
What did you expect to see?
Only 1 SIGINT should be delivered.