]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: panic with the right error on iface conversion
authorIan Lance Taylor <iant@golang.org>
Mon, 20 Jun 2016 22:53:11 +0000 (15:53 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 21 Jun 2016 01:43:42 +0000 (01:43 +0000)
A straight conversion from a type T to an interface type I, where T does
not implement I, should always panic with an interface conversion error
that shows the missing method.  This was not happening if the conversion
was done once using the comma-ok form (the result would not be OK) and
then again in a straight conversion.  Due to an error in the runtime
package the second conversion was failing with a nil pointer
dereference.

Fixes #16130.

Change-Id: I8b9fca0f1bb635a6181b8b76de8c2385bb7ac2d2
Reviewed-on: https://go-review.googlesource.com/24284
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Michel Lespinasse <walken@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/runtime/iface.go
test/fixedbugs/issue16130.go [new file with mode: 0644]

index b57d1cc63c3e8b32fec2a4c9c4b071aa2f15b11e..1690147fac3dc0298b2f6631d7dc4af944e7f295 100644 (file)
@@ -54,7 +54,6 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
                for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
                        if m.inter == inter && m._type == typ {
                                if m.bad != 0 {
-                                       m = nil
                                        if !canfail {
                                                // this can only happen if the conversion
                                                // was already done once using the , ok form
@@ -64,6 +63,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
                                                // adding the itab again, which will throw an error.
                                                additab(m, locked != 0, false)
                                        }
+                                       m = nil
                                }
                                if locked != 0 {
                                        unlock(&ifaceLock)
diff --git a/test/fixedbugs/issue16130.go b/test/fixedbugs/issue16130.go
new file mode 100644 (file)
index 0000000..19c8264
--- /dev/null
@@ -0,0 +1,43 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that an interface conversion error panics with an "interface
+// conversion" run-time error. It was (incorrectly) panicing with a
+// "nil pointer dereference."
+
+package main
+
+import (
+       "fmt"
+       "runtime"
+       "strings"
+)
+
+type I interface {
+       Get() int
+}
+
+func main() {
+       defer func() {
+               r := recover()
+               if r == nil {
+                       panic("expected panic")
+               }
+               re, ok := r.(runtime.Error)
+               if !ok {
+                       panic(fmt.Sprintf("got %T, expected runtime.Error", r))
+               }
+               if !strings.Contains(re.Error(), "interface conversion") {
+                       panic(fmt.Sprintf("got %q, expected interface conversion error", re.Error()))
+               }
+       }()
+       e := (interface{})(0)
+       if _, ok := e.(I); ok {
+               panic("unexpected interface conversion success")
+       }
+       fmt.Println(e.(I))
+       panic("unexpected interface conversion success")
+}