]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/debug: add SetPanicOnFault
authorRuss Cox <rsc@golang.org>
Thu, 20 Feb 2014 21:18:05 +0000 (16:18 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 20 Feb 2014 21:18:05 +0000 (16:18 -0500)
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

14 files changed:
doc/go1.3.txt
src/pkg/runtime/debug/garbage.go
src/pkg/runtime/os_darwin.c
src/pkg/runtime/os_dragonfly.c
src/pkg/runtime/os_freebsd.c
src/pkg/runtime/os_linux.c
src/pkg/runtime/os_netbsd.c
src/pkg/runtime/os_openbsd.c
src/pkg/runtime/os_solaris.c
src/pkg/runtime/os_windows.c
src/pkg/runtime/proc.c
src/pkg/runtime/rdebug.goc
src/pkg/runtime/runtime.h
src/pkg/runtime/runtime_test.go

index 31dfd38a101d4f563fea2e1c7aaf4b6870f5b8d8..613d261974a7f49378d0e8750a8a55b43d979605 100644 (file)
@@ -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)
index a724fdf8f605c0d9db6de26472aa4fc95a631cb5..093e7e7b1807446f6d3bccfcdd57d25998abc5bb 100644 (file)
@@ -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
index 5a38a77a3298a858be52eacc1d66baa53e9e411f..f2262618db50b4dddfc08088a0e6125fe836bedb 100644 (file)
@@ -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");
index ade3adb26def5c2a7d3ee09889cb07740af57b14..f96ea894842f34d9743ba25ac5e56ecb4b41edfc 100644 (file)
@@ -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");
index 442c6d76703b382010493f6d891bf32d3c50599e..8b7b0f6263272b1ae03082daaa948fc7c2aed54e 100644 (file)
@@ -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");
index 130e1059ec8df53b7749594e661eb21b49f2b336..b4be9406ec49184ad02e9d9a578698c427912aa6 100644 (file)
@@ -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");
index 745818183f7ef43eaba873ae3156e6886f0860f4..f8ae30985729734c1de68aadf94fa6ec906f110d 100644 (file)
@@ -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");
index 45f5040c9f8b4b5200edbab1dbb9dc0a4cdf233d..c16276aca023207dc434af646da2df0416b371e6 100644 (file)
@@ -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");
index 4e212f544d0b193de570fcf72d1ad7c645c01fa8..b8cd4d90cac8177cf2c14349415b81f9e49516d0 100644 (file)
@@ -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");
index 8815aee9f94c54c39cb1dddf1a54730e178e6964..a84b4e2830108fbdbdf8397bc0e412e09ce55662 100644 (file)
@@ -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");
index 7799dc8b52b4d8a196591408acb6d7b5a65cd178..986136d7e6afdb4a47ccd4ebecc3b6f07765bbe0 100644 (file)
@@ -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) {
index e5b57c481bc74b073dda2b2161d7f0f3e783f589..042b30ace9b653ab5a2b46ade06eb3082a42aff1 100644 (file)
@@ -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;
+}
index 3d5b6007a897c5087402ddd88cb4cab277fd0a82..8d07294e81b91b95619d334702d4894e6e68f776 100644 (file)
@@ -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;
index c673275620b609c84985304b265c0dc5c9d4e23e..83489480da69f723e2f0e36e5601cc51542c1bf8 100644 (file)
@@ -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")
+}