1
0
mirror of https://github.com/golang/go synced 2024-11-15 11:20:30 -07:00

[release-branch.go1] encoding/json: fix panic unmarshaling into non-nil interface value

««« backport bee83c1509a3
encoding/json: fix panic unmarshaling into non-nil interface value

Fixes #3614.

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

»»»
This commit is contained in:
Russ Cox 2012-06-13 16:24:48 -04:00
parent cec2715018
commit dc0f7d6fde
2 changed files with 53 additions and 2 deletions

View File

@ -273,9 +273,14 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
_, isUnmarshaler = v.Interface().(Unmarshaler) _, isUnmarshaler = v.Interface().(Unmarshaler)
} }
// Load value from interface, but only if the result will be
// usefully addressable.
if iv := v; iv.Kind() == reflect.Interface && !iv.IsNil() { if iv := v; iv.Kind() == reflect.Interface && !iv.IsNil() {
v = iv.Elem() e := iv.Elem()
continue if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
v = e
continue
}
} }
pv := v pv := v

View File

@ -657,3 +657,49 @@ func TestEmptyString(t *testing.T) {
t.Fatal("Decode: did not set Number1") t.Fatal("Decode: did not set Number1")
} }
} }
func intp(x int) *int {
p := new(int)
*p = x
return p
}
func intpp(x *int) **int {
pp := new(*int)
*pp = x
return pp
}
var interfaceSetTests = []struct {
pre interface{}
json string
post interface{}
}{
{"foo", `"bar"`, "bar"},
{"foo", `2`, 2.0},
{"foo", `true`, true},
{"foo", `null`, nil},
{nil, `null`, nil},
{new(int), `null`, nil},
{(*int)(nil), `null`, nil},
{new(*int), `null`, new(*int)},
{(**int)(nil), `null`, nil},
{intp(1), `null`, nil},
{intpp(nil), `null`, intpp(nil)},
{intpp(intp(1)), `null`, intpp(nil)},
}
func TestInterfaceSet(t *testing.T) {
for _, tt := range interfaceSetTests {
b := struct{ X interface{} }{tt.pre}
blob := `{"X":` + tt.json + `}`
if err := Unmarshal([]byte(blob), &b); err != nil {
t.Errorf("Unmarshal %#q: %v", blob, err)
continue
}
if !reflect.DeepEqual(b.X, tt.post) {
t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post)
}
}
}