From 5b8127fd4ea3bd3134f93e07250d595dfbde14ba Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Tue, 12 Dec 2023 21:51:26 -0800 Subject: [PATCH] reflect: move indirect values into interface when setting interfaces Fixes #4040 --- src/reflect/value.go | 7 +++++++ src/reflect/value_test.go | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/reflect/value.go b/src/reflect/value.go index 1227ac42..16d2a17b 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1086,6 +1086,13 @@ func (v Value) Set(x Value) { } if v.typecode.Kind() == Interface && x.typecode.Kind() != Interface { + // move the value of x back into the interface, if possible + if x.isIndirect() && x.typecode.Size() <= unsafe.Sizeof(uintptr(0)) { + var value uintptr + memcpy(unsafe.Pointer(&value), x.value, x.typecode.Size()) + x.value = unsafe.Pointer(value) + } + intf := composeInterface(unsafe.Pointer(x.typecode), x.value) x = Value{ typecode: v.typecode, diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index 9be9789e..6641750b 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -624,6 +624,28 @@ func TestConvert(t *testing.T) { } } +func TestIssue4040(t *testing.T) { + var value interface{} = uint16(0) + + // get the pointer to the interface value + inPtr := ValueOf(&value) + + // dereference to get the actual value (an interface) + inElem := inPtr.Elem() + + // create a new value of the same concrete type + uint16Type := TypeOf(uint16(0)) + newUint16Value := New(uint16Type).Elem() + newUint16Value.Set(ValueOf(uint16(13))) + + // set the new value to the interface + inElem.Set(newUint16Value) + + if value.(uint16) != 13 { + t.Errorf("Failed to set interface value from uint16") + } +} + func equal[T comparable](a, b []T) bool { if len(a) != len(b) { return false