From 31b2360af5d02800c548b502403408794cd38b9a Mon Sep 17 00:00:00 2001 From: dmitrybarsukov Date: Sun, 25 May 2025 22:54:08 +0200 Subject: [PATCH] Return error if trying to marshal +Inf, -Inf or NaN --- jwriter/writer.go | 27 +++++++++++++++++++++++++++ tests/errors.go | 6 ++++++ tests/errors_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/jwriter/writer.go b/jwriter/writer.go index 34b0ade..6f1403a 100644 --- a/jwriter/writer.go +++ b/jwriter/writer.go @@ -2,7 +2,9 @@ package jwriter import ( + "fmt" "io" + "math" "strconv" "unicode/utf8" @@ -248,11 +250,19 @@ func (w *Writer) Int64Str(n int64) { } func (w *Writer) Float32(n float32) { + if w.checkIsUnsupportedFloat(float64(n)) { + return + } + w.Buffer.EnsureSpace(20) w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32) } func (w *Writer) Float32Str(n float32) { + if w.checkIsUnsupportedFloat(float64(n)) { + return + } + w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32) @@ -260,11 +270,19 @@ func (w *Writer) Float32Str(n float32) { } func (w *Writer) Float64(n float64) { + if w.checkIsUnsupportedFloat(n) { + return + } + w.Buffer.EnsureSpace(20) w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64) } func (w *Writer) Float64Str(n float64) { + if w.checkIsUnsupportedFloat(n) { + return + } + w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64) @@ -415,3 +433,12 @@ func (w *Writer) base64(in []byte) { w.Buffer.Buf = append(w.Buffer.Buf, byte(padChar), byte(padChar)) } } + +func (w *Writer) checkIsUnsupportedFloat(val float64) bool { + isUnsupported := math.IsNaN(val) || math.IsInf(val, 0) + if isUnsupported && w.Error == nil { + w.Error = fmt.Errorf("json: unsupported value: %v", val) + } + + return isUnsupported +} diff --git a/tests/errors.go b/tests/errors.go index 14360fc..2a545d1 100644 --- a/tests/errors.go +++ b/tests/errors.go @@ -24,3 +24,9 @@ type ErrorNestedStruct struct { //easyjson:json type ErrorIntMap map[uint32]string + +//easyjson:json +type ErrorFloatTypes struct { + Float64 float64 `json:"float64"` + Float32 float32 `json:"float32"` +} diff --git a/tests/errors_test.go b/tests/errors_test.go index 40fa335..756ef11 100644 --- a/tests/errors_test.go +++ b/tests/errors_test.go @@ -1,6 +1,7 @@ package tests import ( + "math" "testing" "github.com/mailru/easyjson/jlexer" @@ -283,3 +284,40 @@ func TestMultipleErrorsIntMap(t *testing.T) { } } } + +func TestUnsupportedFloatValues(t *testing.T) { + for i, test := range []struct { + Value ErrorFloatTypes + ExpectedErr string + }{ + { + Value: ErrorFloatTypes{Float64: math.NaN()}, + ExpectedErr: "json: unsupported value: NaN", + }, + { + Value: ErrorFloatTypes{Float64: math.Inf(1)}, + ExpectedErr: "json: unsupported value: +Inf", + }, + { + Value: ErrorFloatTypes{Float64: math.Inf(-1)}, + ExpectedErr: "json: unsupported value: -Inf", + }, + { + Value: ErrorFloatTypes{Float32: float32(math.NaN())}, + ExpectedErr: "json: unsupported value: NaN", + }, + { + Value: ErrorFloatTypes{Float32: float32(math.Inf(1))}, + ExpectedErr: "json: unsupported value: +Inf", + }, + { + Value: ErrorFloatTypes{Float32: float32(math.Inf(-1))}, + ExpectedErr: "json: unsupported value: -Inf", + }, + } { + _, err := test.Value.MarshalJSON() + if err == nil || err.Error() != test.ExpectedErr { + t.Errorf("[%d] TestUnsupportedFloatValues(): error: want %s, got %v", i, test.ExpectedErr, err) + } + } +}