diff options
-rw-r--r-- | src/reflect/all_test.go | 35 | ||||
-rw-r--r-- | src/reflect/value.go | 26 |
2 files changed, 50 insertions, 11 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 3eca293675..7f8c12981c 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -1681,6 +1681,11 @@ func (p Point) GCMethod(k int) int { } // This will be index 3. +func (p Point) NoArgs() { + // Exercise no-argument/no-result paths. +} + +// This will be index 4. func (p Point) TotalDist(points ...Point) int { tot := 0 for _, q := range points { @@ -1709,6 +1714,15 @@ func TestMethod(t *testing.T) { t.Errorf("Type MethodByName returned %d; want 275", i) } + m, ok = TypeOf(p).MethodByName("NoArgs") + if !ok { + t.Fatalf("method by name failed") + } + n := len(m.Func.Call([]Value{ValueOf(p)})) + if n != 0 { + t.Errorf("NoArgs returned %d values; want 0", n) + } + i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(12)})[0].Int() if i != 300 { t.Errorf("Pointer Type Method returned %d; want 300", i) @@ -1723,6 +1737,15 @@ func TestMethod(t *testing.T) { t.Errorf("Pointer Type MethodByName returned %d; want 325", i) } + m, ok = TypeOf(&p).MethodByName("NoArgs") + if !ok { + t.Fatalf("method by name failed") + } + n = len(m.Func.Call([]Value{ValueOf(&p)})) + if n != 0 { + t.Errorf("NoArgs returned %d values; want 0", n) + } + // Curried method of value. tfunc := TypeOf((func(int) int)(nil)) v := ValueOf(p).Method(1) @@ -1741,6 +1764,8 @@ func TestMethod(t *testing.T) { if i != 375 { t.Errorf("Value MethodByName returned %d; want 375", i) } + v = ValueOf(p).MethodByName("NoArgs") + v.Call(nil) // Curried method of pointer. v = ValueOf(&p).Method(1) @@ -1759,6 +1784,8 @@ func TestMethod(t *testing.T) { if i != 425 { t.Errorf("Pointer Value MethodByName returned %d; want 425", i) } + v = ValueOf(&p).MethodByName("NoArgs") + v.Call(nil) // Curried method of interface value. // Have to wrap interface value in a struct to get at it. @@ -1808,6 +1835,9 @@ func TestMethodValue(t *testing.T) { if i != 275 { t.Errorf("Value MethodByName returned %d; want 275", i) } + v = ValueOf(p).MethodByName("NoArgs") + ValueOf(v.Interface()).Call(nil) + v.Interface().(func())() // Curried method of pointer. v = ValueOf(&p).Method(1) @@ -1826,6 +1856,9 @@ func TestMethodValue(t *testing.T) { if i != 325 { t.Errorf("Pointer Value MethodByName returned %d; want 325", i) } + v = ValueOf(&p).MethodByName("NoArgs") + ValueOf(v.Interface()).Call(nil) + v.Interface().(func())() // Curried method of pointer to pointer. pp := &p @@ -1881,7 +1914,7 @@ func TestVariadicMethodValue(t *testing.T) { // Curried method of value. tfunc := TypeOf((func(...Point) int)(nil)) - v := ValueOf(p).Method(3) + v := ValueOf(p).Method(4) if tt := v.Type(); tt != tfunc { t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc) } diff --git a/src/reflect/value.go b/src/reflect/value.go index 699ba69408..387b9f3c13 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -630,8 +630,11 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) { args := framePool.Get().(unsafe.Pointer) // Copy in receiver and rest of args. + // Avoid constructing out-of-bounds pointers if there are no args. storeRcvr(rcvr, args) - typedmemmovepartial(frametype, unsafe.Pointer(uintptr(args)+ptrSize), frame, ptrSize, argSize-ptrSize) + if argSize-ptrSize > 0 { + typedmemmovepartial(frametype, unsafe.Pointer(uintptr(args)+ptrSize), frame, ptrSize, argSize-ptrSize) + } // Call. call(frametype, fn, args, uint32(frametype.size), uint32(retOffset)) @@ -641,15 +644,18 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) { // a receiver) is different from the layout of the fn call, which has // a receiver. // Ignore any changes to args and just copy return values. - callerRetOffset := retOffset - ptrSize - if runtime.GOARCH == "amd64p32" { - callerRetOffset = align(argSize-ptrSize, 8) - } - typedmemmovepartial(frametype, - unsafe.Pointer(uintptr(frame)+callerRetOffset), - unsafe.Pointer(uintptr(args)+retOffset), - retOffset, - frametype.size-retOffset) + // Avoid constructing out-of-bounds pointers if there are no return values. + if frametype.size-retOffset > 0 { + callerRetOffset := retOffset - ptrSize + if runtime.GOARCH == "amd64p32" { + callerRetOffset = align(argSize-ptrSize, 8) + } + typedmemmovepartial(frametype, + unsafe.Pointer(uintptr(frame)+callerRetOffset), + unsafe.Pointer(uintptr(args)+retOffset), + retOffset, + frametype.size-retOffset) + } // This is untyped because the frame is really a stack, even // though it's a heap object. |