]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: fix panics on type mismatches.
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Mon, 14 Jan 2013 07:44:16 +0000 (08:44 +0100)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Mon, 14 Jan 2013 07:44:16 +0000 (08:44 +0100)
Fixes #4222.
Fixes #4628.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/7100049

src/pkg/encoding/json/decode.go
src/pkg/encoding/json/decode_test.go

index d86fd7711ba420cd279e6d22197de702b49d3dc4..eb8c75b24ad4f1411802a811f3626f1321c86bfb 100644 (file)
@@ -347,15 +347,19 @@ func (d *decodeState) array(v reflect.Value) {
 
        // Check type of target.
        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:
                d.saveError(&UnmarshalTypeError{"array", v.Type()})
                d.off--
                d.next()
                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.Slice:
                break
@@ -441,7 +445,7 @@ func (d *decodeState) object(v reflect.Value) {
        v = pv
 
        // 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()))
                return
        }
@@ -459,11 +463,9 @@ func (d *decodeState) object(v reflect.Value) {
                        v.Set(reflect.MakeMap(t))
                }
        case reflect.Struct:
+
        default:
                d.saveError(&UnmarshalTypeError{"object", v.Type()})
-       }
-
-       if !v.IsValid() {
                d.off--
                d.next() // skip over { } in input
                return
@@ -646,7 +648,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                case reflect.Bool:
                        v.SetBool(value)
                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
@@ -676,7 +682,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                case reflect.String:
                        v.SetString(string(s))
                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
@@ -705,6 +715,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                                d.saveError(err)
                                break
                        }
+                       if v.NumMethod() != 0 {
+                               d.saveError(&UnmarshalTypeError{"number", v.Type()})
+                               break
+                       }
                        v.Set(reflect.ValueOf(n))
 
                case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
index 562b5b5d88014123100f71c22cdb6e0075bffe44..4c75f19f4aa5e5805a1576e568874a6a02c30ab9 100644 (file)
@@ -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)
+               }
+       }
+}