Skip to content

Commit 4c003f6

Browse files
kezhuwmdempsky
authored andcommitted
reflect: keep RO flags unchanged in Value.Addr
Currently, Value.Addr collapses flagRO, which is a combination of flagEmbedRO and flagStickyRO, to flagStickyRO. This causes exported fields of unexported anonymous field from Value.Addr.Elem read only. This commit fix this by keeping all bits of flagRO from origin value in Value.Addr. This should be safe due to following reasons: * Result of Value.Addr is not CanSet because of it is not CanAddr but not flagRO. * Addr.Elem get same flagRO as origin, so it should behave same as origin in CanSet. Fixes #32772. Change-Id: I79e086628c0fb6569a50ce63f3b95916f997eda1 GitHub-Last-Rev: 78e280e GitHub-Pull-Request: #32787 Reviewed-on: https://go-review.googlesource.com/c/go/+/183937 Reviewed-by: Matthew Dempsky <[email protected]> Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent a1ffbe9 commit 4c003f6

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

src/reflect/all_test.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ func TestCanSetField(t *testing.T) {
350350
}
351351

352352
type testCase struct {
353+
// -1 means Addr().Elem() of current value
353354
index []int
354355
canSet bool
355356
}
@@ -360,35 +361,65 @@ func TestCanSetField(t *testing.T) {
360361
val: ValueOf(&S1{}),
361362
cases: []testCase{
362363
{[]int{0}, false},
364+
{[]int{0, -1}, false},
363365
{[]int{0, 0}, false},
366+
{[]int{0, 0, -1}, false},
367+
{[]int{0, -1, 0}, false},
368+
{[]int{0, -1, 0, -1}, false},
364369
{[]int{0, 1}, true},
370+
{[]int{0, 1, -1}, true},
371+
{[]int{0, -1, 1}, true},
372+
{[]int{0, -1, 1, -1}, true},
365373
{[]int{1}, false},
374+
{[]int{1, -1}, false},
366375
{[]int{2}, true},
376+
{[]int{2, -1}, true},
367377
},
368378
}, {
369379
val: ValueOf(&S2{embed: &embed{}}),
370380
cases: []testCase{
371381
{[]int{0}, false},
382+
{[]int{0, -1}, false},
372383
{[]int{0, 0}, false},
384+
{[]int{0, 0, -1}, false},
385+
{[]int{0, -1, 0}, false},
386+
{[]int{0, -1, 0, -1}, false},
373387
{[]int{0, 1}, true},
388+
{[]int{0, 1, -1}, true},
389+
{[]int{0, -1, 1}, true},
390+
{[]int{0, -1, 1, -1}, true},
374391
{[]int{1}, false},
375392
{[]int{2}, true},
376393
},
377394
}, {
378395
val: ValueOf(&S3{}),
379396
cases: []testCase{
380397
{[]int{0}, true},
398+
{[]int{0, -1}, true},
381399
{[]int{0, 0}, false},
400+
{[]int{0, 0, -1}, false},
401+
{[]int{0, -1, 0}, false},
402+
{[]int{0, -1, 0, -1}, false},
382403
{[]int{0, 1}, true},
404+
{[]int{0, 1, -1}, true},
405+
{[]int{0, -1, 1}, true},
406+
{[]int{0, -1, 1, -1}, true},
383407
{[]int{1}, false},
384408
{[]int{2}, true},
385409
},
386410
}, {
387411
val: ValueOf(&S4{Embed: &Embed{}}),
388412
cases: []testCase{
389413
{[]int{0}, true},
414+
{[]int{0, -1}, true},
390415
{[]int{0, 0}, false},
416+
{[]int{0, 0, -1}, false},
417+
{[]int{0, -1, 0}, false},
418+
{[]int{0, -1, 0, -1}, false},
391419
{[]int{0, 1}, true},
420+
{[]int{0, 1, -1}, true},
421+
{[]int{0, -1, 1}, true},
422+
{[]int{0, -1, 1, -1}, true},
392423
{[]int{1}, false},
393424
{[]int{2}, true},
394425
},
@@ -402,7 +433,11 @@ func TestCanSetField(t *testing.T) {
402433
if f.Kind() == Ptr {
403434
f = f.Elem()
404435
}
405-
f = f.Field(i)
436+
if i == -1 {
437+
f = f.Addr().Elem()
438+
} else {
439+
f = f.Field(i)
440+
}
406441
}
407442
if got := f.CanSet(); got != tc.canSet {
408443
t.Errorf("CanSet() = %v, want %v", got, tc.canSet)

src/reflect/value.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,10 @@ func (v Value) Addr() Value {
269269
if v.flag&flagAddr == 0 {
270270
panic("reflect.Value.Addr of unaddressable value")
271271
}
272-
return Value{v.typ.ptrTo(), v.ptr, v.flag.ro() | flag(Ptr)}
272+
// Preserve flagRO instead of using v.flag.ro() so that
273+
// v.Addr().Elem() is equivalent to v (#32772)
274+
fl := v.flag & flagRO
275+
return Value{v.typ.ptrTo(), v.ptr, fl | flag(Ptr)}
273276
}
274277

275278
// Bool returns v's underlying value.

0 commit comments

Comments
 (0)