reflect: disallow Interface method on Value obtained via unexported name

Had been allowing it for use by fmt, but it is too hard to lock down.
Fix other packages not to depend on it.

R=r, r
CC=golang-dev
https://golang.org/cl/5266054
This commit is contained in:
Russ Cox 2011-10-17 18:48:45 -04:00
parent e5f3dc8bc5
commit 304cf4dc9b
6 changed files with 288 additions and 167 deletions

View file

@ -853,13 +853,13 @@ func TestIsNil(t *testing.T) {
func TestInterfaceExtraction(t *testing.T) {
var s struct {
w io.Writer
W io.Writer
}
s.w = os.Stdout
s.W = os.Stdout
v := Indirect(ValueOf(&s)).Field(0).Interface()
if v != s.w.(interface{}) {
t.Error("Interface() on interface: ", v, s.w)
if v != s.W.(interface{}) {
t.Error("Interface() on interface: ", v, s.W)
}
}
@ -1190,18 +1190,18 @@ type D2 struct {
}
type S0 struct {
a, b, c int
A, B, C int
D1
D2
}
type S1 struct {
b int
B int
S0
}
type S2 struct {
a int
A int
*S1
}
@ -1216,36 +1216,36 @@ type S1y struct {
type S3 struct {
S1x
S2
d, e int
D, E int
*S1y
}
type S4 struct {
*S4
a int
A int
}
var fieldTests = []FTest{
{struct{}{}, "", nil, 0},
{struct{}{}, "foo", nil, 0},
{S0{a: 'a'}, "a", []int{0}, 'a'},
{S0{}, "d", nil, 0},
{S1{S0: S0{a: 'a'}}, "a", []int{1, 0}, 'a'},
{S1{b: 'b'}, "b", []int{0}, 'b'},
{struct{}{}, "Foo", nil, 0},
{S0{A: 'a'}, "A", []int{0}, 'a'},
{S0{}, "D", nil, 0},
{S1{S0: S0{A: 'a'}}, "A", []int{1, 0}, 'a'},
{S1{B: 'b'}, "B", []int{0}, 'b'},
{S1{}, "S0", []int{1}, 0},
{S1{S0: S0{c: 'c'}}, "c", []int{1, 2}, 'c'},
{S2{a: 'a'}, "a", []int{0}, 'a'},
{S1{S0: S0{C: 'c'}}, "C", []int{1, 2}, 'c'},
{S2{A: 'a'}, "A", []int{0}, 'a'},
{S2{}, "S1", []int{1}, 0},
{S2{S1: &S1{b: 'b'}}, "b", []int{1, 0}, 'b'},
{S2{S1: &S1{S0: S0{c: 'c'}}}, "c", []int{1, 1, 2}, 'c'},
{S2{}, "d", nil, 0},
{S2{S1: &S1{B: 'b'}}, "B", []int{1, 0}, 'b'},
{S2{S1: &S1{S0: S0{C: 'c'}}}, "C", []int{1, 1, 2}, 'c'},
{S2{}, "D", nil, 0},
{S3{}, "S1", nil, 0},
{S3{S2: S2{a: 'a'}}, "a", []int{1, 0}, 'a'},
{S3{}, "b", nil, 0},
{S3{d: 'd'}, "d", []int{2}, 0},
{S3{e: 'e'}, "e", []int{3}, 'e'},
{S4{a: 'a'}, "a", []int{1}, 'a'},
{S4{}, "b", nil, 0},
{S3{S2: S2{A: 'a'}}, "A", []int{1, 0}, 'a'},
{S3{}, "B", nil, 0},
{S3{D: 'd'}, "D", []int{2}, 0},
{S3{E: 'e'}, "E", []int{3}, 'e'},
{S4{A: 'a'}, "A", []int{1}, 'a'},
{S4{}, "B", nil, 0},
}
func TestFieldByIndex(t *testing.T) {
@ -1587,3 +1587,68 @@ func TestSetBytes(t *testing.T) {
t.Errorf("ValueOf(%p).Bytes() = %p", &x[0], &y[0])
}
}
type Private struct {
x int
y **int
}
func (p *Private) m() {
}
type Public struct {
X int
Y **int
}
func (p *Public) M() {
}
func TestUnexported(t *testing.T) {
var pub Public
v := ValueOf(&pub)
isValid(v.Elem().Field(0))
isValid(v.Elem().Field(1))
isValid(v.Elem().FieldByName("X"))
isValid(v.Elem().FieldByName("Y"))
isValid(v.Type().Method(0).Func)
isNonNil(v.Elem().Field(0).Interface())
isNonNil(v.Elem().Field(1).Interface())
isNonNil(v.Elem().FieldByName("X").Interface())
isNonNil(v.Elem().FieldByName("Y").Interface())
isNonNil(v.Type().Method(0).Func.Interface())
var priv Private
v = ValueOf(&priv)
isValid(v.Elem().Field(0))
isValid(v.Elem().Field(1))
isValid(v.Elem().FieldByName("x"))
isValid(v.Elem().FieldByName("y"))
isValid(v.Type().Method(0).Func)
shouldPanic(func() { v.Elem().Field(0).Interface() })
shouldPanic(func() { v.Elem().Field(1).Interface() })
shouldPanic(func() { v.Elem().FieldByName("x").Interface() })
shouldPanic(func() { v.Elem().FieldByName("y").Interface() })
shouldPanic(func() { v.Type().Method(0).Func.Interface() })
}
func shouldPanic(f func()) {
defer func() {
if recover() == nil {
panic("did not panic")
}
}()
f()
}
func isNonNil(x interface{}) {
if x == nil {
panic("nil interface")
}
}
func isValid(v Value) {
if !v.IsValid() {
panic("zero Value")
}
}