Skip to content

Commit 3636ced

Browse files
dsnetgopherbot
authored andcommitted
encoding/json: fix extra data regression under goexperiment.jsonv2
When operating under v1 semantics in the v2 implementation, a extra data error should take precedence over any semantic error that could theoretically occur within the value itself. This change only affects code compiled under goexperiment.jsonv2. Fixes #74614 Change-Id: I055a606b053fa66b0c766ae205487b8290109285 Reviewed-on: https://go-review.googlesource.com/c/go/+/689919 Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Auto-Submit: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent a6eec8b commit 3636ced

File tree

2 files changed

+24
-19
lines changed

2 files changed

+24
-19
lines changed

src/encoding/json/jsontext/decode.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,8 @@ func (d *decoderState) ReadValue(flags *jsonwire.ValueFlags) (Value, error) {
776776

777777
// CheckNextValue checks whether the next value is syntactically valid,
778778
// but does not advance the read offset.
779-
func (d *decoderState) CheckNextValue() error {
779+
// If last, it verifies that the stream cleanly terminates with [io.EOF].
780+
func (d *decoderState) CheckNextValue(last bool) error {
780781
d.PeekKind() // populates d.peekPos and d.peekErr
781782
pos, err := d.peekPos, d.peekErr
782783
d.peekPos, d.peekErr = 0, nil
@@ -787,13 +788,18 @@ func (d *decoderState) CheckNextValue() error {
787788
var flags jsonwire.ValueFlags
788789
if pos, err := d.consumeValue(&flags, pos, d.Tokens.Depth()); err != nil {
789790
return wrapSyntacticError(d, err, pos, +1)
791+
} else if last {
792+
return d.checkEOF(pos)
790793
}
791794
return nil
792795
}
793796

794797
// CheckEOF verifies that the input has no more data.
795798
func (d *decoderState) CheckEOF() error {
796-
switch pos, err := d.consumeWhitespace(d.prevEnd); err {
799+
return d.checkEOF(d.prevEnd)
800+
}
801+
func (d *decoderState) checkEOF(pos int) error {
802+
switch pos, err := d.consumeWhitespace(pos); err {
797803
case nil:
798804
err := jsonwire.NewInvalidCharacterError(d.buf[pos:], "after top-level value")
799805
return wrapSyntacticError(d, err, pos, 0)

src/encoding/json/v2/arshal.go

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ func Unmarshal(in []byte, out any, opts ...Options) (err error) {
409409
dec := export.GetBufferedDecoder(in, opts...)
410410
defer export.PutBufferedDecoder(dec)
411411
xd := export.Decoder(dec)
412-
err = unmarshalFull(dec, out, &xd.Struct)
412+
err = unmarshalDecode(dec, out, &xd.Struct, true)
413413
if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
414414
return internal.TransformUnmarshalError(out, err)
415415
}
@@ -426,25 +426,13 @@ func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) {
426426
dec := export.GetStreamingDecoder(in, opts...)
427427
defer export.PutStreamingDecoder(dec)
428428
xd := export.Decoder(dec)
429-
err = unmarshalFull(dec, out, &xd.Struct)
429+
err = unmarshalDecode(dec, out, &xd.Struct, true)
430430
if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
431431
return internal.TransformUnmarshalError(out, err)
432432
}
433433
return err
434434
}
435435

436-
func unmarshalFull(in *jsontext.Decoder, out any, uo *jsonopts.Struct) error {
437-
switch err := unmarshalDecode(in, out, uo); err {
438-
case nil:
439-
return export.Decoder(in).CheckEOF()
440-
case io.EOF:
441-
offset := in.InputOffset() + int64(len(in.UnreadBuffer()))
442-
return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF}
443-
default:
444-
return err
445-
}
446-
}
447-
448436
// UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to
449437
// the provided unmarshal options (while ignoring marshal, encode, or decode options).
450438
// Any unmarshal options already specified on the [jsontext.Decoder]
@@ -463,14 +451,14 @@ func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error)
463451
defer func() { xd.Struct = optsOriginal }()
464452
xd.Struct.JoinWithoutCoderOptions(opts...)
465453
}
466-
err = unmarshalDecode(in, out, &xd.Struct)
454+
err = unmarshalDecode(in, out, &xd.Struct, false)
467455
if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
468456
return internal.TransformUnmarshalError(out, err)
469457
}
470458
return err
471459
}
472460

473-
func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err error) {
461+
func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct, last bool) (err error) {
474462
v := reflect.ValueOf(out)
475463
if v.Kind() != reflect.Pointer || v.IsNil() {
476464
return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(out), Err: internal.ErrNonNilReference}
@@ -481,7 +469,11 @@ func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err er
481469
// In legacy semantics, the entirety of the next JSON value
482470
// was validated before attempting to unmarshal it.
483471
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
484-
if err := export.Decoder(in).CheckNextValue(); err != nil {
472+
if err := export.Decoder(in).CheckNextValue(last); err != nil {
473+
if err == io.EOF {
474+
offset := in.InputOffset() + int64(len(in.UnreadBuffer()))
475+
return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF}
476+
}
485477
return err
486478
}
487479
}
@@ -495,8 +487,15 @@ func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err er
495487
if !uo.Flags.Get(jsonflags.AllowDuplicateNames) {
496488
export.Decoder(in).Tokens.InvalidateDisabledNamespaces()
497489
}
490+
if err == io.EOF {
491+
offset := in.InputOffset() + int64(len(in.UnreadBuffer()))
492+
return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF}
493+
}
498494
return err
499495
}
496+
if last {
497+
return export.Decoder(in).CheckEOF()
498+
}
500499
return nil
501500
}
502501

0 commit comments

Comments
 (0)