Commit a6dcb7d4 by Ian Lance Taylor

runtime: Catch signals on altstack, disable splitstack signal blocking.

From-SVN: r182607
parent e0d2f030
...@@ -24,13 +24,13 @@ __printpanics (struct __go_panic_stack *p) ...@@ -24,13 +24,13 @@ __printpanics (struct __go_panic_stack *p)
if (p->__next != NULL) if (p->__next != NULL)
{ {
__printpanics (p->__next); __printpanics (p->__next);
printf ("\t"); fprintf (stderr, "\t");
} }
printf ("panic: "); fprintf (stderr, "panic: ");
printany (p->__arg); printany (p->__arg);
if (p->__was_recovered) if (p->__was_recovered)
printf (" [recovered]"); fprintf (stderr, " [recovered]");
putchar ('\n'); fputc ('\n', stderr);
} }
/* This implements __go_panic which is used for the panic /* This implements __go_panic which is used for the panic
......
...@@ -17,109 +17,133 @@ ...@@ -17,109 +17,133 @@
#define SA_RESTART 0 #define SA_RESTART 0
#endif #endif
/* What to do for a signal. */ #ifdef USING_SPLIT_STACK
struct sigtab extern void __splitstack_getcontext(void *context[10]);
{
/* Signal number. */
int sig;
/* Nonzero if the signal should be caught. */
_Bool catch;
/* Nonzero if the signal should be queued. */
_Bool queue;
/* Nonzero if the signal should be ignored. */
_Bool ignore;
/* Nonzero if we should restart system calls. */
_Bool restart;
};
/* What to do for signals. */ extern void __splitstack_setcontext(void *context[10]);
static struct sigtab signals[] = #endif
{
{ SIGHUP, 0, 1, 0, 1 }, #define C SigCatch
{ SIGINT, 0, 1, 0, 1 }, #define I SigIgnore
{ SIGQUIT, 0, 1, 0, 1 }, #define R SigRestart
{ SIGALRM, 0, 1, 1, 1 }, #define Q SigQueue
{ SIGTERM, 0, 1, 0, 1 }, #define P SigPanic
/* Signal actions. This collects the sigtab tables for several
different targets from the master library. SIGKILL, SIGCONT, and
SIGSTOP are not listed, as we don't want to set signal handlers for
them. */
SigTab runtime_sigtab[] = {
#ifdef SIGHUP
{ SIGHUP, Q + R },
#endif
#ifdef SIGINT
{ SIGINT, Q + R },
#endif
#ifdef SIGQUIT
{ SIGQUIT, C },
#endif
#ifdef SIGILL #ifdef SIGILL
{ SIGILL, 1, 0, 0, 0 }, { SIGILL, C },
#endif #endif
#ifdef SIGTRAP #ifdef SIGTRAP
{ SIGTRAP, 1, 0, 0, 0 }, { SIGTRAP, C },
#endif #endif
#ifdef SIGABRT #ifdef SIGABRT
{ SIGABRT, 1, 0, 0, 0 }, { SIGABRT, C },
#endif #endif
#ifdef SIGBUS #ifdef SIGBUS
{ SIGBUS, 1, 0, 0, 0 }, { SIGBUS, C + P },
#endif #endif
#ifdef SIGFPE #ifdef SIGFPE
{ SIGFPE, 1, 0, 0, 0 }, { SIGFPE, C + P },
#endif #endif
#ifdef SIGUSR1 #ifdef SIGUSR1
{ SIGUSR1, 0, 1, 1, 1 }, { SIGUSR1, Q + I + R },
#endif #endif
#ifdef SIGSEGV #ifdef SIGSEGV
{ SIGSEGV, 1, 0, 0, 0 }, { SIGSEGV, C + P },
#endif #endif
#ifdef SIGUSR2 #ifdef SIGUSR2
{ SIGUSR2, 0, 1, 1, 1 }, { SIGUSR2, Q + I + R },
#endif #endif
#ifdef SIGPIPE #ifdef SIGPIPE
{ SIGPIPE, 0, 0, 1, 0 }, { SIGPIPE, I },
#endif
#ifdef SIGALRM
{ SIGALRM, Q + I + R },
#endif
#ifdef SIGTERM
{ SIGTERM, Q + R },
#endif #endif
#ifdef SIGSTKFLT #ifdef SIGSTKFLT
{ SIGSTKFLT, 1, 0, 0, 0 }, { SIGSTKFLT, C },
#endif #endif
#ifdef SIGCHLD #ifdef SIGCHLD
{ SIGCHLD, 0, 1, 1, 1 }, { SIGCHLD, Q + I + R },
#endif #endif
#ifdef SIGTSTP #ifdef SIGTSTP
{ SIGTSTP, 0, 1, 1, 1 }, { SIGTSTP, Q + I + R },
#endif #endif
#ifdef SIGTTIN #ifdef SIGTTIN
{ SIGTTIN, 0, 1, 1, 1 }, { SIGTTIN, Q + I + R },
#endif #endif
#ifdef SIGTTOU #ifdef SIGTTOU
{ SIGTTOU, 0, 1, 1, 1 }, { SIGTTOU, Q + I + R },
#endif #endif
#ifdef SIGURG #ifdef SIGURG
{ SIGURG, 0, 1, 1, 1 }, { SIGURG, Q + I + R },
#endif #endif
#ifdef SIGXCPU #ifdef SIGXCPU
{ SIGXCPU, 0, 1, 1, 1 }, { SIGXCPU, Q + I + R },
#endif #endif
#ifdef SIGXFSZ #ifdef SIGXFSZ
{ SIGXFSZ, 0, 1, 1, 1 }, { SIGXFSZ, Q + I + R },
#endif #endif
#ifdef SIGVTARLM #ifdef SIGVTALRM
{ SIGVTALRM, 0, 1, 1, 1 }, { SIGVTALRM, Q + I + R },
#endif #endif
#ifdef SIGPROF #ifdef SIGPROF
{ SIGPROF, 0, 1, 1, 1 }, { SIGPROF, Q + I + R },
#endif #endif
#ifdef SIGWINCH #ifdef SIGWINCH
{ SIGWINCH, 0, 1, 1, 1 }, { SIGWINCH, Q + I + R },
#endif #endif
#ifdef SIGIO #ifdef SIGIO
{ SIGIO, 0, 1, 1, 1 }, { SIGIO, Q + I + R },
#endif #endif
#ifdef SIGPWR #ifdef SIGPWR
{ SIGPWR, 0, 1, 1, 1 }, { SIGPWR, Q + I + R },
#endif #endif
#ifdef SIGSYS #ifdef SIGSYS
{ SIGSYS, 1, 0, 0, 0 }, { SIGSYS, C },
#endif
#ifdef SIGEMT
{ SIGEMT, C },
#endif
#ifdef SIGINFO
{ SIGINFO, Q + I + R },
#endif
#ifdef SIGTHR
{ SIGTHR, Q + I + R },
#endif #endif
{ -1, 0, 0, 0, 0 } { -1, 0 }
}; };
#undef C
#undef I
#undef R
#undef Q
#undef P
/* The Go signal handler. */ /* Handle a signal, for cases where we don't panic. We can split the
stack here. */
static void static void
sighandler (int sig) sig_handler (int sig)
{ {
const char *msg;
int i; int i;
#ifdef SIGPROF #ifdef SIGPROF
...@@ -131,47 +155,59 @@ sighandler (int sig) ...@@ -131,47 +155,59 @@ sighandler (int sig)
} }
#endif #endif
/* FIXME: Should check siginfo for more information when for (i = 0; runtime_sigtab[i].sig != -1; ++i)
available. */
msg = NULL;
switch (sig)
{ {
#ifdef SIGILL struct sigaction sa;
case SIGILL:
msg = "illegal instruction";
break;
#endif
#ifdef SIGBUS if (runtime_sigtab[i].sig != sig)
case SIGBUS: continue;
msg = "invalid memory address or nil pointer dereference";
break;
#endif
#ifdef SIGFPE if ((runtime_sigtab[i].flags & SigQueue) != 0)
case SIGFPE: {
msg = "integer divide by zero or floating point error"; if (__go_sigsend (sig)
break; || (runtime_sigtab[sig].flags & SigIgnore) != 0)
#endif return;
runtime_exit (2); // SIGINT, SIGTERM, etc
}
#ifdef SIGSEGV if (runtime_panicking)
case SIGSEGV: runtime_exit (2);
msg = "invalid memory address or nil pointer dereference"; runtime_panicking = 1;
break;
#endif
default: /* We should do a stack backtrace here. Until we can do that,
break; we reraise the signal in order to get a slightly better
report from the shell. */
memset (&sa, 0, sizeof sa);
sa.sa_handler = SIG_DFL;
i = sigemptyset (&sa.sa_mask);
__go_assert (i == 0);
if (sigaction (sig, &sa, NULL) != 0)
abort ();
raise (sig);
runtime_exit (2);
} }
if (msg != NULL) __builtin_unreachable ();
{ }
/* The start of handling a signal which panics. */
static void
sig_panic_leadin (int sig)
{
int i;
sigset_t clear; sigset_t clear;
if (runtime_m()->mallocing) if (runtime_m ()->mallocing)
{ {
fprintf (stderr, "caught signal while mallocing: %s\n", msg); runtime_printf ("caught signal while mallocing: %d\n", sig);
__go_assert (0); runtime_throw ("caught signal while mallocing");
} }
/* The signal handler blocked signals; unblock them. */ /* The signal handler blocked signals; unblock them. */
...@@ -179,51 +215,163 @@ sighandler (int sig) ...@@ -179,51 +215,163 @@ sighandler (int sig)
__go_assert (i == 0); __go_assert (i == 0);
i = sigprocmask (SIG_UNBLOCK, &clear, NULL); i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
__go_assert (i == 0); __go_assert (i == 0);
}
runtime_panicstring (msg); #ifdef SA_SIGINFO
}
for (i = 0; signals[i].sig != -1; ++i) /* Signal dispatch for signals which panic, on systems which support
{ SA_SIGINFO. This is called on the thread stack, and as such it is
if (signals[i].sig == sig) permitted to split the stack. */
{
struct sigaction sa;
if (signals[i].queue) static void
sig_panic_info_handler (int sig, siginfo_t *info,
void *context __attribute__ ((unused)))
{
if (runtime_g () == NULL)
{ {
if (__go_sigsend (sig) || signals[i].ignore) sig_handler (sig);
return; return;
runtime_exit (2); // SIGINT, SIGTERM, etc
} }
if (runtime_panicking) sig_panic_leadin (sig);
runtime_exit (2);
runtime_panicking = 1;
memset (&sa, 0, sizeof sa); switch (sig)
{
#ifdef SIGBUS
case SIGBUS:
if (info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
runtime_panicstring ("invalid memory address or "
"nil pointer dereference");
runtime_printf ("unexpected fault address %p\n", info->si_addr);
runtime_throw ("fault");
#endif
sa.sa_handler = SIG_DFL; #ifdef SIGSEGV
case SIGSEGV:
if ((info->si_code == 0
|| info->si_code == SEGV_MAPERR
|| info->si_code == SEGV_ACCERR)
&& (uintptr_t) info->si_addr < 0x1000)
runtime_panicstring ("invalid memory address or "
"nil pointer dereference");
runtime_printf ("unexpected fault address %p\n", info->si_addr);
runtime_throw ("fault");
#endif
i = sigemptyset (&sa.sa_mask); #ifdef SIGFPE
__go_assert (i == 0); case SIGFPE:
switch (info->si_code)
{
case FPE_INTDIV:
runtime_panicstring ("integer divide by zero");
case FPE_INTOVF:
runtime_panicstring ("integer overflow");
}
runtime_panicstring ("floating point error");
#endif
}
if (sigaction (sig, &sa, NULL) != 0) /* All signals with SigPanic should be in cases above, and this
abort (); handler should only be invoked for those signals. */
__builtin_unreachable ();
}
raise (sig); #else /* !defined (SA_SIGINFO) */
exit (2);
static void
sig_panic_handler (int sig)
{
if (runtime_g () == NULL)
{
sig_handler (sig);
return;
} }
sig_panic_leadin (sig);
switch (sig)
{
#ifdef SIGBUS
case SIGBUS:
runtime_panicstring ("invalid memory address or "
"nil pointer dereference");
#endif
#ifdef SIGSEGV
case SIGSEGV:
runtime_panicstring ("invalid memory address or "
"nil pointer dereference");
#endif
#ifdef SIGFPE
case SIGFPE:
runtime_panicstring ("integer divide by zero or floating point error");
#endif
} }
abort ();
/* All signals with SigPanic should be in cases above, and this
handler should only be invoked for those signals. */
__builtin_unreachable ();
} }
/* Ignore a signal. */ #endif /* !defined (SA_SIGINFO) */
/* Ignore a signal. This is called on the alternate signal stack so
it may not split the stack. */
static void sig_ignore (int) __attribute__ ((no_split_stack));
static void static void
sig_ignore (int sig __attribute__ ((unused))) sig_ignore (int sig __attribute__ ((unused)))
{ {
} }
/* A signal handler used for signals which are not going to panic.
This is called on the alternate signal stack so it may not split
the stack. */
static void
sig_tramp (int) __attribute__ ((no_split_stack));
static void
sig_tramp (int sig)
{
G *gp;
M *mp;
/* We are now running on the stack registered via sigaltstack.
(Actually there is a small span of time between runtime_siginit
and sigaltstack when the program starts.) */
gp = runtime_g ();
mp = runtime_m ();
if (gp != NULL)
__splitstack_getcontext (&gp->stack_context[0]);
if (gp != NULL && mp->gsignal != NULL)
{
/* We are running on the signal stack. Set the split stack
context so that the stack guards are checked correctly. */
#ifdef USING_SPLIT_STACK
__splitstack_setcontext (&mp->gsignal->stack_context[0]);
#endif
}
sig_handler (sig);
/* We are going to return back to the signal trampoline and then to
whatever we were doing before we got the signal. Restore the
split stack context so that stack guards are checked
correctly. */
if (gp != NULL)
{
#ifdef USING_SPLIT_STACK
__splitstack_setcontext (&gp->stack_context[0]);
#endif
}
}
/* Initialize signal handling for Go. This is called when the program /* Initialize signal handling for Go. This is called when the program
starts. */ starts. */
...@@ -237,21 +385,44 @@ runtime_initsig (int32 queue) ...@@ -237,21 +385,44 @@ runtime_initsig (int32 queue)
memset (&sa, 0, sizeof sa); memset (&sa, 0, sizeof sa);
sa.sa_handler = sighandler;
i = sigfillset (&sa.sa_mask); i = sigfillset (&sa.sa_mask);
__go_assert (i == 0); __go_assert (i == 0);
for (i = 0; signals[i].sig != -1; ++i) for (i = 0; runtime_sigtab[i].sig != -1; ++i)
{ {
if (signals[i].queue != (queue ? 1 : 0)) if (runtime_sigtab[i].flags == 0)
continue;
if ((runtime_sigtab[i].flags & SigQueue) != queue)
continue; continue;
if (signals[i].catch || signals[i].queue)
sa.sa_handler = sighandler; if ((runtime_sigtab[i].flags & (SigCatch | SigQueue)) != 0)
{
if ((runtime_sigtab[i].flags & SigPanic) == 0)
{
sa.sa_flags = SA_ONSTACK;
sa.sa_handler = sig_tramp;
}
else else
{
#ifdef SA_SIGINFO
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sig_panic_info_handler;
#else
sa.sa_flags = 0;
sa.sa_handler = sig_panic_handler;
#endif
}
}
else
{
sa.sa_flags = SA_ONSTACK;
sa.sa_handler = sig_ignore; sa.sa_handler = sig_ignore;
sa.sa_flags = signals[i].restart ? SA_RESTART : 0; }
if (sigaction (signals[i].sig, &sa, NULL) != 0)
if ((runtime_sigtab[i].flags & SigRestart) != 0)
sa.sa_flags |= SA_RESTART;
if (sigaction (runtime_sigtab[i].sig, &sa, NULL) != 0)
__go_assert (0); __go_assert (0);
} }
} }
...@@ -281,7 +452,7 @@ runtime_resetcpuprofiler(int32 hz) ...@@ -281,7 +452,7 @@ runtime_resetcpuprofiler(int32 hz)
} }
else else
{ {
sa.sa_handler = sighandler; sa.sa_handler = sig_handler;
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
i = sigaction (SIGPROF, &sa, NULL); i = sigaction (SIGPROF, &sa, NULL);
__go_assert (i == 0); __go_assert (i == 0);
......
...@@ -47,7 +47,7 @@ runtime_SysAlloc(uintptr n) ...@@ -47,7 +47,7 @@ runtime_SysAlloc(uintptr n)
if (dev_zero == -1) { if (dev_zero == -1) {
dev_zero = open("/dev/zero", O_RDONLY); dev_zero = open("/dev/zero", O_RDONLY);
if (dev_zero < 0) { if (dev_zero < 0) {
printf("open /dev/zero: errno=%d\n", errno); runtime_printf("open /dev/zero: errno=%d\n", errno);
exit(2); exit(2);
} }
} }
...@@ -57,8 +57,8 @@ runtime_SysAlloc(uintptr n) ...@@ -57,8 +57,8 @@ runtime_SysAlloc(uintptr n)
p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0); p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0);
if (p == MAP_FAILED) { if (p == MAP_FAILED) {
if(errno == EACCES) { if(errno == EACCES) {
printf("runtime: mmap: access denied\n"); runtime_printf("runtime: mmap: access denied\n");
printf("if you're running SELinux, enable execmem for this process.\n"); runtime_printf("if you're running SELinux, enable execmem for this process.\n");
exit(2); exit(2);
} }
return nil; return nil;
...@@ -97,7 +97,7 @@ runtime_SysReserve(void *v, uintptr n) ...@@ -97,7 +97,7 @@ runtime_SysReserve(void *v, uintptr n)
if (dev_zero == -1) { if (dev_zero == -1) {
dev_zero = open("/dev/zero", O_RDONLY); dev_zero = open("/dev/zero", O_RDONLY);
if (dev_zero < 0) { if (dev_zero < 0) {
printf("open /dev/zero: errno=%d\n", errno); runtime_printf("open /dev/zero: errno=%d\n", errno);
exit(2); exit(2);
} }
} }
...@@ -123,7 +123,7 @@ runtime_SysMap(void *v, uintptr n) ...@@ -123,7 +123,7 @@ runtime_SysMap(void *v, uintptr n)
if (dev_zero == -1) { if (dev_zero == -1) {
dev_zero = open("/dev/zero", O_RDONLY); dev_zero = open("/dev/zero", O_RDONLY);
if (dev_zero < 0) { if (dev_zero < 0) {
printf("open /dev/zero: errno=%d\n", errno); runtime_printf("open /dev/zero: errno=%d\n", errno);
exit(2); exit(2);
} }
} }
......
...@@ -29,6 +29,11 @@ extern void * __splitstack_resetcontext(void *context[10], size_t *); ...@@ -29,6 +29,11 @@ extern void * __splitstack_resetcontext(void *context[10], size_t *);
extern void *__splitstack_find(void *, void *, size_t *, void **, void **, extern void *__splitstack_find(void *, void *, size_t *, void **, void **,
void **); void **);
extern void __splitstack_block_signals (int *, int *);
extern void __splitstack_block_signals_context (void *context[10], int *,
int *);
#endif #endif
#if defined(USING_SPLIT_STACK) && defined(LINKER_SUPPORTS_SPLIT_STACK) #if defined(USING_SPLIT_STACK) && defined(LINKER_SUPPORTS_SPLIT_STACK)
...@@ -862,6 +867,14 @@ runtime_mstart(void* mp) ...@@ -862,6 +867,14 @@ runtime_mstart(void* mp)
*(int*)0x21 = 0x21; *(int*)0x21 = 0x21;
} }
runtime_minit(); runtime_minit();
#ifdef USING_SPLIT_STACK
{
int dont_block_signals = 0;
__splitstack_block_signals(&dont_block_signals, nil);
}
#endif
schedule(nil); schedule(nil);
return nil; return nil;
} }
...@@ -1142,9 +1155,13 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) ...@@ -1142,9 +1155,13 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize)
newg = runtime_malloc(sizeof(G)); newg = runtime_malloc(sizeof(G));
if(stacksize >= 0) { if(stacksize >= 0) {
#if USING_SPLIT_STACK #if USING_SPLIT_STACK
int dont_block_signals = 0;
*ret_stack = __splitstack_makecontext(stacksize, *ret_stack = __splitstack_makecontext(stacksize,
&newg->stack_context[0], &newg->stack_context[0],
ret_stacksize); ret_stacksize);
__splitstack_block_signals_context(&newg->stack_context[0],
&dont_block_signals, nil);
#else #else
*ret_stack = runtime_mallocgc(stacksize, FlagNoProfiling|FlagNoGC, 0, 0); *ret_stack = runtime_mallocgc(stacksize, FlagNoProfiling|FlagNoGC, 0, 0);
*ret_stacksize = stacksize; *ret_stacksize = stacksize;
...@@ -1186,8 +1203,12 @@ __go_go(void (*fn)(void*), void* arg) ...@@ -1186,8 +1203,12 @@ __go_go(void (*fn)(void*), void* arg)
if((newg = gfget()) != nil){ if((newg = gfget()) != nil){
#ifdef USING_SPLIT_STACK #ifdef USING_SPLIT_STACK
int dont_block_signals = 0;
sp = __splitstack_resetcontext(&newg->stack_context[0], sp = __splitstack_resetcontext(&newg->stack_context[0],
&spsize); &spsize);
__splitstack_block_signals_context(&newg->stack_context[0],
&dont_block_signals, nil);
#else #else
sp = newg->gcinitial_sp; sp = newg->gcinitial_sp;
spsize = newg->gcstack_size; spsize = newg->gcstack_size;
......
...@@ -52,6 +52,7 @@ typedef struct G G; ...@@ -52,6 +52,7 @@ typedef struct G G;
typedef union Lock Lock; typedef union Lock Lock;
typedef struct M M; typedef struct M M;
typedef union Note Note; typedef union Note Note;
typedef struct SigTab SigTab;
typedef struct MCache MCache; typedef struct MCache MCache;
typedef struct FixAlloc FixAlloc; typedef struct FixAlloc FixAlloc;
typedef struct Hchan Hchan; typedef struct Hchan Hchan;
...@@ -179,6 +180,20 @@ struct M ...@@ -179,6 +180,20 @@ struct M
uint32 waitsemalock; uint32 waitsemalock;
}; };
struct SigTab
{
int32 sig;
int32 flags;
};
enum
{
SigCatch = 1<<0,
SigIgnore = 1<<1,
SigRestart = 1<<2,
SigQueue = 1<<3,
SigPanic = 1<<4,
};
/* Macros. */ /* Macros. */
#ifdef __WINDOWS__ #ifdef __WINDOWS__
...@@ -251,7 +266,7 @@ void runtime_args(int32, byte**); ...@@ -251,7 +266,7 @@ void runtime_args(int32, byte**);
void runtime_osinit(); void runtime_osinit();
void runtime_goargs(void); void runtime_goargs(void);
void runtime_goenvs(void); void runtime_goenvs(void);
void runtime_throw(const char*); void runtime_throw(const char*) __attribute__ ((noreturn));
void runtime_panicstring(const char*) __attribute__ ((noreturn)); void runtime_panicstring(const char*) __attribute__ ((noreturn));
void* runtime_mal(uintptr); void* runtime_mal(uintptr);
void runtime_schedinit(void); void runtime_schedinit(void);
......
...@@ -110,6 +110,6 @@ func Signame(sig int32) (name String) { ...@@ -110,6 +110,6 @@ func Signame(sig int32) (name String) {
} }
func Siginit() { func Siginit() {
runtime_initsig(1); runtime_initsig(SigQueue);
sig.inuse = true; // enable reception of signals; cannot disable sig.inuse = true; // enable reception of signals; cannot disable
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment