]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make execution error panic values implement the Error interface
authorEmmanuel Odeke <emm.odeke@gmail.com>
Mon, 28 Mar 2016 00:29:53 +0000 (17:29 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Sun, 10 Apr 2016 01:16:30 +0000 (01:16 +0000)
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/21214
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/runtime/chan.go
src/runtime/crash_test.go
src/runtime/error.go
src/runtime/hashmap.go
src/runtime/malloc.go
src/runtime/proc.go
src/runtime/select.go

index 954b389f47cff05858c73105098fdcf1eb5fcced..8543cb4c9c3ec221c01b5e08797852c92d670285 100644 (file)
@@ -64,7 +64,7 @@ func makechan(t *chantype, size int64) *hchan {
                throw("makechan: bad alignment")
        }
        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
@@ -171,7 +171,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 
        if c.closed != 0 {
                unlock(&c.lock)
-               panic("send on closed channel")
+               panic(plainError("send on closed channel"))
        }
 
        if sg := c.recvq.dequeue(); sg != nil {
@@ -231,7 +231,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
                if c.closed == 0 {
                        throw("chansend: spurious wakeup")
                }
-               panic("send on closed channel")
+               panic(plainError("send on closed channel"))
        }
        gp.param = nil
        if mysg.releasetime > 0 {
@@ -302,13 +302,13 @@ func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {
 
 func closechan(c *hchan) {
        if c == nil {
-               panic("close of nil channel")
+               panic(plainError("close of nil channel"))
        }
 
        lock(&c.lock)
        if c.closed != 0 {
                unlock(&c.lock)
-               panic("close of closed channel")
+               panic(plainError("close of closed channel"))
        }
 
        if raceenabled {
index 85fcc69fedca65bbc6677ed311276a2939f7afca..2941b8e8f8a6d33e97a261f25358ebc47bbe69a1 100644 (file)
@@ -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) {
        // an uncaught panic should still work after goexit
        output := runTestProg(t, "testprog", "PanicAfterGoexit")
index 3e1ec4bc5a78a06e5c96cd302b7d923a42133f71..15f6bdf014662f26e03fc74cce0bd5757114cfd9 100644 (file)
@@ -50,6 +50,17 @@ func (e errorString) Error() string {
        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 {
        String() string
 }
@@ -82,5 +93,5 @@ func printany(i interface{}) {
 
 // called from generated code
 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"))
 }
index 80b2b5338c17ce4c32aaf2921aa1c0fe9e5caa91..9e18192cd8c8d7b0be0dca19457587c947055a50 100644 (file)
@@ -194,7 +194,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
        }
 
        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
        }
 
@@ -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) {
        if h == nil {
-               panic("assignment to entry in nil map")
+               panic(plainError("assignment to entry in nil map"))
        }
        if raceenabled {
                callerpc := getcallerpc(unsafe.Pointer(&t))
index 5f1e2f64c018bb072a82b477f3cf73ebe0d9fa0c..ee4728c9a5098501d6e374a6558738451969314f 100644 (file)
@@ -793,7 +793,7 @@ func newarray(typ *_type, n uintptr) unsafe.Pointer {
                flags |= flagNoScan
        }
        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)
 }
index 1f55b0fa21a8ab804f4262ac34de36eadc8962d6..1a9dbd6c53fa943fc796a2d7abf85b1b140eb56f 100644 (file)
@@ -381,7 +381,7 @@ func badmcall2(fn func(*g)) {
 }
 
 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 {
index c80c833b1566a0bca23a7b7d1ba5f331bcd8f54d..9810db5453e1a8e264bdab782ba6f6ed8ab8d717 100644 (file)
@@ -594,7 +594,7 @@ retc:
 sclose:
        // send on closed channel
        selunlock(scases, lockorder)
-       panic("send on closed channel")
+       panic(plainError("send on closed channel"))
 }
 
 func (c *hchan) sortkey() uintptr {