mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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 <dneil@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
a6eec8bdc7
commit
3636ced112
2 changed files with 24 additions and 19 deletions
|
|
@ -776,7 +776,8 @@ func (d *decoderState) ReadValue(flags *jsonwire.ValueFlags) (Value, error) {
|
|||
|
||||
// CheckNextValue checks whether the next value is syntactically valid,
|
||||
// but does not advance the read offset.
|
||||
func (d *decoderState) CheckNextValue() error {
|
||||
// If last, it verifies that the stream cleanly terminates with [io.EOF].
|
||||
func (d *decoderState) CheckNextValue(last bool) error {
|
||||
d.PeekKind() // populates d.peekPos and d.peekErr
|
||||
pos, err := d.peekPos, d.peekErr
|
||||
d.peekPos, d.peekErr = 0, nil
|
||||
|
|
@ -787,13 +788,18 @@ func (d *decoderState) CheckNextValue() error {
|
|||
var flags jsonwire.ValueFlags
|
||||
if pos, err := d.consumeValue(&flags, pos, d.Tokens.Depth()); err != nil {
|
||||
return wrapSyntacticError(d, err, pos, +1)
|
||||
} else if last {
|
||||
return d.checkEOF(pos)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckEOF verifies that the input has no more data.
|
||||
func (d *decoderState) CheckEOF() error {
|
||||
switch pos, err := d.consumeWhitespace(d.prevEnd); err {
|
||||
return d.checkEOF(d.prevEnd)
|
||||
}
|
||||
func (d *decoderState) checkEOF(pos int) error {
|
||||
switch pos, err := d.consumeWhitespace(pos); err {
|
||||
case nil:
|
||||
err := jsonwire.NewInvalidCharacterError(d.buf[pos:], "after top-level value")
|
||||
return wrapSyntacticError(d, err, pos, 0)
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@ func Unmarshal(in []byte, out any, opts ...Options) (err error) {
|
|||
dec := export.GetBufferedDecoder(in, opts...)
|
||||
defer export.PutBufferedDecoder(dec)
|
||||
xd := export.Decoder(dec)
|
||||
err = unmarshalFull(dec, out, &xd.Struct)
|
||||
err = unmarshalDecode(dec, out, &xd.Struct, true)
|
||||
if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
|
||||
return internal.TransformUnmarshalError(out, err)
|
||||
}
|
||||
|
|
@ -426,25 +426,13 @@ func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) {
|
|||
dec := export.GetStreamingDecoder(in, opts...)
|
||||
defer export.PutStreamingDecoder(dec)
|
||||
xd := export.Decoder(dec)
|
||||
err = unmarshalFull(dec, out, &xd.Struct)
|
||||
err = unmarshalDecode(dec, out, &xd.Struct, true)
|
||||
if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
|
||||
return internal.TransformUnmarshalError(out, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func unmarshalFull(in *jsontext.Decoder, out any, uo *jsonopts.Struct) error {
|
||||
switch err := unmarshalDecode(in, out, uo); err {
|
||||
case nil:
|
||||
return export.Decoder(in).CheckEOF()
|
||||
case io.EOF:
|
||||
offset := in.InputOffset() + int64(len(in.UnreadBuffer()))
|
||||
return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to
|
||||
// the provided unmarshal options (while ignoring marshal, encode, or decode options).
|
||||
// Any unmarshal options already specified on the [jsontext.Decoder]
|
||||
|
|
@ -463,14 +451,14 @@ func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error)
|
|||
defer func() { xd.Struct = optsOriginal }()
|
||||
xd.Struct.JoinWithoutCoderOptions(opts...)
|
||||
}
|
||||
err = unmarshalDecode(in, out, &xd.Struct)
|
||||
err = unmarshalDecode(in, out, &xd.Struct, false)
|
||||
if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
|
||||
return internal.TransformUnmarshalError(out, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err error) {
|
||||
func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct, last bool) (err error) {
|
||||
v := reflect.ValueOf(out)
|
||||
if v.Kind() != reflect.Pointer || v.IsNil() {
|
||||
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
|
|||
// In legacy semantics, the entirety of the next JSON value
|
||||
// was validated before attempting to unmarshal it.
|
||||
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
|
||||
if err := export.Decoder(in).CheckNextValue(); err != nil {
|
||||
if err := export.Decoder(in).CheckNextValue(last); err != nil {
|
||||
if err == io.EOF {
|
||||
offset := in.InputOffset() + int64(len(in.UnreadBuffer()))
|
||||
return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF}
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -495,8 +487,15 @@ func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err er
|
|||
if !uo.Flags.Get(jsonflags.AllowDuplicateNames) {
|
||||
export.Decoder(in).Tokens.InvalidateDisabledNamespaces()
|
||||
}
|
||||
if err == io.EOF {
|
||||
offset := in.InputOffset() + int64(len(in.UnreadBuffer()))
|
||||
return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF}
|
||||
}
|
||||
return err
|
||||
}
|
||||
if last {
|
||||
return export.Decoder(in).CheckEOF()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue