]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: correct type descriptor for call of interface method
authorRuss Cox <rsc@golang.org>
Wed, 16 Apr 2014 15:52:27 +0000 (11:52 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 16 Apr 2014 15:52:27 +0000 (11:52 -0400)
When preparing a call with an interface method, the argument
frame holds the receiver "iword", but funcLayout was being
asked to write a descriptor as if the receiver were a complete
interface value. This was originally caught by running a large
program with Debug=3 in runtime/mgc0.c, but the new panic
in funcLayout suffices to catch the mistake with the existing
tests.

Fixes #7748.

LGTM=bradfitz, iant
R=golang-codereviews, bradfitz, iant
CC=golang-codereviews, khr
https://golang.org/cl/88100048

src/pkg/reflect/type.go
src/pkg/reflect/value.go

index 47bd103fb0c2a3d299d6e9be50b8c252c229b520..5a4ac8cf7c10596cfebf7d278d07529350dfd7ec 100644 (file)
@@ -1833,7 +1833,10 @@ var layoutCache struct {
 // the name for possible debugging use.
 func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) {
        if t.Kind() != Func {
-               panic("reflect: funcSignature of non-func type")
+               panic("reflect: funcLayout of non-func type")
+       }
+       if rcvr != nil && rcvr.Kind() == Interface {
+               panic("reflect: funcLayout with interface receiver " + rcvr.String())
        }
        k := layoutKey{t, rcvr}
        layoutCache.RLock()
index 720090bd66d8e5e749e18f153e4c067268b4609e..39cc91991f7ee9fb9f0aa715aa37f26f1ea4159d 100644 (file)
@@ -440,9 +440,8 @@ func (v Value) call(op string, in []Value) []Value {
                rcvrtype *rtype
        )
        if v.flag&flagMethod != 0 {
-               rcvrtype = t
                rcvr = v
-               t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
+               rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
        } else if v.flag&flagIndir != 0 {
                fn = *(*unsafe.Pointer)(v.ptr)
        } else {
@@ -529,8 +528,7 @@ func (v Value) call(op string, in []Value) []Value {
        y := (*methodValue)(fn)
        if y.fn == methodValueCallCode {
                rcvr = y.rcvr
-               rcvrtype = rcvr.typ
-               t, fn = methodReceiver("call", rcvr, y.method)
+               rcvrtype, t, fn = methodReceiver("call", rcvr, y.method)
        }
 
        // Compute frame type, allocate a chunk of memory for frame
@@ -668,9 +666,10 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 // described by v. The Value v may or may not have the
 // flagMethod bit set, so the kind cached in v.flag should
 // not be used.
+// The return value rcvrtype gives the method's actual receiver type.
 // The return value t gives the method type signature (without the receiver).
 // The return value fn is a pointer to the method code.
-func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Pointer) {
+func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) {
        i := methodIndex
        if v.typ.Kind() == Interface {
                tt := (*interfaceType)(unsafe.Pointer(v.typ))
@@ -685,9 +684,11 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
                if iface.itab == nil {
                        panic("reflect: " + op + " of method on nil interface value")
                }
+               rcvrtype = iface.itab.typ
                fn = unsafe.Pointer(&iface.itab.fun[i])
                t = m.typ
        } else {
+               rcvrtype = v.typ
                ut := v.typ.uncommon()
                if ut == nil || i < 0 || i >= len(ut.methods) {
                        panic("reflect: internal error: invalid method index")
@@ -746,8 +747,7 @@ func align(x, n uintptr) uintptr {
 // The gc compilers know to do that for the name "reflect.callMethod".
 func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
        rcvr := ctxt.rcvr
-       rcvrtype := rcvr.typ
-       t, fn := methodReceiver("call", rcvr, ctxt.method)
+       rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
        frametype, argSize, retOffset := funcLayout(t, rcvrtype)
 
        // Make a new frame that is one word bigger so we can store the receiver.