mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/json: fix panics on type mismatches.
Fixes #4222. Fixes #4628. R=golang-dev, adg CC=golang-dev https://golang.org/cl/7100049
This commit is contained in:
parent
06af0ea3f3
commit
406ca3c2f1
2 changed files with 46 additions and 10 deletions
|
|
@ -347,15 +347,19 @@ func (d *decodeState) array(v reflect.Value) {
|
||||||
|
|
||||||
// Check type of target.
|
// Check type of target.
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
|
case reflect.Interface:
|
||||||
|
if v.NumMethod() == 0 {
|
||||||
|
// Decoding into nil interface? Switch to non-reflect code.
|
||||||
|
v.Set(reflect.ValueOf(d.arrayInterface()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Otherwise it's invalid.
|
||||||
|
fallthrough
|
||||||
default:
|
default:
|
||||||
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
||||||
d.off--
|
d.off--
|
||||||
d.next()
|
d.next()
|
||||||
return
|
return
|
||||||
case reflect.Interface:
|
|
||||||
// Decoding into nil interface? Switch to non-reflect code.
|
|
||||||
v.Set(reflect.ValueOf(d.arrayInterface()))
|
|
||||||
return
|
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
break
|
break
|
||||||
|
|
@ -441,7 +445,7 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
v = pv
|
v = pv
|
||||||
|
|
||||||
// Decoding into nil interface? Switch to non-reflect code.
|
// Decoding into nil interface? Switch to non-reflect code.
|
||||||
if v.Kind() == reflect.Interface {
|
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
|
||||||
v.Set(reflect.ValueOf(d.objectInterface()))
|
v.Set(reflect.ValueOf(d.objectInterface()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -459,11 +463,9 @@ func (d *decodeState) object(v reflect.Value) {
|
||||||
v.Set(reflect.MakeMap(t))
|
v.Set(reflect.MakeMap(t))
|
||||||
}
|
}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
|
|
||||||
default:
|
default:
|
||||||
d.saveError(&UnmarshalTypeError{"object", v.Type()})
|
d.saveError(&UnmarshalTypeError{"object", v.Type()})
|
||||||
}
|
|
||||||
|
|
||||||
if !v.IsValid() {
|
|
||||||
d.off--
|
d.off--
|
||||||
d.next() // skip over { } in input
|
d.next() // skip over { } in input
|
||||||
return
|
return
|
||||||
|
|
@ -646,7 +648,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
v.SetBool(value)
|
v.SetBool(value)
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
v.Set(reflect.ValueOf(value))
|
if v.NumMethod() == 0 {
|
||||||
|
v.Set(reflect.ValueOf(value))
|
||||||
|
} else {
|
||||||
|
d.saveError(&UnmarshalTypeError{"bool", v.Type()})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case '"': // string
|
case '"': // string
|
||||||
|
|
@ -676,7 +682,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
v.SetString(string(s))
|
v.SetString(string(s))
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
v.Set(reflect.ValueOf(string(s)))
|
if v.NumMethod() == 0 {
|
||||||
|
v.Set(reflect.ValueOf(string(s)))
|
||||||
|
} else {
|
||||||
|
d.saveError(&UnmarshalTypeError{"string", v.Type()})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default: // number
|
default: // number
|
||||||
|
|
@ -705,6 +715,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||||
d.saveError(err)
|
d.saveError(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if v.NumMethod() != 0 {
|
||||||
|
d.saveError(&UnmarshalTypeError{"number", v.Type()})
|
||||||
|
break
|
||||||
|
}
|
||||||
v.Set(reflect.ValueOf(n))
|
v.Set(reflect.ValueOf(n))
|
||||||
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
|
|
||||||
|
|
@ -1042,3 +1042,25 @@ func TestStringKind(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var decodeTypeErrorTests = []struct {
|
||||||
|
dest interface{}
|
||||||
|
src string
|
||||||
|
}{
|
||||||
|
{new(string), `{"user": "name"}`}, // issue 4628.
|
||||||
|
{new(error), `{}`}, // issue 4222
|
||||||
|
{new(error), `[]`},
|
||||||
|
{new(error), `""`},
|
||||||
|
{new(error), `123`},
|
||||||
|
{new(error), `true`},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalTypeError(t *testing.T) {
|
||||||
|
for _, item := range decodeTypeErrorTests {
|
||||||
|
err := Unmarshal([]byte(item.src), item.dest)
|
||||||
|
if _, ok := err.(*UnmarshalTypeError); !ok {
|
||||||
|
t.Errorf("expected type error for Unmarshal(%q, type %T): got %v instead",
|
||||||
|
item.src, item.dest, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue