aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json/v2/errors.go
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2025-10-10 17:56:04 -0700
committerJoseph Tsai <joetsai@digital-static.net>2025-10-13 10:44:23 -0700
commit0e64ee1286c092eca95b3ffcc5917d34f43d4c0f (patch)
treeb5d2e8be0c0b4eb951503f74374299d0f5ddfd36 /src/encoding/json/v2/errors.go
parent6bcd97d9f4386528aa85eb3cc27da0ed902de870 (diff)
downloadgo-0e64ee1286c092eca95b3ffcc5917d34f43d4c0f.tar.xz
encoding/json/v2: report EOF for top-level values in UnmarshalDecode
The fully streaming UnmarshalJSONFrom method and UnmarshalFromFunc introduce an edge case where they can encounter EOF in the stream, where it should be reported upstream as EOF rather than ErrUnexpectedEOF or be wrapped within a SemanticError. This is not possible with other unmarshal methods since the "json" package would read the appropriate JSON value before calling the custom method or function. To avoid custom unmarshal methods from encountering EOF, check whether the stream is already at EOF for top-level values before calling the custom method. Also, when wrapping EOF within a SemanticError, convert it to ErrUnexpectedEOF to better indicate that this is unexpected. Fixes #75802 Change-Id: I001396734b7e95b5337f77b71326284974ee730a Reviewed-on: https://go-review.googlesource.com/c/go/+/710877 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Carlos Amedee <carlos@golang.org>
Diffstat (limited to 'src/encoding/json/v2/errors.go')
-rw-r--r--src/encoding/json/v2/errors.go16
1 files changed, 13 insertions, 3 deletions
diff --git a/src/encoding/json/v2/errors.go b/src/encoding/json/v2/errors.go
index 0f50d608c9..4421f8b821 100644
--- a/src/encoding/json/v2/errors.go
+++ b/src/encoding/json/v2/errors.go
@@ -10,6 +10,7 @@ import (
"cmp"
"errors"
"fmt"
+ "io"
"reflect"
"strconv"
"strings"
@@ -118,7 +119,7 @@ func newInvalidFormatError(c coder, t reflect.Type) error {
// newMarshalErrorBefore wraps err in a SemanticError assuming that e
// is positioned right before the next token or value, which causes an error.
func newMarshalErrorBefore(e *jsontext.Encoder, t reflect.Type, err error) error {
- return &SemanticError{action: "marshal", GoType: t, Err: err,
+ return &SemanticError{action: "marshal", GoType: t, Err: toUnexpectedEOF(err),
ByteOffset: e.OutputOffset() + int64(export.Encoder(e).CountNextDelimWhitespace()),
JSONPointer: jsontext.Pointer(export.Encoder(e).AppendStackPointer(nil, +1))}
}
@@ -134,7 +135,7 @@ func newUnmarshalErrorBefore(d *jsontext.Decoder, t reflect.Type, err error) err
if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
k = d.PeekKind()
}
- return &SemanticError{action: "unmarshal", GoType: t, Err: err,
+ return &SemanticError{action: "unmarshal", GoType: t, Err: toUnexpectedEOF(err),
ByteOffset: d.InputOffset() + int64(export.Decoder(d).CountNextDelimWhitespace()),
JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, +1)),
JSONKind: k}
@@ -157,7 +158,7 @@ func newUnmarshalErrorBeforeWithSkipping(d *jsontext.Decoder, t reflect.Type, er
// is positioned right after the previous token or value, which caused an error.
func newUnmarshalErrorAfter(d *jsontext.Decoder, t reflect.Type, err error) error {
tokOrVal := export.Decoder(d).PreviousTokenOrValue()
- return &SemanticError{action: "unmarshal", GoType: t, Err: err,
+ return &SemanticError{action: "unmarshal", GoType: t, Err: toUnexpectedEOF(err),
ByteOffset: d.InputOffset() - int64(len(tokOrVal)),
JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, -1)),
JSONKind: jsontext.Value(tokOrVal).Kind()}
@@ -206,6 +207,7 @@ func newSemanticErrorWithPosition(c coder, t reflect.Type, prevDepth int, prevLe
if serr == nil {
serr = &SemanticError{Err: err}
}
+ serr.Err = toUnexpectedEOF(serr.Err)
var currDepth int
var currLength int64
var coderState interface{ AppendStackPointer([]byte, int) []byte }
@@ -432,3 +434,11 @@ func newDuplicateNameError(ptr jsontext.Pointer, quotedName []byte, offset int64
Err: jsontext.ErrDuplicateName,
}
}
+
+// toUnexpectedEOF converts [io.EOF] to [io.ErrUnexpectedEOF].
+func toUnexpectedEOF(err error) error {
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return err
+}