Skip to content

Commit afe9837

Browse files
committed
cmd/compile/internal/gc: make embedded unexported structs RO
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 <[email protected]>
1 parent 34f04a6 commit afe9837

File tree

2 files changed

+192
-1
lines changed

2 files changed

+192
-1
lines changed

src/cmd/compile/internal/gc/reflect.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,8 @@ ok:
11801180
}
11811181
} else {
11821182
ot = dgostringptr(s, ot, "")
1183-
if t1.Type.Sym != nil && t1.Type.Sym.Pkg == builtinpkg {
1183+
if t1.Type.Sym != nil &&
1184+
(t1.Type.Sym.Pkg == builtinpkg || !exportname(t1.Type.Sym.Name)) {
11841185
ot = dgopkgpath(s, ot, localpkg)
11851186
} else {
11861187
ot = dgostringptr(s, ot, "")

src/reflect/all_test.go

+190
Original file line numberDiff line numberDiff line change
@@ -2776,32 +2776,58 @@ func TestSetBytes(t *testing.T) {
27762776
type Private struct {
27772777
x int
27782778
y **int
2779+
Z int
27792780
}
27802781

27812782
func (p *Private) m() {
27822783
}
27832784

2785+
type private struct {
2786+
Z int
2787+
z int
2788+
S string
2789+
A [1]Private
2790+
T []Private
2791+
}
2792+
2793+
func (p *private) P() {
2794+
}
2795+
27842796
type Public struct {
27852797
X int
27862798
Y **int
2799+
private
27872800
}
27882801

27892802
func (p *Public) M() {
27902803
}
27912804

27922805
func TestUnexported(t *testing.T) {
27932806
var pub Public
2807+
pub.S = "S"
2808+
pub.T = pub.A[:]
27942809
v := ValueOf(&pub)
27952810
isValid(v.Elem().Field(0))
27962811
isValid(v.Elem().Field(1))
2812+
isValid(v.Elem().Field(2))
27972813
isValid(v.Elem().FieldByName("X"))
27982814
isValid(v.Elem().FieldByName("Y"))
2815+
isValid(v.Elem().FieldByName("Z"))
27992816
isValid(v.Type().Method(0).Func)
2817+
m, _ := v.Type().MethodByName("M")
2818+
isValid(m.Func)
2819+
m, _ = v.Type().MethodByName("P")
2820+
isValid(m.Func)
28002821
isNonNil(v.Elem().Field(0).Interface())
28012822
isNonNil(v.Elem().Field(1).Interface())
2823+
isNonNil(v.Elem().Field(2).Field(2).Index(0))
28022824
isNonNil(v.Elem().FieldByName("X").Interface())
28032825
isNonNil(v.Elem().FieldByName("Y").Interface())
2826+
isNonNil(v.Elem().FieldByName("Z").Interface())
2827+
isNonNil(v.Elem().FieldByName("S").Index(0).Interface())
28042828
isNonNil(v.Type().Method(0).Func.Interface())
2829+
m, _ = v.Type().MethodByName("P")
2830+
isNonNil(m.Func.Interface())
28052831

28062832
var priv Private
28072833
v = ValueOf(&priv)
@@ -2817,6 +2843,170 @@ func TestUnexported(t *testing.T) {
28172843
shouldPanic(func() { v.Type().Method(0).Func.Interface() })
28182844
}
28192845

2846+
func TestSetPanic(t *testing.T) {
2847+
ok := func(f func()) { f() }
2848+
bad := shouldPanic
2849+
clear := func(v Value) { v.Set(Zero(v.Type())) }
2850+
2851+
type t0 struct {
2852+
W int
2853+
}
2854+
2855+
type t1 struct {
2856+
Y int
2857+
t0
2858+
}
2859+
2860+
type T2 struct {
2861+
Z int
2862+
namedT0 t0
2863+
}
2864+
2865+
type T struct {
2866+
X int
2867+
t1
2868+
T2
2869+
NamedT1 t1
2870+
NamedT2 T2
2871+
namedT1 t1
2872+
namedT2 T2
2873+
}
2874+
2875+
// not addressable
2876+
v := ValueOf(T{})
2877+
bad(func() { clear(v.Field(0)) }) // .X
2878+
bad(func() { clear(v.Field(1)) }) // .t1
2879+
bad(func() { clear(v.Field(1).Field(0)) }) // .t1.Y
2880+
bad(func() { clear(v.Field(1).Field(1)) }) // .t1.t0
2881+
bad(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
2882+
bad(func() { clear(v.Field(2)) }) // .T2
2883+
bad(func() { clear(v.Field(2).Field(0)) }) // .T2.Z
2884+
bad(func() { clear(v.Field(2).Field(1)) }) // .T2.namedT0
2885+
bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
2886+
bad(func() { clear(v.Field(3)) }) // .NamedT1
2887+
bad(func() { clear(v.Field(3).Field(0)) }) // .NamedT1.Y
2888+
bad(func() { clear(v.Field(3).Field(1)) }) // .NamedT1.t0
2889+
bad(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
2890+
bad(func() { clear(v.Field(4)) }) // .NamedT2
2891+
bad(func() { clear(v.Field(4).Field(0)) }) // .NamedT2.Z
2892+
bad(func() { clear(v.Field(4).Field(1)) }) // .NamedT2.namedT0
2893+
bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
2894+
bad(func() { clear(v.Field(5)) }) // .namedT1
2895+
bad(func() { clear(v.Field(5).Field(0)) }) // .namedT1.Y
2896+
bad(func() { clear(v.Field(5).Field(1)) }) // .namedT1.t0
2897+
bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
2898+
bad(func() { clear(v.Field(6)) }) // .namedT2
2899+
bad(func() { clear(v.Field(6).Field(0)) }) // .namedT2.Z
2900+
bad(func() { clear(v.Field(6).Field(1)) }) // .namedT2.namedT0
2901+
bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
2902+
2903+
// addressable
2904+
v = ValueOf(&T{}).Elem()
2905+
ok(func() { clear(v.Field(0)) }) // .X
2906+
bad(func() { clear(v.Field(1)) }) // .t1
2907+
ok(func() { clear(v.Field(1).Field(0)) }) // .t1.Y
2908+
bad(func() { clear(v.Field(1).Field(1)) }) // .t1.t0
2909+
ok(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
2910+
ok(func() { clear(v.Field(2)) }) // .T2
2911+
ok(func() { clear(v.Field(2).Field(0)) }) // .T2.Z
2912+
bad(func() { clear(v.Field(2).Field(1)) }) // .T2.namedT0
2913+
bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
2914+
ok(func() { clear(v.Field(3)) }) // .NamedT1
2915+
ok(func() { clear(v.Field(3).Field(0)) }) // .NamedT1.Y
2916+
bad(func() { clear(v.Field(3).Field(1)) }) // .NamedT1.t0
2917+
ok(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
2918+
ok(func() { clear(v.Field(4)) }) // .NamedT2
2919+
ok(func() { clear(v.Field(4).Field(0)) }) // .NamedT2.Z
2920+
bad(func() { clear(v.Field(4).Field(1)) }) // .NamedT2.namedT0
2921+
bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
2922+
bad(func() { clear(v.Field(5)) }) // .namedT1
2923+
bad(func() { clear(v.Field(5).Field(0)) }) // .namedT1.Y
2924+
bad(func() { clear(v.Field(5).Field(1)) }) // .namedT1.t0
2925+
bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
2926+
bad(func() { clear(v.Field(6)) }) // .namedT2
2927+
bad(func() { clear(v.Field(6).Field(0)) }) // .namedT2.Z
2928+
bad(func() { clear(v.Field(6).Field(1)) }) // .namedT2.namedT0
2929+
bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
2930+
}
2931+
2932+
type timp int
2933+
2934+
func (t timp) W() {}
2935+
func (t timp) Y() {}
2936+
func (t timp) w() {}
2937+
func (t timp) y() {}
2938+
2939+
func TestCallPanic(t *testing.T) {
2940+
type t0 interface {
2941+
W()
2942+
w()
2943+
}
2944+
type T1 interface {
2945+
Y()
2946+
y()
2947+
}
2948+
type T2 struct {
2949+
T1
2950+
t0
2951+
}
2952+
type T struct {
2953+
t0 // 0
2954+
T1 // 1
2955+
2956+
NamedT0 t0 // 2
2957+
NamedT1 T1 // 3
2958+
NamedT2 T2 // 4
2959+
2960+
namedT0 t0 // 5
2961+
namedT1 T1 // 6
2962+
namedT2 T2 // 7
2963+
}
2964+
ok := func(f func()) { f() }
2965+
bad := shouldPanic
2966+
call := func(v Value) { v.Call(nil) }
2967+
2968+
i := timp(0)
2969+
v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
2970+
ok(func() { call(v.Field(0).Method(0)) }) // .t0.W
2971+
ok(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
2972+
bad(func() { call(v.Field(0).Method(1)) }) // .t0.w
2973+
bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
2974+
ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y
2975+
ok(func() { call(v.Field(1).Elem().Method(0)) }) // .T1.Y
2976+
bad(func() { call(v.Field(1).Method(1)) }) // .T1.y
2977+
bad(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y
2978+
2979+
ok(func() { call(v.Field(2).Method(0)) }) // .NamedT0.W
2980+
ok(func() { call(v.Field(2).Elem().Method(0)) }) // .NamedT0.W
2981+
bad(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w
2982+
bad(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w
2983+
2984+
ok(func() { call(v.Field(3).Method(0)) }) // .NamedT1.Y
2985+
ok(func() { call(v.Field(3).Elem().Method(0)) }) // .NamedT1.Y
2986+
bad(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
2987+
bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
2988+
2989+
ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
2990+
ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
2991+
ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
2992+
ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
2993+
2994+
bad(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
2995+
bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
2996+
bad(func() { call(v.Field(5).Method(1)) }) // .namedT0.w
2997+
bad(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w
2998+
2999+
bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.Y
3000+
bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.Y
3001+
bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.y
3002+
bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.y
3003+
3004+
bad(func() { call(v.Field(7).Field(0).Method(0)) }) // .namedT2.T1.Y
3005+
bad(func() { call(v.Field(7).Field(0).Elem().Method(0)) }) // .namedT2.T1.W
3006+
bad(func() { call(v.Field(7).Field(1).Method(0)) }) // .namedT2.t0.W
3007+
bad(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W
3008+
}
3009+
28203010
func shouldPanic(f func()) {
28213011
defer func() {
28223012
if recover() == nil {

0 commit comments

Comments
 (0)