1
0
mirror of https://github.com/json-iterator/go.git synced 2025-04-17 11:26:35 +02:00

#68 handle float to int safely

This commit is contained in:
Tao Wen 2017-06-20 15:46:22 +08:00
parent a5ae3a2649
commit 8ef0c22f25
2 changed files with 37 additions and 9 deletions

View File

@ -4,11 +4,28 @@ import (
"github.com/json-iterator/go" "github.com/json-iterator/go"
"unsafe" "unsafe"
"encoding/json" "encoding/json"
"strings"
) )
const MaxUint = ^uint(0)
const MinUint = 0
const MaxInt = int(MaxUint >> 1)
const MinInt = -MaxInt - 1
func RegisterFuzzyDecoders() { func RegisterFuzzyDecoders() {
jsoniter.RegisterTypeDecoder("string", &FuzzyStringDecoder{}) jsoniter.RegisterTypeDecoder("string", &FuzzyStringDecoder{})
jsoniter.RegisterTypeDecoder("int", &FuzzyIntDecoder{}) jsoniter.RegisterTypeDecoder("int", &FuzzyNumberDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator, errorReporter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(MaxInt) || val < float64(MinInt) {
errorReporter.ReportError("fuzzy decode int", "exceed range")
return
}
*((*int)(ptr)) = int(val)
} else {
*((*int)(ptr)) = iter.ReadInt()
}
}})
} }
type FuzzyStringDecoder struct { type FuzzyStringDecoder struct {
@ -28,20 +45,25 @@ func (decoder *FuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Ite
} }
} }
type FuzzyIntDecoder struct { type FuzzyNumberDecoder struct {
fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator, errorReporter *jsoniter.Iterator)
} }
func (decoder *FuzzyIntDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { func (decoder *FuzzyNumberDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext() valueType := iter.WhatIsNext()
var str string
switch valueType { switch valueType {
case jsoniter.Number: case jsoniter.Number:
// use current iterator var number json.Number
iter.ReadVal(&number)
str = string(number)
case jsoniter.String: case jsoniter.String:
str := iter.ReadString() str = iter.ReadString()
iter = iter.Config().BorrowIterator([]byte(str))
defer iter.Config().ReturnIterator(iter)
default: default:
iter.ReportError("FuzzyIntDecoder", "not number or string") iter.ReportError("FuzzyNumberDecoder", "not number or string")
} }
*((*int)(ptr)) = int(iter.ReadFloat64()) newIter := iter.Config().BorrowIterator([]byte(str))
defer iter.Config().ReturnIterator(newIter)
isFloat := strings.IndexByte(str, '.') != -1
decoder.fun(isFloat, ptr, newIter, iter)
} }

View File

@ -51,3 +51,9 @@ func Test_float_to_int(t *testing.T) {
should.Nil(jsoniter.UnmarshalFromString(`1.23`, &val)) should.Nil(jsoniter.UnmarshalFromString(`1.23`, &val))
should.Equal(1, val) should.Equal(1, val)
} }
func Test_large_float_to_int(t *testing.T) {
should := require.New(t)
var val int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}