Revert "encoding/json: don't reuse slice elements when decoding"

This reverts https://golang.org/cl/191783.

Reason for revert: Broke too many programs which depended on the previous
behavior, even when it was the opposite of what the documentation said.

We can attempt to fix the original issue again for 1.16, while keeping
those programs in mind.

Fixes #39427.

Change-Id: I7a7f24b2a594c597ef625aeff04fff29aaa88fc6
Reviewed-on: https://go-review.googlesource.com/c/go/+/240657
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Daniel Martí 2020-07-01 11:31:15 +00:00
parent a4ba411b19
commit 5de90d33c8
2 changed files with 19 additions and 36 deletions

View file

@ -177,7 +177,8 @@ func (d *decodeState) unmarshal(v interface{}) error {
d.scanWhile(scanSkipSpace) d.scanWhile(scanSkipSpace)
// We decode rv not rv.Elem because the Unmarshaler interface // We decode rv not rv.Elem because the Unmarshaler interface
// test must be applied at the top level of the value. // test must be applied at the top level of the value.
if err := d.value(rv); err != nil { err := d.value(rv)
if err != nil {
return d.addErrorContext(err) return d.addErrorContext(err)
} }
return d.savedError return d.savedError
@ -507,7 +508,6 @@ func (d *decodeState) array(v reflect.Value) error {
return nil return nil
} }
v = pv v = pv
initialSliceCap := 0
// Check type of target. // Check type of target.
switch v.Kind() { switch v.Kind() {
@ -524,9 +524,8 @@ func (d *decodeState) array(v reflect.Value) error {
d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
d.skip() d.skip()
return nil return nil
case reflect.Slice: case reflect.Array, reflect.Slice:
initialSliceCap = v.Cap() break
case reflect.Array:
} }
i := 0 i := 0
@ -537,6 +536,7 @@ func (d *decodeState) array(v reflect.Value) error {
break break
} }
// Get element of array, growing if necessary.
if v.Kind() == reflect.Slice { if v.Kind() == reflect.Slice {
// Grow slice if necessary // Grow slice if necessary
if i >= v.Cap() { if i >= v.Cap() {
@ -552,22 +552,19 @@ func (d *decodeState) array(v reflect.Value) error {
v.SetLen(i + 1) v.SetLen(i + 1)
} }
} }
var into reflect.Value
if i < v.Len() { if i < v.Len() {
into = v.Index(i) // Decode into element.
if i < initialSliceCap { if err := d.value(v.Index(i)); err != nil {
// Reusing an element from the slice's original return err
// backing array; zero it before decoding. }
into.Set(reflect.Zero(v.Type().Elem())) } else {
// Ran out of fixed array: skip.
if err := d.value(reflect.Value{}); err != nil {
return err
} }
} }
i++ i++
// Note that we decode the value even if we ran past the end of
// the fixed array. In that case, we decode into an empty value
// and do nothing with it.
if err := d.value(into); err != nil {
return err
}
// Next token must be , or ]. // Next token must be , or ].
if d.opcode == scanSkipSpace { if d.opcode == scanSkipSpace {
@ -583,17 +580,16 @@ func (d *decodeState) array(v reflect.Value) error {
if i < v.Len() { if i < v.Len() {
if v.Kind() == reflect.Array { if v.Kind() == reflect.Array {
// Zero the remaining elements. // Array. Zero the rest.
zero := reflect.Zero(v.Type().Elem()) z := reflect.Zero(v.Type().Elem())
for ; i < v.Len(); i++ { for ; i < v.Len(); i++ {
v.Index(i).Set(zero) v.Index(i).Set(z)
} }
} else { } else {
v.SetLen(i) v.SetLen(i)
} }
} }
if v.Kind() == reflect.Slice && v.IsNil() { if i == 0 && v.Kind() == reflect.Slice {
// Don't allow the resulting slice to be nil.
v.Set(reflect.MakeSlice(v.Type(), 0, 0)) v.Set(reflect.MakeSlice(v.Type(), 0, 0))
} }
return nil return nil

View file

@ -2099,10 +2099,7 @@ func TestSkipArrayObjects(t *testing.T) {
// slices, and arrays. // slices, and arrays.
// Issues 4900 and 8837, among others. // Issues 4900 and 8837, among others.
func TestPrefilled(t *testing.T) { func TestPrefilled(t *testing.T) {
type T struct { // Values here change, cannot reuse table across runs.
A, B int
}
// Values here change, cannot reuse the table across runs.
var prefillTests = []struct { var prefillTests = []struct {
in string in string
ptr interface{} ptr interface{}
@ -2138,16 +2135,6 @@ func TestPrefilled(t *testing.T) {
ptr: &[...]int{1, 2}, ptr: &[...]int{1, 2},
out: &[...]int{3, 0}, out: &[...]int{3, 0},
}, },
{
in: `[{"A": 3}]`,
ptr: &[]T{{A: -1, B: -2}, {A: -3, B: -4}},
out: &[]T{{A: 3}},
},
{
in: `[{"A": 3}]`,
ptr: &[...]T{{A: -1, B: -2}, {A: -3, B: -4}},
out: &[...]T{{A: 3, B: -2}, {}},
},
} }
for _, tt := range prefillTests { for _, tt := range prefillTests {