From d15e32fb895ecf971031a72137b85ed1cff626fd Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 15 Aug 2021 14:58:59 +0200 Subject: [PATCH] reflect: don't construct an interface-in-interface value v.Interaface() could construct an interface in interface value if v was of type interface. This is not correct, and doesn't follow upstream Go behavior. Instead, it should return the interface value itself. --- src/reflect/value.go | 8 ++++++++ testdata/reflect.go | 16 ++++++++++++++++ testdata/reflect.txt | 4 ++++ 3 files changed, 28 insertions(+) diff --git a/src/reflect/value.go b/src/reflect/value.go index f5f0132d..10cf4f74 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -67,6 +67,14 @@ func (v Value) Interface() interface{} { // valueInterfaceUnsafe is used by the runtime to hash map keys. It should not // be subject to the isExported check. func valueInterfaceUnsafe(v Value) interface{} { + if v.typecode.Kind() == Interface { + // The value itself is an interface. This can happen when getting the + // value of a struct field of interface type, like this: + // type T struct { + // X interface{} + // } + return *(*interface{})(v.value) + } if v.isIndirect() && v.typecode.Size() <= unsafe.Sizeof(uintptr(0)) { // Value was indirect but must be put back directly in the interface // value. diff --git a/testdata/reflect.go b/testdata/reflect.go index 5a107e2d..2b7dbc04 100644 --- a/testdata/reflect.go +++ b/testdata/reflect.go @@ -321,6 +321,9 @@ func main() { println("\nstruct tags") TestStructTag() + + println("\nv.Interface() method") + testInterfaceMethod() } func emptyFunc() { @@ -470,6 +473,19 @@ func TestStructTag() { println(field.Tag.Get("color"), field.Tag.Get("species")) } +// Test Interface() call: it should never return an interface itself. +func testInterfaceMethod() { + v := reflect.ValueOf(struct{ X interface{} }{X: 5}) + println("kind:", v.Field(0).Kind().String()) + itf := v.Field(0).Interface() + switch n := itf.(type) { + case int: + println("int", n) // correct + default: + println("something else") // incorrect + } +} + var xorshift32State uint32 = 1 func xorshift32(x uint32) uint32 { diff --git a/testdata/reflect.txt b/testdata/reflect.txt index 4bd55fd8..19642949 100644 --- a/testdata/reflect.txt +++ b/testdata/reflect.txt @@ -377,3 +377,7 @@ type assertion succeeded for unreferenced type struct tags blue gopher + +v.Interface() method +kind: interface +int 5