mirror of
https://github.com/ii64/sonic.git
synced 2026-06-21 00:46:43 +08:00
fix: parsing to float64 when the integer(int64) overflow
This commit is contained in:
parent
f9632ab873
commit
e88411dafe
6 changed files with 818 additions and 846 deletions
|
|
@ -34,8 +34,8 @@ type atofTest struct {
|
|||
// Tests from Go strconv package, https://github.com/golang/go/blob/master/src/strconv/atof_test.go
|
||||
// All tests are passed in Go encoding/json.
|
||||
var atoftests = []atofTest{
|
||||
{"1.234e", "1.234", nil},
|
||||
{"1i", "1", nil},
|
||||
{"1.234e", "", nil}, // error
|
||||
{"1i", "1", nil}, // pass
|
||||
{"1", "1", nil},
|
||||
{"1e23", "1e+23", nil},
|
||||
{"1E23", "1e+23", nil},
|
||||
|
|
@ -140,19 +140,25 @@ var atoftests = []atofTest{
|
|||
{"1090544144181609348671888949248", "1.0905441441816093e+30", nil},
|
||||
// slightly above, rounds up
|
||||
{"1090544144181609348835077142190", "1.0905441441816094e+30", nil},
|
||||
|
||||
// Corner case between int64 and float64 for the input
|
||||
{"9223372036854775807", "9223372036854775807", nil}, // max int64: (1 << 63) - 1
|
||||
{"9223372036854775808", "9223372036854775808", nil},
|
||||
{"-9223372036854775808", "-9223372036854775808", nil}, // min int64: 1 << 63
|
||||
{"-9223372036854775809", "-9223372036854775809", nil},
|
||||
}
|
||||
|
||||
func TestDecodeFloat(t *testing.T) {
|
||||
var sonicout, stdout interface{}
|
||||
for _, tt := range atoftests {
|
||||
for i, tt := range atoftests {
|
||||
// default float64
|
||||
var sonicout, stdout interface{}
|
||||
sonicerr := decoder.NewDecoder(tt.in).Decode(&sonicout)
|
||||
stderr := json.NewDecoder(strings.NewReader(tt.in)).Decode(&stdout)
|
||||
if !reflect.DeepEqual(sonicout, stdout) {
|
||||
t.Fatalf("Test %#v\ngot:\n %#v\nexp:\n %#v\n", tt.in, sonicout, stdout)
|
||||
t.Fatalf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sonicout, stdout)
|
||||
}
|
||||
if !reflect.DeepEqual(sonicerr == nil, stderr == nil) {
|
||||
t.Fatalf("Test %#v\ngot:\n %#v\nexp:\n %#v\n", tt.in, sonicerr, stderr)
|
||||
t.Fatalf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sonicerr, stderr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,16 +19,16 @@ var (
|
|||
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 238
|
||||
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
||||
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 4951
|
||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16081
|
||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16116
|
||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13759
|
||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15993
|
||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16028
|
||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13671
|
||||
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3731
|
||||
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5972
|
||||
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 9426
|
||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11985
|
||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13209
|
||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12001
|
||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13121
|
||||
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11032
|
||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13486
|
||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13398
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,16 +19,16 @@ var (
|
|||
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 366
|
||||
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
||||
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5299
|
||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18501
|
||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18536
|
||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15701
|
||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18413
|
||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18448
|
||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15613
|
||||
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3979
|
||||
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 7136
|
||||
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11379
|
||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13927
|
||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15151
|
||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13943
|
||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15063
|
||||
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13090
|
||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15428
|
||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15340
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -412,12 +412,12 @@ void vstring(const GoString *src, long *p, JsonState *ret) {
|
|||
man_nd++; \
|
||||
} else { \
|
||||
exp10++; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define add_float_to_mantissa(man, man_nd, exp10, dig) \
|
||||
man = man * 10 + dig; \
|
||||
man_nd++; \
|
||||
exp10--; \
|
||||
exp10--;
|
||||
|
||||
#define parse_float_digits(val, sgn, ...) \
|
||||
while (i < n && s[i] >= '0' && s[i] <= '9' __VA_ARGS__) { \
|
||||
|
|
@ -490,7 +490,9 @@ static inline int is_atof_exact(uint64_t man, int exp, int sgn, double *val) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
f *= sgn;
|
||||
if (sgn == -1) {
|
||||
f = -f;
|
||||
}
|
||||
*val = 0;
|
||||
|
||||
if (exp == 0 || man == 0) {
|
||||
|
|
@ -563,12 +565,6 @@ void vnumber(const GoString *src, long *p, JsonState *ret) {
|
|||
check_eof()
|
||||
check_sign(sgn = -1)
|
||||
|
||||
/* zero */
|
||||
if (i + 1 == n && s[i] == '0') {
|
||||
i++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check for leading zero */
|
||||
check_digit()
|
||||
check_leading_zero()
|
||||
|
|
@ -634,10 +630,8 @@ void vnumber(const GoString *src, long *p, JsonState *ret) {
|
|||
exp10 += exp * esm;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret->vt == V_INTEGER) {
|
||||
/* if INT64_MIN <= man * sgn <= INT64_MAX */
|
||||
if ( exp10 == 0 && (((man & ((uint64_t)1 << 63)) == 0) || ((man & sgn) == man))) {
|
||||
if ( exp10 == 0 && (man >> 63) == 0) {
|
||||
ret->iv = (int64_t)man * sgn;
|
||||
ret->dv = (double)(ret->iv);
|
||||
} else { // integer overflow
|
||||
|
|
|
|||
Loading…
Reference in a new issue