Skip to content

Commit 6471ace

Browse files
committed
reflect: fix mutability of non-exported embedded fields
The reflect API normally grants only read-only access to non-exported fields, but it specially handles non-exported embedded fields so that users can still fully access promoted fields and methods. For example, if v.Field(i) refers to a non-exported embedded field, it would be limited to RO access. But if v.Field(i).Field(j) is an exported field, then the resulting Value will have full access. However, the way this was implemented allowed other operations to be interspersed between the Field calls, which could grant inappropriate access. Relatedly, Elem() is safe to use on pointer-embeddings, but it was also being allowed on embeddings of interface types. This is inappropriate because it could allow accessing methods of the dynamic value's complete method set, not just those that were promoted via the interface embedding. Fixes #22031. Fixes #22053. Change-Id: I9db9be88583f1c1d80c1b4705a76f23a4379182f Reviewed-on: https://go-review.googlesource.com/66331 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
1 parent a714470 commit 6471ace

File tree

2 files changed

+57
-32
lines changed

2 files changed

+57
-32
lines changed

src/reflect/all_test.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3224,7 +3224,7 @@ func TestCallPanic(t *testing.T) {
32243224
i := timp(0)
32253225
v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
32263226
ok(func() { call(v.Field(0).Method(0)) }) // .t0.W
3227-
ok(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
3227+
bad(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
32283228
bad(func() { call(v.Field(0).Method(1)) }) // .t0.w
32293229
bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
32303230
ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y
@@ -3242,10 +3242,10 @@ func TestCallPanic(t *testing.T) {
32423242
bad(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
32433243
bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
32443244

3245-
ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
3246-
ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
3247-
ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
3248-
ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
3245+
ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
3246+
ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
3247+
ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
3248+
bad(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
32493249

32503250
bad(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
32513251
bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
@@ -6387,3 +6387,21 @@ func TestAliasNames(t *testing.T) {
63876387
t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want)
63886388
}
63896389
}
6390+
6391+
func TestIssue22031(t *testing.T) {
6392+
type s []struct{ C int }
6393+
6394+
type t1 struct{ s }
6395+
type t2 struct{ f s }
6396+
6397+
tests := []Value{
6398+
ValueOf(t1{s{{}}}).Field(0).Index(0).Field(0),
6399+
ValueOf(t2{s{{}}}).Field(0).Index(0).Field(0),
6400+
}
6401+
6402+
for i, test := range tests {
6403+
if test.CanSet() {
6404+
t.Errorf("%d: CanSet: got true, want false", i)
6405+
}
6406+
}
6407+
}

src/reflect/value.go

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ func (f flag) kind() Kind {
8080
return Kind(f & flagKindMask)
8181
}
8282

83+
func (f flag) ro() flag {
84+
if f&flagRO != 0 {
85+
return flagStickyRO
86+
}
87+
return 0
88+
}
89+
8390
// pointer returns the underlying pointer represented by v.
8491
// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
8592
func (v Value) pointer() unsafe.Pointer {
@@ -237,7 +244,7 @@ func (v Value) Addr() Value {
237244
if v.flag&flagAddr == 0 {
238245
panic("reflect.Value.Addr of unaddressable value")
239246
}
240-
return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)}
247+
return Value{v.typ.ptrTo(), v.ptr, v.flag.ro() | flag(Ptr)}
241248
}
242249

243250
// Bool returns v's underlying value.
@@ -736,7 +743,7 @@ func (v Value) Elem() Value {
736743
}
737744
x := unpackEface(eface)
738745
if x.flag != 0 {
739-
x.flag |= v.flag & flagRO
746+
x.flag |= v.flag.ro()
740747
}
741748
return x
742749
case Ptr:
@@ -865,7 +872,7 @@ func (v Value) Index(i int) Value {
865872
// In the latter case, we must be doing Index(0), so offset = 0,
866873
// so v.ptr + offset is still okay.
867874
val := unsafe.Pointer(uintptr(v.ptr) + offset)
868-
fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind()) // bits same as overall array
875+
fl := v.flag&(flagIndir|flagAddr) | v.flag.ro() | flag(typ.Kind()) // bits same as overall array
869876
return Value{typ, val, fl}
870877

871878
case Slice:
@@ -878,7 +885,7 @@ func (v Value) Index(i int) Value {
878885
tt := (*sliceType)(unsafe.Pointer(v.typ))
879886
typ := tt.elem
880887
val := arrayAt(s.Data, i, typ.size)
881-
fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind())
888+
fl := flagAddr | flagIndir | v.flag.ro() | flag(typ.Kind())
882889
return Value{typ, val, fl}
883890

884891
case String:
@@ -887,7 +894,7 @@ func (v Value) Index(i int) Value {
887894
panic("reflect: string index out of range")
888895
}
889896
p := arrayAt(s.Data, i, 1)
890-
fl := v.flag&flagRO | flag(Uint8) | flagIndir
897+
fl := v.flag.ro() | flag(Uint8) | flagIndir
891898
return Value{uint8Type, p, fl}
892899
}
893900
panic(&ValueError{"reflect.Value.Index", v.kind()})
@@ -1065,7 +1072,7 @@ func (v Value) MapIndex(key Value) Value {
10651072
return Value{}
10661073
}
10671074
typ := tt.elem
1068-
fl := (v.flag | key.flag) & flagRO
1075+
fl := (v.flag | key.flag).ro()
10691076
fl |= flag(typ.Kind())
10701077
if ifaceIndir(typ) {
10711078
// Copy result so future changes to the map
@@ -1087,7 +1094,7 @@ func (v Value) MapKeys() []Value {
10871094
tt := (*mapType)(unsafe.Pointer(v.typ))
10881095
keyType := tt.key
10891096

1090-
fl := v.flag&flagRO | flag(keyType.Kind())
1097+
fl := v.flag.ro() | flag(keyType.Kind())
10911098

10921099
m := v.pointer()
10931100
mlen := int(0)
@@ -1591,7 +1598,7 @@ func (v Value) Slice(i, j int) Value {
15911598
s.Data = base
15921599
}
15931600

1594-
fl := v.flag&flagRO | flagIndir | flag(Slice)
1601+
fl := v.flag.ro() | flagIndir | flag(Slice)
15951602
return Value{typ.common(), unsafe.Pointer(&x), fl}
15961603
}
15971604

@@ -1643,7 +1650,7 @@ func (v Value) Slice3(i, j, k int) Value {
16431650
s.Data = base
16441651
}
16451652

1646-
fl := v.flag&flagRO | flagIndir | flag(Slice)
1653+
fl := v.flag.ro() | flagIndir | flag(Slice)
16471654
return Value{typ.common(), unsafe.Pointer(&x), fl}
16481655
}
16491656

@@ -2170,7 +2177,7 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
21702177
case directlyAssignable(dst, v.typ):
21712178
// Overwrite type so that they match.
21722179
// Same memory layout, so no harm done.
2173-
fl := v.flag & (flagRO | flagAddr | flagIndir)
2180+
fl := v.flag&(flagAddr|flagIndir) | v.flag.ro()
21742181
fl |= flag(dst.Kind())
21752182
return Value{dst, v.ptr, fl}
21762183

@@ -2362,72 +2369,72 @@ func makeRunes(f flag, v []rune, t Type) Value {
23622369

23632370
// convertOp: intXX -> [u]intXX
23642371
func cvtInt(v Value, t Type) Value {
2365-
return makeInt(v.flag&flagRO, uint64(v.Int()), t)
2372+
return makeInt(v.flag.ro(), uint64(v.Int()), t)
23662373
}
23672374

23682375
// convertOp: uintXX -> [u]intXX
23692376
func cvtUint(v Value, t Type) Value {
2370-
return makeInt(v.flag&flagRO, v.Uint(), t)
2377+
return makeInt(v.flag.ro(), v.Uint(), t)
23712378
}
23722379

23732380
// convertOp: floatXX -> intXX
23742381
func cvtFloatInt(v Value, t Type) Value {
2375-
return makeInt(v.flag&flagRO, uint64(int64(v.Float())), t)
2382+
return makeInt(v.flag.ro(), uint64(int64(v.Float())), t)
23762383
}
23772384

23782385
// convertOp: floatXX -> uintXX
23792386
func cvtFloatUint(v Value, t Type) Value {
2380-
return makeInt(v.flag&flagRO, uint64(v.Float()), t)
2387+
return makeInt(v.flag.ro(), uint64(v.Float()), t)
23812388
}
23822389

23832390
// convertOp: intXX -> floatXX
23842391
func cvtIntFloat(v Value, t Type) Value {
2385-
return makeFloat(v.flag&flagRO, float64(v.Int()), t)
2392+
return makeFloat(v.flag.ro(), float64(v.Int()), t)
23862393
}
23872394

23882395
// convertOp: uintXX -> floatXX
23892396
func cvtUintFloat(v Value, t Type) Value {
2390-
return makeFloat(v.flag&flagRO, float64(v.Uint()), t)
2397+
return makeFloat(v.flag.ro(), float64(v.Uint()), t)
23912398
}
23922399

23932400
// convertOp: floatXX -> floatXX
23942401
func cvtFloat(v Value, t Type) Value {
2395-
return makeFloat(v.flag&flagRO, v.Float(), t)
2402+
return makeFloat(v.flag.ro(), v.Float(), t)
23962403
}
23972404

23982405
// convertOp: complexXX -> complexXX
23992406
func cvtComplex(v Value, t Type) Value {
2400-
return makeComplex(v.flag&flagRO, v.Complex(), t)
2407+
return makeComplex(v.flag.ro(), v.Complex(), t)
24012408
}
24022409

24032410
// convertOp: intXX -> string
24042411
func cvtIntString(v Value, t Type) Value {
2405-
return makeString(v.flag&flagRO, string(v.Int()), t)
2412+
return makeString(v.flag.ro(), string(v.Int()), t)
24062413
}
24072414

24082415
// convertOp: uintXX -> string
24092416
func cvtUintString(v Value, t Type) Value {
2410-
return makeString(v.flag&flagRO, string(v.Uint()), t)
2417+
return makeString(v.flag.ro(), string(v.Uint()), t)
24112418
}
24122419

24132420
// convertOp: []byte -> string
24142421
func cvtBytesString(v Value, t Type) Value {
2415-
return makeString(v.flag&flagRO, string(v.Bytes()), t)
2422+
return makeString(v.flag.ro(), string(v.Bytes()), t)
24162423
}
24172424

24182425
// convertOp: string -> []byte
24192426
func cvtStringBytes(v Value, t Type) Value {
2420-
return makeBytes(v.flag&flagRO, []byte(v.String()), t)
2427+
return makeBytes(v.flag.ro(), []byte(v.String()), t)
24212428
}
24222429

24232430
// convertOp: []rune -> string
24242431
func cvtRunesString(v Value, t Type) Value {
2425-
return makeString(v.flag&flagRO, string(v.runes()), t)
2432+
return makeString(v.flag.ro(), string(v.runes()), t)
24262433
}
24272434

24282435
// convertOp: string -> []rune
24292436
func cvtStringRunes(v Value, t Type) Value {
2430-
return makeRunes(v.flag&flagRO, []rune(v.String()), t)
2437+
return makeRunes(v.flag.ro(), []rune(v.String()), t)
24312438
}
24322439

24332440
// convertOp: direct copy
@@ -2442,7 +2449,7 @@ func cvtDirect(v Value, typ Type) Value {
24422449
ptr = c
24432450
f &^= flagAddr
24442451
}
2445-
return Value{t, ptr, v.flag&flagRO | f} // v.flag&flagRO|f == f?
2452+
return Value{t, ptr, v.flag.ro() | f} // v.flag.ro()|f == f?
24462453
}
24472454

24482455
// convertOp: concrete -> interface
@@ -2454,14 +2461,14 @@ func cvtT2I(v Value, typ Type) Value {
24542461
} else {
24552462
ifaceE2I(typ.(*rtype), x, target)
24562463
}
2457-
return Value{typ.common(), target, v.flag&flagRO | flagIndir | flag(Interface)}
2464+
return Value{typ.common(), target, v.flag.ro() | flagIndir | flag(Interface)}
24582465
}
24592466

24602467
// convertOp: interface -> interface
24612468
func cvtI2I(v Value, typ Type) Value {
24622469
if v.IsNil() {
24632470
ret := Zero(typ)
2464-
ret.flag |= v.flag & flagRO
2471+
ret.flag |= v.flag.ro()
24652472
return ret
24662473
}
24672474
return cvtT2I(v.Elem(), typ)

0 commit comments

Comments
 (0)