From: Dmitriy Vyukov Date: Thu, 13 Mar 2014 09:25:59 +0000 (+0400) Subject: runtime: harden conditions when runtime panics on crash X-Git-Tag: go1.3beta1~367 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=156962872575382697a0487030cd5777312d6d0c;p=gostls13.git runtime: harden conditions when runtime panics on crash This is especially important for SetPanicOnCrash, but also useful for e.g. nil deref in mallocgc. Panics on such crashes can't lead to anything useful, only to deadlocks, hangs and obscure crashes. This is a copy of broken but already LGTMed https://golang.org/cl/68540043/ TBR=rsc R=rsc CC=golang-codereviews https://golang.org/cl/75320043 --- diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c index 29bf7de27f..d35f7800a3 100644 --- a/src/pkg/runtime/panic.c +++ b/src/pkg/runtime/panic.c @@ -485,6 +485,29 @@ runtime·throwinit(void) runtime·throw("recursive call during initialization - linker skew"); } +bool +runtime·canpanic(G *gp) +{ + byte g; + + USED(&g); // don't use global g, it points to gsignal + + // Is it okay for gp to panic instead of crashing the program? + // Yes, as long as it is running Go code, not runtime code, + // and not stuck in a system call. + if(gp == nil || gp != m->curg) + return false; + if(m->locks != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0) + return false; + if(gp->status != Grunning || gp->syscallsp != 0) + return false; +#ifdef GOOS_windows + if(m->libcallsp != 0) + return false; +#endif + return true; +} + void runtime·throw(int8 *s) { diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 0682a8026a..ecff533f59 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -836,6 +836,7 @@ void runtime·goenvs_unix(void); void* runtime·getu(void); void runtime·throw(int8*); void runtime·panicstring(int8*); +bool runtime·canpanic(G*); void runtime·prints(int8*); void runtime·printf(int8*, ...); byte* runtime·mchr(byte*, byte, byte*); diff --git a/src/pkg/runtime/signal_386.c b/src/pkg/runtime/signal_386.c index 829f389cc2..70790fa0a3 100644 --- a/src/pkg/runtime/signal_386.c +++ b/src/pkg/runtime/signal_386.c @@ -45,7 +45,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) t = &runtime·sigtab[sig]; if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) + if(!runtime·canpanic(gp)) goto Throw; // Make it look like a call to the signal func. diff --git a/src/pkg/runtime/signal_amd64x.c b/src/pkg/runtime/signal_amd64x.c index 871891ad18..b217338711 100644 --- a/src/pkg/runtime/signal_amd64x.c +++ b/src/pkg/runtime/signal_amd64x.c @@ -54,7 +54,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) t = &runtime·sigtab[sig]; if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) + if(!runtime·canpanic(gp)) goto Throw; // Make it look like a call to the signal func. diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c index 563f1f2bef..41997dbd85 100644 --- a/src/pkg/runtime/signal_arm.c +++ b/src/pkg/runtime/signal_arm.c @@ -52,7 +52,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) t = &runtime·sigtab[sig]; if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) + if(!runtime·canpanic(gp)) goto Throw; // Make it look like a call to the signal func.