package main
/*
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct sigaction go_handler;
static void signal_handler(int sig, siginfo_t* info, void* ctx) {
printf("called %d\n", sig);
if (go_handler.sa_flags & SA_SIGINFO) {
go_handler.sa_sigaction(sig, info, ctx);
} else {
go_handler.sa_handler(sig);
}
}
void install_signal_handler() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_handler;
action.sa_flags = SA_SIGINFO | SA_RESTART |SA_ONSTACK;
sigemptyset(&action.sa_mask);
sigaction(SIGSEGV, &action, &go_handler);
}
*/
import "C"
func init() {
C.install_signal_handler()
}
func main() {
var x *int
*x = 0
}
called 11
runtime: newstack sp=0xc420009a40 stack=[0xc42004c000, 0xc42004dfc0]
morebuf={pc:0x7fff8ef2c52a sp:0xc420009a50 lr:0x0}
sched={pc:0x40340e0 sp:0xc420009a48 lr:0x0 ctxt:0x0}
runtime: gp=0xc4200001a0, gp->status=0x2
runtime: split stack overflow: 0xc420009a40 < 0xc42004c000
fatal error: runtime: split stack overflow
runtime stack:
runtime.throw(0x406bdf3, 0x1d)
/usr/local/go/src/runtime/panic.go:566 +0x95
runtime.newstack()
/usr/local/go/src/runtime/stack.go:1004 +0x5f4
runtime.morestack()
/usr/local/go/src/runtime/asm_amd64.s:366 +0x7f
goroutine 1 [running]:
runtime.sighandler(0xc42004df90, 0x0, 0x0, 0x0)
/usr/local/go/src/runtime/signal_amd64x.go:44 fp=0xc420009a50 sp=0xc420009a48
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2086 +0x1
It appears as though the signal handler is somehow not running on the
alternate signal stack. I don't know why that would be, though. I
have no other explanation. You'll have to debug it.
What you are doing seems rather dubious but I can't think of any
reason why it shouldn't work.
I'm not sure which part of the os/signal docs you are thinking of.
Crashes in Go code will work regardless of whether they are running on
threads started by C or not. So I assume you are talking about
crashes in C. How do you want to handle those crashes? Do you just
want to try to dump the stack? How do you want to handle other C
threads when one C thread crashes?
I do agree that your code should work in principle, and I'm not sure
why it doesn't.
If all you wan to do is handle SIGSEGV when it occurs in a C thread,
it may work to call signal.Notify(c, syscall.SIGSEGV). The channel
will receive a signal wen a SIGSEGV occurs in C code. At that point
it's not safe to continue, but it is safe to take whatever action you
like to dump C threads. I'm not sure this will work, because it
depends on what happens when the SIGSEGV signal handler returns to the
C code that triggered the SIGSEGV.
Interesting. Maybe we need to change this line in setsig in
runtime/os_darwin.go
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
to be
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) =
unsafe.Pointer(funcPC(sigtramp))
OK, then perhaps we need setsig in os_darwin.go to set
the sigaction field to a new function, written in assembler, like
sigtramp, but taking just the sigaction arguments.
And presumably not
calling sigreturn.
I'm only talking about changing Darwin.