From: Russ Cox Date: Fri, 20 Sep 2013 19:15:25 +0000 (-0400) Subject: runtime: avoid allocation of internal panic values X-Git-Tag: go1.2rc2~158 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=551ada4742d3df6a24ddab5516fc8646c8a28958;p=gostls13.git runtime: avoid allocation of internal panic values 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 --- diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go index b6b520cf27..bd70908839 100644 --- a/src/pkg/runtime/error.go +++ b/src/pkg/runtime/error.go @@ -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 } diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c index a1e91d3d8f..8227a444d3 100644 --- a/src/pkg/runtime/panic.c +++ b/src/pkg/runtime/panic.c @@ -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); } diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index e34e9e5067..d5fc2dcac5 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -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(); diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 66e87d5c27..c989edcf8d 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -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*); diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc index 5d472208bf..b79acbe1c2 100644 --- a/src/pkg/runtime/string.goc +++ b/src/pkg/runtime/string.goc @@ -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) {