Skip to content

Segfault when calling Go function from cgo signal handler #45499

Closed
@tiborvass

Description

@tiborvass

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

$ go version
1.16.3

Does this issue reproduce with the latest release?

Yes

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/root/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.16.3"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/root/tmp-curiosity-segv/go.mod"
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-build37738244=/tmp/go-build -gno-record-gcc-switches"

What did you do?

// cgosignal.go
// Run with: go run cgosignal.go & sleep 1; kill -USR1 %%
package main

/*
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

extern double asin(double);
extern double acos(double);

static void sighandler(int signum) {
    fprintf(stderr, "Signal caught, exiting!\n");
    fprintf(stderr, "acos = %lf\n", acos(3.14));
    fprintf(stderr, "Past Go call!\n");
    exit(0);
}

static void main() {
    struct sigaction sigact;
    sigact.sa_handler = sighandler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGUSR1, &sigact, NULL);

    fprintf(stderr, "Loaded; waiting for SIGUSR1\n");
    acos(3.14);
    asin(3.14);

    sleep(0xFFFFFFFF);
}
*/
import "C"

//export asin
func asin(x C.double) C.double {
	for {}
	return x
}

//export acos
func acos(x C.double) C.double {
	return x
}

func main() {
	C.main()
}

What did you expect to see?

[1] 27268
Loaded; waiting for SIGUSR1
Signal caught, exiting!
acos = 3.14
Past Go call!
exit status 0
[1]+  Exit 0                  go run cgosignal.go

What did you see instead?

[1] 27268
Loaded; waiting for SIGUSR1
Signal caught, exiting!
unexpected fault address 0xfffffffffffffff8
fatal: morestack on g0
SIGTRAP: trace trap
PC=0x45ce02 m=0 sigcode=128
signal arrived during cgo execution

goroutine 1 [running, locked to thread]:
runtime.abort()
	/usr/local/go/src/runtime/asm_amd64.s:854 +0x2 fp=0xc00004a750 sp=0xc00004a748 pc=0x45ce02
runtime.morestack()
	/usr/local/go/src/runtime/asm_amd64.s:425 +0x25 fp=0xc00004a758 sp=0xc00004a750 pc=0x45b2c5

rax    0x17
rbx    0x6d8840
rcx    0x45e675
rdx    0x17
rdi    0x2
rsi    0x47d19a
rbp    0xc00004a720
rsp    0xc00004a748
r8     0x1
r9     0x706280
r10    0x0
r11    0x202
r12    0xf2
r13    0x0
r14    0x48fd98
r15    0x0
rip    0x45ce02
rflags 0x206
cs     0x33
fs     0x0
gs     0x0
exit status 2
[1]+  Exit 1                  go run cgosignal.go

Notes

I was trying to help out @paultag (https://twitter.com/paultag/status/1380617072921677828) and managed to reproduce the issue without shared libraries involved, just plain cgo signal handler calling Go code.

The only maybe-related issue I found was #19465 (I'm suspecting something to do with async-signal-safety) which is why I did the repro with SIGUSR1 and not SIGINT (which also has the issue).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions