]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: align first argument in callMethod
authorCherry Zhang <cherryyz@google.com>
Wed, 14 Aug 2019 13:50:51 +0000 (09:50 -0400)
committerCherry Zhang <cherryyz@google.com>
Wed, 14 Aug 2019 19:49:15 +0000 (19:49 +0000)
When calling a function obtained from reflect.Value.Method (or
MethodByName), we copy the arguments from the caller frame, which
does not include the receiver, to a new frame to call the actual
method, which does include the receiver. Here we need to align
the first (non-receiver) argument. As the receiver is pointer
sized, it is generally naturally aligned, except on amd64p32,
where the argument can have larger alignment, and this aligning
becomes necessary.

Fixes #33628.

Change-Id: I5bea0e20173f06d1602c5666d4f334e3d0de5c1e
Reviewed-on: https://go-review.googlesource.com/c/go/+/190297
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/reflect/all_test.go
src/reflect/value.go

index 0dbf4c5e877e50eb38047b1f832ef26516f9ca4f..4431ce2391096275f4b17e80c560f21f0fefba66 100644 (file)
@@ -2057,6 +2057,16 @@ func (p Point) TotalDist(points ...Point) int {
        return tot
 }
 
+// This will be index 5.
+func (p *Point) Int64Method(x int64) int64 {
+       return x
+}
+
+// This will be index 6.
+func (p *Point) Int32Method(x int32) int32 {
+       return x
+}
+
 func TestMethod(t *testing.T) {
        // Non-curried method of type.
        p := Point{3, 4}
@@ -2265,6 +2275,17 @@ func TestMethodValue(t *testing.T) {
        if i != 425 {
                t.Errorf("Interface MethodByName returned %d; want 425", i)
        }
+
+       // For issue #33628: method args are not stored at the right offset
+       // on amd64p32.
+       m64 := ValueOf(&p).MethodByName("Int64Method").Interface().(func(int64) int64)
+       if x := m64(123); x != 123 {
+               t.Errorf("Int64Method returned %d; want 123", x)
+       }
+       m32 := ValueOf(&p).MethodByName("Int32Method").Interface().(func(int32) int32)
+       if x := m32(456); x != 456 {
+               t.Errorf("Int32Method returned %d; want 456", x)
+       }
 }
 
 func TestVariadicMethodValue(t *testing.T) {
index 218b4d25cc223f3973fb78a1bf878f7dd802a1bf..9ea95bc1d99c75ddac104cf5c85f305656ecbf98 100644 (file)
@@ -696,10 +696,16 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool) {
        scratch := framePool.Get().(unsafe.Pointer)
 
        // Copy in receiver and rest of args.
-       // Avoid constructing out-of-bounds pointers if there are no args.
        storeRcvr(rcvr, scratch)
-       if argSize-ptrSize > 0 {
-               typedmemmovepartial(frametype, add(scratch, ptrSize, "argSize > ptrSize"), frame, ptrSize, argSize-ptrSize)
+       // Align the first arg. Only on amd64p32 the alignment can be
+       // larger than ptrSize.
+       argOffset := uintptr(ptrSize)
+       if len(t.in()) > 0 {
+               argOffset = align(argOffset, uintptr(t.in()[0].align))
+       }
+       // Avoid constructing out-of-bounds pointers if there are no args.
+       if argSize-argOffset > 0 {
+               typedmemmovepartial(frametype, add(scratch, argOffset, "argSize > argOffset"), frame, argOffset, argSize-argOffset)
        }
 
        // Call.
@@ -714,9 +720,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool) {
        // Ignore any changes to args and just copy return values.
        // Avoid constructing out-of-bounds pointers if there are no return values.
        if frametype.size-retOffset > 0 {
-               callerRetOffset := retOffset - ptrSize
+               callerRetOffset := retOffset - argOffset
                if runtime.GOARCH == "amd64p32" {
-                       callerRetOffset = align(argSize-ptrSize, 8)
+                       callerRetOffset = align(argSize-argOffset, 8)
                }
                // This copies to the stack. Write barriers are not needed.
                memmove(add(frame, callerRetOffset, "frametype.size > retOffset"),