mirror of
https://github.com/golang/go
synced 2024-11-20 11:14:45 -07:00
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:
parent
8022a1a588
commit
09b736a2ab
@ -273,9 +273,14 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (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() {
|
||||
v = iv.Elem()
|
||||
continue
|
||||
e := iv.Elem()
|
||||
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
||||
v = e
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
pv := v
|
||||
|
@ -683,3 +683,49 @@ func TestEmptyString(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user