]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: avoid allocation of internal panic values
authorRuss Cox <rsc@golang.org>
Fri, 20 Sep 2013 19:15:25 +0000 (15:15 -0400)
committerRuss Cox <rsc@golang.org>
Fri, 20 Sep 2013 19:15:25 +0000 (15:15 -0400)
If a fault happens in malloc, inevitably the next thing that happens
is a deadlock trying to allocate the panic value that says the fault
happened. Stop doing that, two ways.

First, reject panic in malloc just as we reject panic in garbage collection.

Second, runtime.panicstring was using an error implementation
backed by a Go string, so the interface held an allocated *string.
Since the actual errors are C strings, define a new error
implementation backed by a C char*, which needs no indirection
and therefore no allocation.

This second fix will avoid allocation for errors like nil panic derefs
or division by zero, so it is worth doing even though the first fix
should take care of faults during malloc.

Update #6419

R=golang-dev, dvyukov, dave
CC=golang-dev
https://golang.org/cl/13774043

src/pkg/runtime/error.go
src/pkg/runtime/panic.c
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.h
src/pkg/runtime/string.goc

index b6b520cf27b3cd5eb14a4ef297a54ae1888a49d0..bd70908839e18b0cccb36863c0c4fbb7771d48b4 100644 (file)
@@ -74,6 +74,22 @@ func newErrorString(s string, ret *interface{}) {
        *ret = errorString(s)
 }
 
+// An errorCString represents a runtime error described by a single C string.
+type errorCString uintptr
+
+func (e errorCString) RuntimeError() {}
+
+func cstringToGo(uintptr) string
+
+func (e errorCString) Error() string {
+       return "runtime error: " + cstringToGo(uintptr(e))
+}
+
+// For calling from C.
+func newErrorCString(s uintptr, ret *interface{}) {
+       *ret = errorCString(s)
+}
+
 type stringer interface {
        String() string
 }
index a1e91d3d8f04a7d0d486733d2748c6289e8d05c0..8227a444d30db3575e14dd5447421f620902d741 100644 (file)
@@ -470,11 +470,15 @@ runtime·panicstring(int8 *s)
 {
        Eface err;
 
+       if(m->mallocing) {
+               runtime·printf("panic: %s\n", s);
+               runtime·throw("panic during malloc");
+       }
        if(m->gcing) {
                runtime·printf("panic: %s\n", s);
                runtime·throw("panic during gc");
        }
-       runtime·newErrorString(runtime·gostringnocopy((byte*)s), &err);
+       runtime·newErrorCString(s, &err);
        runtime·panic(err);
 }
 
index e34e9e5067bb1fd1ad92a7f4d87d0d424f6d2967..d5fc2dcac5f373f65d7592cfc6caab1078f9979b 100644 (file)
@@ -128,6 +128,7 @@ runtime·schedinit(void)
 {
        int32 n, procs;
        byte *p;
+       Eface i;
 
        runtime·sched.maxmcount = 10000;
        runtime·precisestack = haveexperiment("precisestack");
@@ -136,6 +137,12 @@ runtime·schedinit(void)
        runtime·mprofinit();
        runtime·mallocinit();
        mcommoninit(m);
+       
+       // Initialize the itable value for newErrorCString,
+       // so that the next time it gets called, possibly
+       // in a fault during a garbage collection, it will not
+       // need to allocated memory.
+       runtime·newErrorCString(0, &i);
 
        runtime·goargs();
        runtime·goenvs();
index 66e87d5c27c62caa6c230d95c6efd756c9dcdc32..c989edcf8d09809ecd0e84639cc4267682e721f9 100644 (file)
@@ -1004,6 +1004,7 @@ void      runtime·panicslice(void);
 void   runtime·printany(Eface);
 void   runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*);
 void   runtime·newErrorString(String, Eface*);
+void   runtime·newErrorCString(int8*, Eface*);
 void   runtime·fadd64c(uint64, uint64, uint64*);
 void   runtime·fsub64c(uint64, uint64, uint64*);
 void   runtime·fmul64c(uint64, uint64, uint64*);
index 5d472208bf1a5ec6f20aa818a9f59e6fbe22707f..b79acbe1c2f3e058b76757e3e1c9db9e01b51000 100644 (file)
@@ -102,6 +102,13 @@ runtime·gostringnocopy(byte *str)
        return s;
 }
 
+void
+runtime·cstringToGo(byte *str, String s)
+{
+       s = runtime·gostringnocopy(str);
+       FLUSH(&s);
+}
+
 String
 runtime·gostringw(uint16 *str)
 {