Merge pull request #421 from dmitrybarsukov/bugfix/invalid-json-on-NaN-or-Inf

Bugfix: do not generate invalid JSON when float value is +Inf, -Inf or NaN
This commit is contained in:
Vasily Romanov
2025-09-15 21:16:52 +03:00
committed by GitHub
3 changed files with 71 additions and 0 deletions
+27
View File
@@ -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
}
+6
View File
@@ -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"`
}
+38
View File
@@ -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)
}
}
}