mirror of
https://github.com/golang/go
synced 2024-11-19 21:04:43 -07:00
reflect: correct type descriptor for call of interface method
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
This commit is contained in:
parent
a5b1530557
commit
fcf8a77525
@ -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()
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user