Skip to content

runtime: respect SA_RESETHAND when forwarding to non-Go signal handler #32659

Open
@jimhuaang

Description

@jimhuaang

What version of Go are you using (go version)?

go version go1.10.4 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/jim/go"
GORACE=""
GOROOT="/usr/lib/go-1.10"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.10/pkg/tool/linux_amd64"
GCCGO="/usr/bin/gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build690985833=/tmp/go-build -gno-record-gcc-switches"

What did you do?

    1. Compile a library using -buildmode=c-shared
    1. Trap SIGSEGV in a C program with a handler which will reraise SIGSEGV
    1. Load the library against the C program using dlopen
    1. Cause the C program to SEGSIGV by dereference a NULL pointer

src file: infinitesignalloop.gz
to compile: uncompress src file to GOPATH and run make
to reproduce: just run ./trap_signal before

What did you expect to see?

The program should crash finally with the default system segfault handler be called.

trap SIGSEGV before dlopen ./libdummycgo.so
Received Segmentation fault ...
Segmentation fault (core dumped)

What did you see instead?

A infinite sighandling loop has happen.

trap SIGSEGV before dlopen ./libdummycgo.so
Received Segmentation fault ...
Received Segmentation fault ...
... // infinite loop
Received Segmentation fault ...
Killed

Following the code with gdb, it seems that Go signal handler raises SIGSEGV again to invoke the C handler, then C handler reraise SIGSEGV, which is catched by Go signal handler again, and then repeat and repeat.

As doc https://golang.org/pkg/os/signal/#hdr-Go_programs_that_use_cgo_or_SWIG said in section Go programs that use cgo or SWIG (not in section Non-Go programs that call Go code)

If the Go signal handler is invoked on a non-Go thread not running Go code, the handler generally forwards the signal to the non-Go code, as follows. If the signal is SIGPROF, the Go handler does nothing. Otherwise, the Go handler removes itself, unblocks the signal, and raises it again, to invoke any non-Go handler or default system handler. If the program does not exit, the Go handler then reinstalls itself and continues execution of the program.

And if we trap SIGSEGV after load the library (just run ./trap_signal after), there C program will just crash with system default handler called as expected.

Some more tests shows above issue exist for all synchronize signals (SIGBUS, SIGFPE, and SIGSEGV).

When not use dlopen to load the library, instead to link the library against to a C program as following,

    1. Compile a library using -buildmode=c-shared
    1. Trap SIGSEGV in a C program with a handler which will reraise SIGSEGV
    1. Link the library against the C program
    1. Cause the C program to SEGSIGV by dereference a NULL pointer
      and then run the C program, it will crash with default segfault handler called.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions