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.
Этот коммит содержится в:
Ayke van Laethem 2021-08-15 14:58:59 +02:00 коммит произвёл Ron Evans
родитель b534dd67e0
коммит d15e32fb89
3 изменённых файлов: 28 добавлений и 0 удалений

Просмотреть файл

@ -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.

16
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 {

4
testdata/reflect.txt предоставленный
Просмотреть файл

@ -377,3 +377,7 @@ type assertion succeeded for unreferenced type
struct tags
blue gopher
v.Interface() method
kind: interface
int 5