]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/gc: make embedded unexported structs RO
authorMarcel van Lohuizen <mpvl@golang.org>
Mon, 31 Aug 2015 20:24:07 +0000 (22:24 +0200)
committerMarcel van Lohuizen <mpvl@golang.org>
Mon, 26 Oct 2015 13:57:48 +0000 (13:57 +0000)
gc will need to be rebuild.

Package that assume f.PkgPath != nil means a field is unexported and
must be ignored must be revised to check for
f.PkgPath != nil && !f.Anonymous,
so that they do try to walk into the embedded fields to look for
exported fields contained within.

Closes #12367, fixes #7363, fixes #11007, and fixes #7247.

Change-Id: I16402ee21ccfede80f277f84b3995cf26e97433d
Reviewed-on: https://go-review.googlesource.com/14085
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/compile/internal/gc/reflect.go
src/reflect/all_test.go

index 99ad619d8cb057adcbc4713cae0c9849d66fcd98..d1b18ff939bbe7c7dde68361aa1f0b76c4bf2293 100644 (file)
@@ -1180,7 +1180,8 @@ ok:
                                }
                        } else {
                                ot = dgostringptr(s, ot, "")
-                               if t1.Type.Sym != nil && t1.Type.Sym.Pkg == builtinpkg {
+                               if t1.Type.Sym != nil &&
+                                       (t1.Type.Sym.Pkg == builtinpkg || !exportname(t1.Type.Sym.Name)) {
                                        ot = dgopkgpath(s, ot, localpkg)
                                } else {
                                        ot = dgostringptr(s, ot, "")
index 1748bf6630ad980014d035b544332fbc7b7998ea..11ab63a3ce92aafe26aa6cf554f05a5bd71bb21f 100644 (file)
@@ -2776,14 +2776,27 @@ func TestSetBytes(t *testing.T) {
 type Private struct {
        x int
        y **int
+       Z int
 }
 
 func (p *Private) m() {
 }
 
+type private struct {
+       Z int
+       z int
+       S string
+       A [1]Private
+       T []Private
+}
+
+func (p *private) P() {
+}
+
 type Public struct {
        X int
        Y **int
+       private
 }
 
 func (p *Public) M() {
@@ -2791,17 +2804,30 @@ func (p *Public) M() {
 
 func TestUnexported(t *testing.T) {
        var pub Public
+       pub.S = "S"
+       pub.T = pub.A[:]
        v := ValueOf(&pub)
        isValid(v.Elem().Field(0))
        isValid(v.Elem().Field(1))
+       isValid(v.Elem().Field(2))
        isValid(v.Elem().FieldByName("X"))
        isValid(v.Elem().FieldByName("Y"))
+       isValid(v.Elem().FieldByName("Z"))
        isValid(v.Type().Method(0).Func)
+       m, _ := v.Type().MethodByName("M")
+       isValid(m.Func)
+       m, _ = v.Type().MethodByName("P")
+       isValid(m.Func)
        isNonNil(v.Elem().Field(0).Interface())
        isNonNil(v.Elem().Field(1).Interface())
+       isNonNil(v.Elem().Field(2).Field(2).Index(0))
        isNonNil(v.Elem().FieldByName("X").Interface())
        isNonNil(v.Elem().FieldByName("Y").Interface())
+       isNonNil(v.Elem().FieldByName("Z").Interface())
+       isNonNil(v.Elem().FieldByName("S").Index(0).Interface())
        isNonNil(v.Type().Method(0).Func.Interface())
+       m, _ = v.Type().MethodByName("P")
+       isNonNil(m.Func.Interface())
 
        var priv Private
        v = ValueOf(&priv)
@@ -2817,6 +2843,170 @@ func TestUnexported(t *testing.T) {
        shouldPanic(func() { v.Type().Method(0).Func.Interface() })
 }
 
+func TestSetPanic(t *testing.T) {
+       ok := func(f func()) { f() }
+       bad := shouldPanic
+       clear := func(v Value) { v.Set(Zero(v.Type())) }
+
+       type t0 struct {
+               W int
+       }
+
+       type t1 struct {
+               Y int
+               t0
+       }
+
+       type T2 struct {
+               Z       int
+               namedT0 t0
+       }
+
+       type T struct {
+               X int
+               t1
+               T2
+               NamedT1 t1
+               NamedT2 T2
+               namedT1 t1
+               namedT2 T2
+       }
+
+       // not addressable
+       v := ValueOf(T{})
+       bad(func() { clear(v.Field(0)) })                   // .X
+       bad(func() { clear(v.Field(1)) })                   // .t1
+       bad(func() { clear(v.Field(1).Field(0)) })          // .t1.Y
+       bad(func() { clear(v.Field(1).Field(1)) })          // .t1.t0
+       bad(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
+       bad(func() { clear(v.Field(2)) })                   // .T2
+       bad(func() { clear(v.Field(2).Field(0)) })          // .T2.Z
+       bad(func() { clear(v.Field(2).Field(1)) })          // .T2.namedT0
+       bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
+       bad(func() { clear(v.Field(3)) })                   // .NamedT1
+       bad(func() { clear(v.Field(3).Field(0)) })          // .NamedT1.Y
+       bad(func() { clear(v.Field(3).Field(1)) })          // .NamedT1.t0
+       bad(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
+       bad(func() { clear(v.Field(4)) })                   // .NamedT2
+       bad(func() { clear(v.Field(4).Field(0)) })          // .NamedT2.Z
+       bad(func() { clear(v.Field(4).Field(1)) })          // .NamedT2.namedT0
+       bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
+       bad(func() { clear(v.Field(5)) })                   // .namedT1
+       bad(func() { clear(v.Field(5).Field(0)) })          // .namedT1.Y
+       bad(func() { clear(v.Field(5).Field(1)) })          // .namedT1.t0
+       bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
+       bad(func() { clear(v.Field(6)) })                   // .namedT2
+       bad(func() { clear(v.Field(6).Field(0)) })          // .namedT2.Z
+       bad(func() { clear(v.Field(6).Field(1)) })          // .namedT2.namedT0
+       bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
+
+       // addressable
+       v = ValueOf(&T{}).Elem()
+       ok(func() { clear(v.Field(0)) })                    // .X
+       bad(func() { clear(v.Field(1)) })                   // .t1
+       ok(func() { clear(v.Field(1).Field(0)) })           // .t1.Y
+       bad(func() { clear(v.Field(1).Field(1)) })          // .t1.t0
+       ok(func() { clear(v.Field(1).Field(1).Field(0)) })  // .t1.t0.W
+       ok(func() { clear(v.Field(2)) })                    // .T2
+       ok(func() { clear(v.Field(2).Field(0)) })           // .T2.Z
+       bad(func() { clear(v.Field(2).Field(1)) })          // .T2.namedT0
+       bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
+       ok(func() { clear(v.Field(3)) })                    // .NamedT1
+       ok(func() { clear(v.Field(3).Field(0)) })           // .NamedT1.Y
+       bad(func() { clear(v.Field(3).Field(1)) })          // .NamedT1.t0
+       ok(func() { clear(v.Field(3).Field(1).Field(0)) })  // .NamedT1.t0.W
+       ok(func() { clear(v.Field(4)) })                    // .NamedT2
+       ok(func() { clear(v.Field(4).Field(0)) })           // .NamedT2.Z
+       bad(func() { clear(v.Field(4).Field(1)) })          // .NamedT2.namedT0
+       bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
+       bad(func() { clear(v.Field(5)) })                   // .namedT1
+       bad(func() { clear(v.Field(5).Field(0)) })          // .namedT1.Y
+       bad(func() { clear(v.Field(5).Field(1)) })          // .namedT1.t0
+       bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
+       bad(func() { clear(v.Field(6)) })                   // .namedT2
+       bad(func() { clear(v.Field(6).Field(0)) })          // .namedT2.Z
+       bad(func() { clear(v.Field(6).Field(1)) })          // .namedT2.namedT0
+       bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
+}
+
+type timp int
+
+func (t timp) W() {}
+func (t timp) Y() {}
+func (t timp) w() {}
+func (t timp) y() {}
+
+func TestCallPanic(t *testing.T) {
+       type t0 interface {
+               W()
+               w()
+       }
+       type T1 interface {
+               Y()
+               y()
+       }
+       type T2 struct {
+               T1
+               t0
+       }
+       type T struct {
+               t0 // 0
+               T1 // 1
+
+               NamedT0 t0 // 2
+               NamedT1 T1 // 3
+               NamedT2 T2 // 4
+
+               namedT0 t0 // 5
+               namedT1 T1 // 6
+               namedT2 T2 // 7
+       }
+       ok := func(f func()) { f() }
+       bad := shouldPanic
+       call := func(v Value) { v.Call(nil) }
+
+       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
+       ok(func() { call(v.Field(0).Elem().Method(0)) })  // .t0.W
+       bad(func() { call(v.Field(0).Method(1)) })        // .t0.w
+       bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
+       ok(func() { call(v.Field(1).Method(0)) })         // .T1.Y
+       ok(func() { call(v.Field(1).Elem().Method(0)) })  // .T1.Y
+       bad(func() { call(v.Field(1).Method(1)) })        // .T1.y
+       bad(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y
+
+       ok(func() { call(v.Field(2).Method(0)) })         // .NamedT0.W
+       ok(func() { call(v.Field(2).Elem().Method(0)) })  // .NamedT0.W
+       bad(func() { call(v.Field(2).Method(1)) })        // .NamedT0.w
+       bad(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w
+
+       ok(func() { call(v.Field(3).Method(0)) })         // .NamedT1.Y
+       ok(func() { call(v.Field(3).Elem().Method(0)) })  // .NamedT1.Y
+       bad(func() { call(v.Field(3).Method(1)) })        // .NamedT1.y
+       bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
+
+       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
+       ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
+
+       bad(func() { call(v.Field(5).Method(0)) })        // .namedT0.W
+       bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
+       bad(func() { call(v.Field(5).Method(1)) })        // .namedT0.w
+       bad(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w
+
+       bad(func() { call(v.Field(6).Method(0)) })        // .namedT1.Y
+       bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.Y
+       bad(func() { call(v.Field(6).Method(0)) })        // .namedT1.y
+       bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.y
+
+       bad(func() { call(v.Field(7).Field(0).Method(0)) })        // .namedT2.T1.Y
+       bad(func() { call(v.Field(7).Field(0).Elem().Method(0)) }) // .namedT2.T1.W
+       bad(func() { call(v.Field(7).Field(1).Method(0)) })        // .namedT2.t0.W
+       bad(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W
+}
+
 func shouldPanic(f func()) {
        defer func() {
                if recover() == nil {