aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/fmt/print.go
diff options
context:
space:
mode:
authorAndrew Gerrand <adg@golang.org>2011-10-18 14:06:11 +1100
committerAndrew Gerrand <adg@golang.org>2011-10-18 14:06:11 +1100
commit0584eb2e7779d5bf699702d06acb686cd08bddd2 (patch)
tree291e3db413833a248a5afbb4cb023e23ca78593e /src/pkg/fmt/print.go
parentadfa87c5d754252f2bf428b38560de3d630dbe9d (diff)
downloadgo-release-branch.r58.tar.gz
go-release-branch.r58.zip
[release-branch.r58] reflect: disallow Interface method on Value obtained via unexported namerelease.r58.2release-branch.r58
Also remove exp/datafmt that depends on the broken reflect behavior. ««« CL 5267049 / eeca0d4a91a3 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 »»» R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/5297042
Diffstat (limited to 'src/pkg/fmt/print.go')
-rw-r--r--src/pkg/fmt/print.go245
1 files changed, 151 insertions, 94 deletions
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index c18a8ea38d..1042315ed9 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -259,10 +259,8 @@ func Sprintln(a ...interface{}) string {
// the thing inside the interface, not the interface itself.
func getField(v reflect.Value, i int) reflect.Value {
val := v.Field(i)
- if i := val; i.Kind() == reflect.Interface {
- if inter := i.Interface(); inter != nil {
- return reflect.ValueOf(inter)
- }
+ if val.Kind() == reflect.Interface && !val.IsNil() {
+ val = val.Elem()
}
return val
}
@@ -289,27 +287,32 @@ func (p *pp) unknownType(v interface{}) {
p.buf.WriteByte('?')
}
-func (p *pp) badVerb(verb int, val interface{}) {
+func (p *pp) badVerb(verb int, val interface{}, val1 reflect.Value) {
p.add('%')
p.add('!')
p.add(verb)
p.add('(')
- if val == nil {
- p.buf.Write(nilAngleBytes)
- } else {
+ switch {
+ case val != nil:
p.buf.WriteString(reflect.TypeOf(val).String())
p.add('=')
p.printField(val, 'v', false, false, 0)
+ case val1.IsValid():
+ p.buf.WriteString(val1.Type().String())
+ p.add('=')
+ p.printValue(val1, 'v', false, false, 0)
+ default:
+ p.buf.Write(nilAngleBytes)
}
p.add(')')
}
-func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+func (p *pp) fmtBool(v bool, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 't', 'v':
p.fmt.fmt_boolean(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
@@ -323,7 +326,7 @@ func (p *pp) fmtC(c int64) {
p.fmt.pad(p.runeBuf[0:w])
}
-func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+func (p *pp) fmtInt64(v int64, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.integer(v, 2, signed, ldigits)
@@ -337,7 +340,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
if 0 <= v && v <= unicode.MaxRune {
p.fmt.fmt_qc(v)
} else {
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
@@ -346,7 +349,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
case 'X':
p.fmt.integer(v, 16, signed, udigits)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
@@ -376,7 +379,7 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.precPresent = precPresent
}
-func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.integer(int64(v), 2, unsigned, ldigits)
@@ -396,7 +399,7 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
if 0 <= v && v <= unicode.MaxRune {
p.fmt.fmt_qc(int64(v))
} else {
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
case 'x':
p.fmt.integer(int64(v), 16, unsigned, ldigits)
@@ -405,11 +408,11 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
case 'U':
p.fmtUnicode(int64(v))
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
-func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.fmt_fb32(v)
@@ -424,11 +427,11 @@ func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
case 'G':
p.fmt.fmt_G32(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
-func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.fmt_fb64(v)
@@ -443,33 +446,33 @@ func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
case 'G':
p.fmt.fmt_G64(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
-func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c64(v, verb)
case 'v':
p.fmt.fmt_c64(v, 'g')
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
-func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c128(v, verb)
case 'v':
p.fmt.fmt_c128(v, 'g')
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
-func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}, value1 reflect.Value) {
switch verb {
case 'v':
if goSyntax {
@@ -486,11 +489,11 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
case 'q':
p.fmt.fmt_q(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
-func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
+func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}, value1 reflect.Value) {
if verb == 'v' || verb == 'd' {
if goSyntax {
p.buf.Write(bytesBytes)
@@ -525,7 +528,7 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf
case 'q':
p.fmt.fmt_q(s)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
@@ -535,12 +538,12 @@ func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSynt
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
u = value.Pointer()
default:
- p.badVerb(verb, field)
+ p.badVerb(verb, field, value)
return
}
if goSyntax {
p.add('(')
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
p.add(')')
p.add('(')
if u == 0 {
@@ -561,12 +564,48 @@ var (
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
)
+func (p *pp) handleMethods(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString, handled bool) {
+ // Is it a Formatter?
+ if formatter, ok := field.(Formatter); ok {
+ handled = true
+ wasString = false
+ formatter.Format(p, verb)
+ return
+ }
+ // Must not touch flags before Formatter looks at them.
+ if plus {
+ p.fmt.plus = false
+ }
+
+ // If we're doing Go syntax and the field knows how to supply it, take care of it now.
+ if goSyntax {
+ p.fmt.sharp = false
+ if stringer, ok := field.(GoStringer); ok {
+ wasString = false
+ handled = true
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false, field, reflect.Value{})
+ return
+ }
+ } else {
+ // Is it a Stringer?
+ if stringer, ok := field.(Stringer); ok {
+ wasString = false
+ handled = true
+ p.printField(stringer.String(), verb, plus, false, depth)
+ return
+ }
+ }
+ handled = false
+ return
+}
+
func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
if field == nil {
if verb == 'T' || verb == 'v' {
p.buf.Write(nilAngleBytes)
} else {
- p.badVerb(verb, field)
+ p.badVerb(verb, field, reflect.Value{})
}
return false
}
@@ -581,115 +620,133 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax)
return false
}
- // Is it a Formatter?
- if formatter, ok := field.(Formatter); ok {
- formatter.Format(p, verb)
- return false // this value is not a string
- }
- // Must not touch flags before Formatter looks at them.
- if plus {
- p.fmt.plus = false
- }
- // If we're doing Go syntax and the field knows how to supply it, take care of it now.
- if goSyntax {
- p.fmt.sharp = false
- if stringer, ok := field.(GoStringer); ok {
- // Print the result of GoString unadorned.
- p.fmtString(stringer.GoString(), 's', false, field)
- return false // this value is not a string
- }
- } else {
- // Is it a Stringer?
- if stringer, ok := field.(Stringer); ok {
- p.printField(stringer.String(), verb, plus, false, depth)
- return false // this value is not a string
- }
+ if wasString, handled := p.handleMethods(field, verb, plus, goSyntax, depth); handled {
+ return wasString
}
// Some types can be done without reflection.
switch f := field.(type) {
case bool:
- p.fmtBool(f, verb, field)
+ p.fmtBool(f, verb, field, reflect.Value{})
return false
case float32:
- p.fmtFloat32(f, verb, field)
+ p.fmtFloat32(f, verb, field, reflect.Value{})
return false
case float64:
- p.fmtFloat64(f, verb, field)
+ p.fmtFloat64(f, verb, field, reflect.Value{})
return false
case complex64:
- p.fmtComplex64(complex64(f), verb, field)
+ p.fmtComplex64(complex64(f), verb, field, reflect.Value{})
return false
case complex128:
- p.fmtComplex128(f, verb, field)
+ p.fmtComplex128(f, verb, field, reflect.Value{})
return false
case int:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int8:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int16:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int32:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int64:
- p.fmtInt64(f, verb, field)
+ p.fmtInt64(f, verb, field, reflect.Value{})
return false
case uint:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint8:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint16:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint32:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint64:
- p.fmtUint64(f, verb, goSyntax, field)
+ p.fmtUint64(f, verb, goSyntax, field, reflect.Value{})
return false
case uintptr:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case string:
- p.fmtString(f, verb, goSyntax, field)
+ p.fmtString(f, verb, goSyntax, field, reflect.Value{})
return verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, goSyntax, depth, field)
+ p.fmtBytes(f, verb, goSyntax, depth, field, reflect.Value{})
return verb == 's'
}
// Need to use reflection
- value := reflect.ValueOf(field)
+ return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
+}
+
+// printValue is like printField but starts with a reflect value, not an interface{} value.
+func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+ if !value.IsValid() {
+ if verb == 'T' || verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb, nil, value)
+ }
+ return false
+ }
+
+ // Special processing considerations.
+ // %T (the value's type) and %p (its address) are special; we always do them first.
+ switch verb {
+ case 'T':
+ p.printField(value.Type().String(), 's', false, false, 0)
+ return false
+ case 'p':
+ p.fmtPointer(nil, value, verb, goSyntax)
+ return false
+ }
+ // Handle values with special methods.
+ // Call always, even when field == nil, because handleMethods clears p.fmt.plus for us.
+ var field interface{}
+ if value.CanInterface() {
+ field = value.Interface()
+ }
+ if wasString, handled := p.handleMethods(field, verb, plus, goSyntax, depth); handled {
+ return wasString
+ }
+
+ return p.printReflectValue(value, verb, plus, goSyntax, depth)
+}
+
+// printReflectValue is the fallback for both printField and printValue.
+// It uses reflect to print the value.
+func (p *pp) printReflectValue(value reflect.Value, verb int, plus, goSyntax bool, depth int) (wasString bool) {
BigSwitch:
switch f := value; f.Kind() {
case reflect.Bool:
- p.fmtBool(f.Bool(), verb, field)
+ p.fmtBool(f.Bool(), verb, nil, value)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.fmtInt64(f.Int(), verb, field)
+ p.fmtInt64(f.Int(), verb, nil, value)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p.fmtUint64(uint64(f.Uint()), verb, goSyntax, field)
+ p.fmtUint64(uint64(f.Uint()), verb, goSyntax, nil, value)
case reflect.Float32, reflect.Float64:
if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Float()), verb, field)
+ p.fmtFloat32(float32(f.Float()), verb, nil, value)
} else {
- p.fmtFloat64(float64(f.Float()), verb, field)
+ p.fmtFloat64(float64(f.Float()), verb, nil, value)
}
case reflect.Complex64, reflect.Complex128:
if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Complex()), verb, field)
+ p.fmtComplex64(complex64(f.Complex()), verb, nil, value)
} else {
- p.fmtComplex128(complex128(f.Complex()), verb, field)
+ p.fmtComplex128(complex128(f.Complex()), verb, nil, value)
}
case reflect.String:
- p.fmtString(f.String(), verb, goSyntax, field)
+ p.fmtString(f.String(), verb, goSyntax, nil, value)
case reflect.Map:
if goSyntax {
p.buf.WriteString(f.Type().String())
@@ -706,9 +763,9 @@ BigSwitch:
p.buf.WriteByte(' ')
}
}
- p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(key, verb, plus, goSyntax, depth+1)
p.buf.WriteByte(':')
- p.printField(f.MapIndex(key).Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1)
}
if goSyntax {
p.buf.WriteByte('}')
@@ -717,7 +774,7 @@ BigSwitch:
}
case reflect.Struct:
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
}
p.add('{')
v := f
@@ -736,20 +793,20 @@ BigSwitch:
p.buf.WriteByte(':')
}
}
- p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(getField(v, i), verb, plus, goSyntax, depth+1)
}
p.buf.WriteByte('}')
case reflect.Interface:
value := f.Elem()
if !value.IsValid() {
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
p.buf.Write(nilParenBytes)
} else {
p.buf.Write(nilAngleBytes)
}
} else {
- return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+ return p.printValue(value, verb, plus, goSyntax, depth+1)
}
case reflect.Array, reflect.Slice:
// Byte slices are special.
@@ -765,11 +822,11 @@ BigSwitch:
for i := range bytes {
bytes[i] = byte(f.Index(i).Uint())
}
- p.fmtBytes(bytes, verb, goSyntax, depth, field)
+ p.fmtBytes(bytes, verb, goSyntax, depth, nil, value)
return verb == 's'
}
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
p.buf.WriteByte('{')
} else {
p.buf.WriteByte('[')
@@ -782,7 +839,7 @@ BigSwitch:
p.buf.WriteByte(' ')
}
}
- p.printField(f.Index(i).Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(f.Index(i), verb, plus, goSyntax, depth+1)
}
if goSyntax {
p.buf.WriteByte('}')
@@ -797,17 +854,17 @@ BigSwitch:
switch a := f.Elem(); a.Kind() {
case reflect.Array, reflect.Slice:
p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(a, verb, plus, goSyntax, depth+1)
break BigSwitch
case reflect.Struct:
p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(a, verb, plus, goSyntax, depth+1)
break BigSwitch
}
}
if goSyntax {
p.buf.WriteByte('(')
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
p.buf.WriteByte(')')
p.buf.WriteByte('(')
if v == 0 {
@@ -824,7 +881,7 @@ BigSwitch:
}
p.fmt0x64(uint64(v), true)
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(field, value, verb, goSyntax)
+ p.fmtPointer(nil, value, verb, goSyntax)
default:
p.unknownType(f)
}