mirror of
https://github.com/golang/go
synced 2024-11-12 05:40:22 -07:00
runtime/debug: add SetPanicOnFault
SetPanicOnFault allows recovery from unexpected memory faults. This can be useful if you are using a memory-mapped file or probing the address space of the current program. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/66590044
This commit is contained in:
parent
67c83db60d
commit
e56c6e7535
@ -8,3 +8,4 @@ testing: add b.RunParallel function (CL 57270043)
|
||||
misc/benchcmp has been replaced by go tool benchcmp (CL 47980043)
|
||||
cmd/go, go/build: support .m files (CL 60590044)
|
||||
unicode: upgrade from Unicode 6.2.0 to 6.3.0 (CL 65400044)
|
||||
runtime/debug: add SetPanicOnFault (CL 66590044)
|
||||
|
@ -135,3 +135,14 @@ func SetMaxStack(bytes int) int {
|
||||
func SetMaxThreads(threads int) int {
|
||||
return setMaxThreads(threads)
|
||||
}
|
||||
|
||||
// SetPanicOnFault controls the runtime's behavior when a program faults
|
||||
// at an unexpected (non-nil) address. Such faults are typically caused by
|
||||
// bugs such as runtime memory corruption, so the default response is to crash
|
||||
// the program. Programs working with memory-mapped files or unsafe
|
||||
// manipulation of memory may cause faults at non-nil addresses in less
|
||||
// dramatic situations; SetPanicOnFault allows such programs to request
|
||||
// that the runtime trigger only a panic, not a crash.
|
||||
// SetPanicOnFault applies only to the current goroutine.
|
||||
// It returns the previous setting.
|
||||
func SetPanicOnFault(enabled bool) bool
|
||||
|
@ -436,7 +436,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case SIGBUS:
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
@ -444,7 +444,7 @@ runtime·sigpanic(void)
|
||||
runtime·printf("unexpected fault address %p\n", g->sigcode1);
|
||||
runtime·throw("fault");
|
||||
case SIGSEGV:
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -171,7 +171,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case SIGBUS:
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
@ -179,7 +179,7 @@ runtime·sigpanic(void)
|
||||
runtime·printf("unexpected fault address %p\n", g->sigcode1);
|
||||
runtime·throw("fault");
|
||||
case SIGSEGV:
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -179,7 +179,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case SIGBUS:
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
@ -187,7 +187,7 @@ runtime·sigpanic(void)
|
||||
runtime·printf("unexpected fault address %p\n", g->sigcode1);
|
||||
runtime·throw("fault");
|
||||
case SIGSEGV:
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -220,7 +220,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case SIGBUS:
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
@ -228,7 +228,7 @@ runtime·sigpanic(void)
|
||||
runtime·printf("unexpected fault address %p\n", g->sigcode1);
|
||||
runtime·throw("fault");
|
||||
case SIGSEGV:
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -239,7 +239,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case SIGBUS:
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
@ -247,7 +247,7 @@ runtime·sigpanic(void)
|
||||
runtime·printf("unexpected fault address %p\n", g->sigcode1);
|
||||
runtime·throw("fault");
|
||||
case SIGSEGV:
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -216,7 +216,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case SIGBUS:
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
@ -224,7 +224,7 @@ runtime·sigpanic(void)
|
||||
runtime·printf("unexpected fault address %p\n", g->sigcode1);
|
||||
runtime·throw("fault");
|
||||
case SIGSEGV:
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -211,7 +211,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case SIGBUS:
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
@ -219,7 +219,7 @@ runtime·sigpanic(void)
|
||||
runtime·printf("unexpected fault address %p\n", g->sigcode1);
|
||||
runtime·throw("fault");
|
||||
case SIGSEGV:
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
|
||||
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -348,7 +348,7 @@ runtime·sigpanic(void)
|
||||
{
|
||||
switch(g->sig) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
if(g->sigcode1 < 0x1000) {
|
||||
if(g->sigcode1 < 0x1000 || g->paniconfault) {
|
||||
if(g->sigpc == 0)
|
||||
runtime·panicstring("call of nil func value");
|
||||
runtime·panicstring("invalid memory address or nil pointer dereference");
|
||||
|
@ -1449,6 +1449,7 @@ goexit0(G *gp)
|
||||
gp->status = Gdead;
|
||||
gp->m = nil;
|
||||
gp->lockedm = nil;
|
||||
gp->paniconfault = 0;
|
||||
m->curg = nil;
|
||||
m->lockedg = nil;
|
||||
if(m->locked & ~LockExternal) {
|
||||
|
@ -20,3 +20,8 @@ func setGCPercent(in int) (out int) {
|
||||
func setMaxThreads(in int) (out int) {
|
||||
out = runtime·setmaxthreads(in);
|
||||
}
|
||||
|
||||
func SetPanicOnFault(enabled bool) (old bool) {
|
||||
old = g->paniconfault;
|
||||
g->paniconfault = enabled;
|
||||
}
|
||||
|
@ -273,6 +273,7 @@ struct G
|
||||
bool issystem; // do not output in stack dump
|
||||
bool isbackground; // ignore in deadlock detector
|
||||
bool preempt; // preemption signal, duplicates stackguard0 = StackPreempt
|
||||
bool paniconfault; // panic (instead of crash) on unexpected fault address
|
||||
int8 raceignore; // ignore race detection events
|
||||
M* m; // for debuggers, but offset not hard-coded
|
||||
M* lockedm;
|
||||
|
@ -10,9 +10,11 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
. "runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var errf error
|
||||
@ -131,3 +133,19 @@ func TestRuntimeGogoBytes(t *testing.T) {
|
||||
func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
|
||||
SetCPUProfileRate(0)
|
||||
}
|
||||
|
||||
func TestSetPanicOnFault(t *testing.T) {
|
||||
old := debug.SetPanicOnFault(true)
|
||||
defer debug.SetPanicOnFault(old)
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err == nil {
|
||||
t.Fatalf("did not find error in recover")
|
||||
}
|
||||
}()
|
||||
|
||||
var p *int
|
||||
p = (*int)(unsafe.Pointer(^uintptr(0)))
|
||||
println(*p)
|
||||
t.Fatalf("still here - should have faulted")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user