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
This commit is contained in:
Russ Cox 2013-09-20 15:15:25 -04:00
parent 81dc0b65b2
commit 551ada4742
5 changed files with 36 additions and 1 deletions

View 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
}

View 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);
}

View 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();

View 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*);

View 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)
{