diff options
| author | Joe Tsai <joetsai@digital-static.net> | 2025-07-24 12:16:35 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-07-24 20:30:28 -0700 |
| commit | 3636ced112d89da03739fa7d5468c0270addaa28 (patch) | |
| tree | bf040cf5f2709dc070e920b031f018bdecfa9e0f /src/encoding/json/v2 | |
| parent | a6eec8bdc79a89f6001d7788d280b8910c5f1b13 (diff) | |
| download | go-3636ced112d89da03739fa7d5468c0270addaa28.tar.xz | |
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>
Diffstat (limited to 'src/encoding/json/v2')
| -rw-r--r-- | src/encoding/json/v2/arshal.go | 33 |
1 files changed, 16 insertions, 17 deletions
diff --git a/src/encoding/json/v2/arshal.go b/src/encoding/json/v2/arshal.go index 5cd2106be9..e2ce778d5a 100644 --- a/src/encoding/json/v2/arshal.go +++ b/src/encoding/json/v2/arshal.go @@ -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 } |
