Skip to content

Commit 91ef076

Browse files
committed
reflect: fix Value.SetIterXXX to check for the read-only bit
v.SetIterXXX(i) is semantically identical to v.Set(i.XXX()). If the latter panics for unexported values, so should the former. This change may breaking some programs, but the change is justified under the "Go 1 and the Future of Go Programs" document because the "library has a bug that violates the specification". In this case, the "reflect" package does not accurately match the behavior of the Go language specification. Also, this API was recently released, so the number of users who could be depending on this behavior is hopefully lower. Fixes #54628 Change-Id: If86ede51f286e38093f6697944c089f616525115 Reviewed-on: https://go-review.googlesource.com/c/go/+/425184 Auto-Submit: Joseph Tsai <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Keith Randall <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Joseph Tsai <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent 64b260d commit 91ef076

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

src/reflect/all_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -8001,6 +8001,17 @@ func TestSetIter(t *testing.T) {
80018001
if got := *y.Interface().(*int); got != b {
80028002
t.Errorf("pointer incorrect: got %d want %d", got, b)
80038003
}
8004+
8005+
// Make sure we panic assigning from an unexported field.
8006+
m = ValueOf(struct{ m map[string]int }{data}).Field(0)
8007+
for iter := m.MapRange(); iter.Next(); {
8008+
shouldPanic("using value obtained using unexported field", func() {
8009+
k.SetIterKey(iter)
8010+
})
8011+
shouldPanic("using value obtained using unexported field", func() {
8012+
v.SetIterValue(iter)
8013+
})
8014+
}
80048015
}
80058016

80068017
func TestMethodCallValueCodePtr(t *testing.T) {

src/reflect/value.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -1837,7 +1837,8 @@ func (iter *MapIter) Key() Value {
18371837

18381838
// SetIterKey assigns to v the key of iter's current map entry.
18391839
// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value.
1840-
// As in Go, the key must be assignable to v's type.
1840+
// As in Go, the key must be assignable to v's type and
1841+
// must not be derived from an unexported field.
18411842
func (v Value) SetIterKey(iter *MapIter) {
18421843
if !iter.hiter.initialized() {
18431844
panic("reflect: Value.SetIterKey called before Next")
@@ -1856,6 +1857,7 @@ func (v Value) SetIterKey(iter *MapIter) {
18561857
t := (*mapType)(unsafe.Pointer(iter.m.typ))
18571858
ktype := t.key
18581859

1860+
iter.m.mustBeExported() // do not let unexported m leak
18591861
key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir}
18601862
key = key.assignTo("reflect.MapIter.SetKey", v.typ, target)
18611863
typedmemmove(v.typ, v.ptr, key.ptr)
@@ -1878,7 +1880,8 @@ func (iter *MapIter) Value() Value {
18781880

18791881
// SetIterValue assigns to v the value of iter's current map entry.
18801882
// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value.
1881-
// As in Go, the value must be assignable to v's type.
1883+
// As in Go, the value must be assignable to v's type and
1884+
// must not be derived from an unexported field.
18821885
func (v Value) SetIterValue(iter *MapIter) {
18831886
if !iter.hiter.initialized() {
18841887
panic("reflect: Value.SetIterValue called before Next")
@@ -1897,6 +1900,7 @@ func (v Value) SetIterValue(iter *MapIter) {
18971900
t := (*mapType)(unsafe.Pointer(iter.m.typ))
18981901
vtype := t.elem
18991902

1903+
iter.m.mustBeExported() // do not let unexported m leak
19001904
elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir}
19011905
elem = elem.assignTo("reflect.MapIter.SetValue", v.typ, target)
19021906
typedmemmove(v.typ, v.ptr, elem.ptr)
@@ -2218,7 +2222,8 @@ func (v Value) send(x Value, nb bool) (selected bool) {
22182222

22192223
// Set assigns x to the value v.
22202224
// It panics if CanSet returns false.
2221-
// As in Go, x's value must be assignable to v's type.
2225+
// As in Go, x's value must be assignable to v's type and
2226+
// must not be derived from an unexported field.
22222227
func (v Value) Set(x Value) {
22232228
v.mustBeAssignable()
22242229
x.mustBeExported() // do not let unexported x leak

0 commit comments

Comments
 (0)