diff --git a/runtime/internal/lib/reflect/value.go b/runtime/internal/lib/reflect/value.go index 5640d4f4b0..04c1a739ad 100644 --- a/runtime/internal/lib/reflect/value.go +++ b/runtime/internal/lib/reflect/value.go @@ -2263,6 +2263,13 @@ type closure struct { env unsafe.Pointer } +func toFFIWordArg(v Value) unsafe.Pointer { + if v.flag&flagIndir != 0 { + return v.ptr + } + return unsafe.Pointer(&v.ptr) +} + func toFFIArg(v Value, typ *abi.Type) unsafe.Pointer { kind := typ.Kind() switch kind { @@ -2282,16 +2289,16 @@ func toFFIArg(v Value, typ *abi.Type) unsafe.Pointer { } return unsafe.Pointer(&v.ptr) case abi.Chan: - return unsafe.Pointer(&v.ptr) + return toFFIWordArg(v) case abi.Func: return unsafe.Pointer(&v.ptr) case abi.Interface: i := v.Interface() return unsafe.Pointer(&i) case abi.Map: - return unsafe.Pointer(&v.ptr) + return toFFIWordArg(v) case abi.Pointer: - return unsafe.Pointer(&v.ptr) + return toFFIWordArg(v) case abi.Slice: return v.ptr case abi.String: @@ -2302,7 +2309,7 @@ func toFFIArg(v Value, typ *abi.Type) unsafe.Pointer { } return unsafe.Pointer(&v.ptr) case abi.UnsafePointer: - return unsafe.Pointer(&v.ptr) + return toFFIWordArg(v) } panic("reflect.toFFIArg unsupport type " + v.typ().String()) } diff --git a/test/go/reflect_call_word_args_test.go b/test/go/reflect_call_word_args_test.go new file mode 100644 index 0000000000..f7caeeea71 --- /dev/null +++ b/test/go/reflect_call_word_args_test.go @@ -0,0 +1,43 @@ +package gotest + +import ( + "reflect" + "testing" + "unsafe" +) + +type reflectCallWordArgHolder struct { + P *int + C chan int + M map[string]int + U unsafe.Pointer +} + +func reflectCallWordArgTake(p *int, c chan int, m map[string]int, u unsafe.Pointer) (int, int, int, int) { + return *p, cap(c), m["x"], *(*int)(u) +} + +func TestReflectCallIndirectWordArgs(t *testing.T) { + x := 7 + h := reflectCallWordArgHolder{ + P: &x, + C: make(chan int, 3), + M: map[string]int{"x": 11}, + U: unsafe.Pointer(&x), + } + v := reflect.ValueOf(h) + out := reflect.ValueOf(reflectCallWordArgTake).Call([]reflect.Value{ + v.Field(0), + v.Field(1), + v.Field(2), + v.Field(3), + }) + + got := []int{int(out[0].Int()), int(out[1].Int()), int(out[2].Int()), int(out[3].Int())} + want := []int{7, 3, 11, 7} + for i := range want { + if got[i] != want[i] { + t.Fatalf("result[%d] = %d, want %d; all results: %v", i, got[i], want[i], got) + } + } +}