diff options
Diffstat (limited to 'libgo/go/runtime/panic.go')
-rw-r--r-- | libgo/go/runtime/panic.go | 170 |
1 files changed, 139 insertions, 31 deletions
diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go index 88c0a4d..5868430 100644 --- a/libgo/go/runtime/panic.go +++ b/libgo/go/runtime/panic.go @@ -23,81 +23,189 @@ import ( //go:linkname makefuncreturning runtime.makefuncreturning //go:linkname gorecover runtime.gorecover //go:linkname deferredrecover runtime.deferredrecover +//go:linkname goPanicIndex runtime.goPanicIndex +//go:linkname goPanicIndexU runtime.goPanicIndexU +//go:linkname goPanicSliceAlen runtime.goPanicSliceAlen +//go:linkname goPanicSliceAlenU runtime.goPanicSliceAlenU +//go:linkname goPanicSliceAcap runtime.goPanicSliceAcap +//go:linkname goPanicSliceAcapU runtime.goPanicSliceAcapU +//go:linkname goPanicSliceB runtime.goPanicSliceB +//go:linkname goPanicSliceBU runtime.goPanicSliceBU +//go:linkname goPanicSlice3Alen runtime.goPanicSlice3Alen +//go:linkname goPanicSlice3AlenU runtime.goPanicSlice3AlenU +//go:linkname goPanicSlice3Acap runtime.goPanicSlice3Acap +//go:linkname goPanicSlice3AcapU runtime.goPanicSlice3AcapU +//go:linkname goPanicSlice3B runtime.goPanicSlice3B +//go:linkname goPanicSlice3BU runtime.goPanicSlice3BU +//go:linkname goPanicSlice3C runtime.goPanicSlice3C +//go:linkname goPanicSlice3CU runtime.goPanicSlice3CU //go:linkname panicmem runtime.panicmem // Temporary for C code to call: //go:linkname throw runtime.throw -// Calling panic with one of the errors below will call errorString.Error -// which will call mallocgc to concatenate strings. That will fail if -// malloc is locked, causing a confusing error message. Throw a better -// error message instead. -func panicCheckMalloc(err error) { +// Check to make sure we can really generate a panic. If the panic +// was generated from the runtime, or from inside malloc, then convert +// to a throw of msg. +// pc should be the program counter of the compiler-generated code that +// triggered this panic. +func panicCheck1(pc uintptr, msg string) { + name, _, _, _ := funcfileline(pc-1, -1) + if hasPrefix(name, "runtime.") { + throw(msg) + } + // TODO: is this redundant? How could we be in malloc + // but not in the runtime? runtime/internal/*, maybe? gp := getg() if gp != nil && gp.m != nil && gp.m.mallocing != 0 { - throw(string(err.(errorString))) + throw(msg) } } -var indexError = error(errorString("index out of range")) +// Same as above, but calling from the runtime is allowed. +// +// Using this function is necessary for any panic that may be +// generated by runtime.sigpanic, since those are always called by the +// runtime. +func panicCheck2(err string) { + // panic allocates, so to avoid recursive malloc, turn panics + // during malloc into throws. + gp := getg() + if gp != nil && gp.m != nil && gp.m.mallocing != 0 { + throw(err) + } +} -// The panicindex, panicslice, and panicdivide functions are called by +// Many of the following panic entry-points turn into throws when they +// happen in various runtime contexts. These should never happen in +// the runtime, and if they do, they indicate a serious issue and +// should not be caught by user code. +// +// The panic{Index,Slice,divide,shift} functions are called by // code generated by the compiler for out of bounds index expressions, -// out of bounds slice expressions, and division by zero. The -// panicdivide (again), panicoverflow, panicfloat, and panicmem +// out of bounds slice expressions, division by zero, and shift by negative. +// The panicdivide (again), panicoverflow, panicfloat, and panicmem // functions are called by the signal handler when a signal occurs // indicating the respective problem. // -// Since panicindex and panicslice are never called directly, and +// Since panic{Index,Slice,shift} are never called directly, and // since the runtime package should never have an out of bounds slice -// or array reference, if we see those functions called from the +// or array reference or negative shift, if we see those functions called from the // runtime package we turn the panic into a throw. That will dump the // entire runtime stack for easier debugging. +// +// The entry points called by the signal handler will be called from +// runtime.sigpanic, so we can't disallow calls from the runtime to +// these (they always look like they're called from the runtime). +// Hence, for these, we just check for clearly bad runtime conditions. + +// failures in the comparisons for s[x], 0 <= x < y (y == len(s)) +func goPanicIndex(x int, y int) { + panicCheck1(getcallerpc(), "index out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsIndex}) +} +func goPanicIndexU(x uint, y int) { + panicCheck1(getcallerpc(), "index out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex}) +} -func panicindex() { - name, _, _, _ := funcfileline(getcallerpc()-1, -1) - if hasPrefix(name, "runtime.") { - throw(string(indexError.(errorString))) - } - panicCheckMalloc(indexError) - panic(indexError) +// failures in the comparisons for s[:x], 0 <= x <= y (y == len(s) or cap(s)) +func goPanicSliceAlen(x int, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAlen}) +} +func goPanicSliceAlenU(x uint, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen}) +} +func goPanicSliceAcap(x int, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAcap}) +} +func goPanicSliceAcapU(x uint, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap}) } -var sliceError = error(errorString("slice bounds out of range")) +// failures in the comparisons for s[x:y], 0 <= x <= y +func goPanicSliceB(x int, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceB}) +} +func goPanicSliceBU(x uint, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB}) +} -func panicslice() { - name, _, _, _ := funcfileline(getcallerpc()-1, -1) - if hasPrefix(name, "runtime.") { - throw(string(sliceError.(errorString))) - } - panicCheckMalloc(sliceError) - panic(sliceError) +// failures in the comparisons for s[::x], 0 <= x <= y (y == len(s) or cap(s)) +func goPanicSlice3Alen(x int, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Alen}) +} +func goPanicSlice3AlenU(x uint, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen}) +} +func goPanicSlice3Acap(x int, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Acap}) +} +func goPanicSlice3AcapU(x uint, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap}) +} + +// failures in the comparisons for s[:x:y], 0 <= x <= y +func goPanicSlice3B(x int, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3B}) +} +func goPanicSlice3BU(x uint, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B}) +} + +// failures in the comparisons for s[x:y:], 0 <= x <= y +func goPanicSlice3C(x int, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3C}) +} +func goPanicSlice3CU(x uint, y int) { + panicCheck1(getcallerpc(), "slice bounds out of range") + panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C}) +} + +var shiftError = error(errorString("negative shift amount")) + +func panicshift() { + panicCheck1(getcallerpc(), "negative shift amount") + panic(shiftError) } var divideError = error(errorString("integer divide by zero")) func panicdivide() { - panicCheckMalloc(divideError) + panicCheck2("integer divide by zero") panic(divideError) } var overflowError = error(errorString("integer overflow")) func panicoverflow() { - panicCheckMalloc(overflowError) + panicCheck2("integer overflow") panic(overflowError) } var floatError = error(errorString("floating point error")) func panicfloat() { - panicCheckMalloc(floatError) + panicCheck2("floating point error") panic(floatError) } var memoryError = error(errorString("invalid memory address or nil pointer dereference")) func panicmem() { - panicCheckMalloc(memoryError) + panicCheck2("invalid memory address or nil pointer dereference") panic(memoryError) } |