aboutsummaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2020-04-19 13:59:16 -0700
committerMatthew Dempsky <mdempsky@google.com>2020-04-21 05:41:33 +0000
commit0eb694e9c217c051cd8cc18258bf593d0be7fb8d (patch)
tree40d746cd173648d4bf00fc78486eac4494a16964 /src/reflect
parent925516309128f20bb11a38f3e5265f23360a28ba (diff)
downloadgo-0eb694e9c217c051cd8cc18258bf593d0be7fb8d.tar.gz
go-0eb694e9c217c051cd8cc18258bf593d0be7fb8d.zip
reflect: disallow invoking methods on unexported embedded fields
Given: type u struct{} func (u) M() {} type t struct { u; u2 u } var v = reflect.ValueOf(t{}) Package reflect allows: v.Method(0) // v.M v.Field(0).Method(0) // v.u.M but panics from: v.Field(1).Method(0) // v.u2.M because u2 is not an exported field. However, u is not an exported field either, so this is inconsistent. It seems like this behavior originates from #12367, where it was decided to allow traversing unexported embedded fields to be able to access their exported fields, since package reflect doesn't provide an alternative way to access promoted fields directly. But extending that logic to promoted *methods* was inappropriate, because package reflect's normal method handling logic already handles promoted methods correctly. This CL corrects that mistake. Fixes #38521. Change-Id: If65008965f35927b4e7927cddf8614695288eb19 Reviewed-on: https://go-review.googlesource.com/c/go/+/228902 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/all_test.go4
-rw-r--r--src/reflect/value.go2
2 files changed, 3 insertions, 3 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index cb0c8344f3..3129ff8e5d 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -3567,7 +3567,7 @@ func TestCallPanic(t *testing.T) {
i := timp(0)
v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
- ok(func() { call(v.Field(0).Method(0)) }) // .t0.W
+ badCall(func() { call(v.Field(0).Method(0)) }) // .t0.W
badCall(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
badCall(func() { call(v.Field(0).Method(1)) }) // .t0.w
badMethod(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
@@ -3588,7 +3588,7 @@ func TestCallPanic(t *testing.T) {
ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
- ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
+ badCall(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
badCall(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
badCall(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 57ac65e084..de6f22b5b3 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1315,7 +1315,7 @@ func (v Value) Method(i int) Value {
if v.typ.Kind() == Interface && v.IsNil() {
panic("reflect: Method on nil interface value")
}
- fl := v.flag & (flagStickyRO | flagIndir) // Clear flagEmbedRO
+ fl := v.flag.ro() | (v.flag & flagIndir)
fl |= flag(Func)
fl |= flag(i)<<flagMethodShift | flagMethod
return Value{v.typ, v.ptr, fl}