Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segfault when calling Go function from cgo signal handler #45499

Closed
tiborvass opened this issue Apr 10, 2021 · 2 comments
Closed

Segfault when calling Go function from cgo signal handler #45499

tiborvass opened this issue Apr 10, 2021 · 2 comments

Comments

@tiborvass
Copy link

tiborvass commented Apr 10, 2021

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).

@seankhliao
Copy link
Member

have you seen the os/signal section cgo ?

@ianlancetaylor
Copy link
Member

Unfortunately, C signal handlers can only call functions that are async-signal-safe (https://man7.org/linux/man-pages/man7/signal-safety.7.html). And Go code is never async-signal-safe. It is never going to be possible to call a Go function from a C signal handler.

@golang golang locked and limited conversation to collaborators Apr 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants