Commit e4f1d9cf authored by Emmanuel Odeke's avatar Emmanuel Odeke Committed by Brad Fitzpatrick

runtime: make execution error panic values implement the Error interface

Make execution panics implement Error as
mandated by https://golang.org/ref/spec#Run_time_panics,
instead of panics with strings.

Fixes #14965

Change-Id: I7827f898b9b9c08af541db922cc24fa0800ff18a
Reviewed-on: https://go-review.googlesource.com/21214Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 824d8c10
...@@ -64,7 +64,7 @@ func makechan(t *chantype, size int64) *hchan { ...@@ -64,7 +64,7 @@ func makechan(t *chantype, size int64) *hchan {
throw("makechan: bad alignment") throw("makechan: bad alignment")
} }
if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/elem.size) { if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/elem.size) {
panic("makechan: size out of range") panic(plainError("makechan: size out of range"))
} }
var c *hchan var c *hchan
...@@ -171,7 +171,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -171,7 +171,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
if c.closed != 0 { if c.closed != 0 {
unlock(&c.lock) unlock(&c.lock)
panic("send on closed channel") panic(plainError("send on closed channel"))
} }
if sg := c.recvq.dequeue(); sg != nil { if sg := c.recvq.dequeue(); sg != nil {
...@@ -231,7 +231,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -231,7 +231,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
if c.closed == 0 { if c.closed == 0 {
throw("chansend: spurious wakeup") throw("chansend: spurious wakeup")
} }
panic("send on closed channel") panic(plainError("send on closed channel"))
} }
gp.param = nil gp.param = nil
if mysg.releasetime > 0 { if mysg.releasetime > 0 {
...@@ -302,13 +302,13 @@ func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) { ...@@ -302,13 +302,13 @@ func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {
func closechan(c *hchan) { func closechan(c *hchan) {
if c == nil { if c == nil {
panic("close of nil channel") panic(plainError("close of nil channel"))
} }
lock(&c.lock) lock(&c.lock)
if c.closed != 0 { if c.closed != 0 {
unlock(&c.lock) unlock(&c.lock)
panic("close of closed channel") panic(plainError("close of closed channel"))
} }
if raceenabled { if raceenabled {
......
...@@ -273,6 +273,52 @@ func TestGoexitInPanic(t *testing.T) { ...@@ -273,6 +273,52 @@ func TestGoexitInPanic(t *testing.T) {
} }
} }
// Issue 14965: Runtime panics should be of type runtime.Error
func TestRuntimePanicWithRuntimeError(t *testing.T) {
testCases := [...]func(){
0: func() {
var m map[uint64]bool
m[1234] = true
},
1: func() {
ch := make(chan struct{})
close(ch)
close(ch)
},
2: func() {
var ch = make(chan struct{})
close(ch)
ch <- struct{}{}
},
3: func() {
var s = make([]int, 2)
_ = s[2]
},
4: func() {
n := -1
_ = make(chan bool, n)
},
5: func() {
close((chan bool)(nil))
},
}
for i, fn := range testCases {
got := panicValue(fn)
if _, ok := got.(runtime.Error); !ok {
t.Errorf("test #%d: recovered value %v(type %T) does not implement runtime.Error", i, got, got)
}
}
}
func panicValue(fn func()) (recovered interface{}) {
defer func() {
recovered = recover()
}()
fn()
return
}
func TestPanicAfterGoexit(t *testing.T) { func TestPanicAfterGoexit(t *testing.T) {
// an uncaught panic should still work after goexit // an uncaught panic should still work after goexit
output := runTestProg(t, "testprog", "PanicAfterGoexit") output := runTestProg(t, "testprog", "PanicAfterGoexit")
......
...@@ -50,6 +50,17 @@ func (e errorString) Error() string { ...@@ -50,6 +50,17 @@ func (e errorString) Error() string {
return "runtime error: " + string(e) return "runtime error: " + string(e)
} }
// plainError represents a runtime error described a string without
// the prefix "runtime error: " after invoking errorString.Error().
// See Issue #14965.
type plainError string
func (e plainError) RuntimeError() {}
func (e plainError) Error() string {
return string(e)
}
type stringer interface { type stringer interface {
String() string String() string
} }
...@@ -82,5 +93,5 @@ func printany(i interface{}) { ...@@ -82,5 +93,5 @@ func printany(i interface{}) {
// called from generated code // called from generated code
func panicwrap(pkg, typ, meth string) { func panicwrap(pkg, typ, meth string) {
panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer") panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))
} }
...@@ -194,7 +194,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { ...@@ -194,7 +194,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
} }
if hint < 0 || int64(int32(hint)) != hint { if hint < 0 || int64(int32(hint)) != hint {
panic("makemap: size out of range") panic(plainError("makemap: size out of range"))
// TODO: make hint an int, then none of this nonsense // TODO: make hint an int, then none of this nonsense
} }
...@@ -428,7 +428,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe ...@@ -428,7 +428,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) { func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
if h == nil { if h == nil {
panic("assignment to entry in nil map") panic(plainError("assignment to entry in nil map"))
} }
if raceenabled { if raceenabled {
callerpc := getcallerpc(unsafe.Pointer(&t)) callerpc := getcallerpc(unsafe.Pointer(&t))
......
...@@ -793,7 +793,7 @@ func newarray(typ *_type, n uintptr) unsafe.Pointer { ...@@ -793,7 +793,7 @@ func newarray(typ *_type, n uintptr) unsafe.Pointer {
flags |= flagNoScan flags |= flagNoScan
} }
if int(n) < 0 || (typ.size > 0 && n > _MaxMem/typ.size) { if int(n) < 0 || (typ.size > 0 && n > _MaxMem/typ.size) {
panic("runtime: allocation size out of range") panic(plainError("runtime: allocation size out of range"))
} }
return mallocgc(typ.size*n, typ, flags) return mallocgc(typ.size*n, typ, flags)
} }
......
...@@ -381,7 +381,7 @@ func badmcall2(fn func(*g)) { ...@@ -381,7 +381,7 @@ func badmcall2(fn func(*g)) {
} }
func badreflectcall() { func badreflectcall() {
panic("runtime: arg size to reflect.call more than 1GB") panic(plainError("arg size to reflect.call more than 1GB"))
} }
func lockedOSThread() bool { func lockedOSThread() bool {
......
...@@ -594,7 +594,7 @@ retc: ...@@ -594,7 +594,7 @@ retc:
sclose: sclose:
// send on closed channel // send on closed channel
selunlock(scases, lockorder) selunlock(scases, lockorder)
panic("send on closed channel") panic(plainError("send on closed channel"))
} }
func (c *hchan) sortkey() uintptr { func (c *hchan) sortkey() uintptr {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment