Commit 406ca3c2 authored by Rémy Oudompheng's avatar Rémy Oudompheng

encoding/json: fix panics on type mismatches.

Fixes #4222.
Fixes #4628.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/7100049
parent 06af0ea3
...@@ -347,15 +347,19 @@ func (d *decodeState) array(v reflect.Value) { ...@@ -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) { ...@@ -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) { ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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) { ...@@ -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)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment