Go version
go version go1.26.1 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/kir/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/kir/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build737629206=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/kir/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/kir/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/kir/sdk/go1.26.1'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/kir/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/kir/sdk/go1.26.1/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.26.1'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
Run a simple Go program as PID 1 (in a new Linux PID namespace).
The program has no signal handlers installed.
Send SIGTERM to it.
What did you see happen?
The program exits with exit code 2.
What did you expect to see?
Either the signal being ignored (as this is PID 1 aka init), or at least a
saner exit code.
A curious bug was reported to kubernetes 1 and runc2 recently:
sometimes runc init reports exit status of 2.
Turns out, Go runtime assumes that on any UNIX system signals such as
SIGTERM (or any other that has _sigKill flag set in sigtable) with no
signal handler set up, will result in kernel terminating the program.
This is true, except for PID 1 which gets a custom treatment from the
kernel.
As a result, when a Go program that runs as PID 1 (which is easy to
achieve in Linux by using a new PID namespace) receives such a signal,
Go runtime calls dieFromSignal which falls through all the way to
exit(2), which is very confusing to a user.
This issue can be worked around by the program by adding custom handlers
for SIGTERM/SIGINT/SIGHUP, but that requires a goroutine to handle those
signals, which, in case of runc, unnecessarily raises its NPROC/pid.max
requirement (see discussion at 2).
Go version
go version go1.26.1 linux/amd64
Output of
go envin your module/workspace:What did you do?
Run a simple Go program as PID 1 (in a new Linux PID namespace).
The program has no signal handlers installed.
Send SIGTERM to it.
What did you see happen?
The program exits with exit code 2.
What did you expect to see?
Either the signal being ignored (as this is PID 1 aka init), or at least a
saner exit code.
A curious bug was reported to kubernetes 1 and runc2 recently:
sometimes
runc initreports exit status of 2.Turns out, Go runtime assumes that on any UNIX system signals such as
SIGTERM (or any other that has _sigKill flag set in sigtable) with no
signal handler set up, will result in kernel terminating the program.
This is true, except for PID 1 which gets a custom treatment from the
kernel.
As a result, when a Go program that runs as PID 1 (which is easy to
achieve in Linux by using a new PID namespace) receives such a signal,
Go runtime calls dieFromSignal which falls through all the way to
exit(2), which is very confusing to a user.
This issue can be worked around by the program by adding custom handlers
for SIGTERM/SIGINT/SIGHUP, but that requires a goroutine to handle those
signals, which, in case of runc, unnecessarily raises its NPROC/pid.max
requirement (see discussion at 2).