diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 69d5378049..6cc1c9abad 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -8001,6 +8001,17 @@ func TestSetIter(t *testing.T) { if got := *y.Interface().(*int); got != b { t.Errorf("pointer incorrect: got %d want %d", got, b) } + + // Make sure we panic assigning from an unexported field. + m = ValueOf(struct{ m map[string]int }{data}).Field(0) + for iter := m.MapRange(); iter.Next(); { + shouldPanic("using value obtained using unexported field", func() { + k.SetIterKey(iter) + }) + shouldPanic("using value obtained using unexported field", func() { + v.SetIterValue(iter) + }) + } } func TestMethodCallValueCodePtr(t *testing.T) { diff --git a/src/reflect/value.go b/src/reflect/value.go index 2589a6dd18..5276af6fd6 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1837,7 +1837,8 @@ func (iter *MapIter) Key() Value { // SetIterKey assigns to v the key of iter's current map entry. // It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value. -// As in Go, the key must be assignable to v's type. +// As in Go, the key must be assignable to v's type and +// must not be derived from an unexported field. func (v Value) SetIterKey(iter *MapIter) { if !iter.hiter.initialized() { panic("reflect: Value.SetIterKey called before Next") @@ -1856,6 +1857,7 @@ func (v Value) SetIterKey(iter *MapIter) { t := (*mapType)(unsafe.Pointer(iter.m.typ)) ktype := t.key + iter.m.mustBeExported() // do not let unexported m leak key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir} key = key.assignTo("reflect.MapIter.SetKey", v.typ, target) typedmemmove(v.typ, v.ptr, key.ptr) @@ -1878,7 +1880,8 @@ func (iter *MapIter) Value() Value { // SetIterValue assigns to v the value of iter's current map entry. // It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value. -// As in Go, the value must be assignable to v's type. +// As in Go, the value must be assignable to v's type and +// must not be derived from an unexported field. func (v Value) SetIterValue(iter *MapIter) { if !iter.hiter.initialized() { panic("reflect: Value.SetIterValue called before Next") @@ -1897,6 +1900,7 @@ func (v Value) SetIterValue(iter *MapIter) { t := (*mapType)(unsafe.Pointer(iter.m.typ)) vtype := t.elem + iter.m.mustBeExported() // do not let unexported m leak elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir} elem = elem.assignTo("reflect.MapIter.SetValue", v.typ, target) typedmemmove(v.typ, v.ptr, elem.ptr) @@ -2218,7 +2222,8 @@ func (v Value) send(x Value, nb bool) (selected bool) { // Set assigns x to the value v. // It panics if CanSet returns false. -// As in Go, x's value must be assignable to v's type. +// As in Go, x's value must be assignable to v's type and +// must not be derived from an unexported field. func (v Value) Set(x Value) { v.mustBeAssignable() x.mustBeExported() // do not let unexported x leak