diff --git a/parse.go b/parse.go index 6936303..601fccc 100644 --- a/parse.go +++ b/parse.go @@ -5,7 +5,11 @@ import ( "strconv" ) -const maxFracDigits = 16 +const ( + maxFracDigits = 16 + maxUint64Cutoff = math.MaxUint64 / 10 + maxUint64Cutlim = math.MaxUint64 % 10 +) type Signed interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 @@ -136,10 +140,6 @@ func ParseUint8[S byteSeq](s S) (uint8, error) { // It returns an error if any non-digit is encountered or overflow happens. func parseDigits[S byteSeq](s S, i int) (uint64, error) { var n uint64 - const ( - cutoff = math.MaxUint64 / 10 - cutlim = math.MaxUint64 % 10 - ) digits := 0 for ; i < len(s); i++ { c := s[i] - '0' @@ -148,7 +148,7 @@ func parseDigits[S byteSeq](s S, i int) (uint64, error) { } d := uint64(c) // Any value with <= 19 digits is guaranteed to fit in uint64. - if digits >= 19 && (n > cutoff || (n == cutoff && d > cutlim)) { + if digits >= 19 && (n > maxUint64Cutoff || (n == maxUint64Cutoff && d > maxUint64Cutlim)) { return 0, strconv.ErrRange } n = n*10 + d @@ -245,11 +245,10 @@ func parseFloat[S byteSeq](fn string, s S) (float64, error) { if c > 9 { break } - nn := intPart*10 + uint64(c) - if nn < intPart { + if intPart > maxUint64Cutoff || (intPart == maxUint64Cutoff && uint64(c) > maxUint64Cutlim) { return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange} } - intPart = nn + intPart = intPart*10 + uint64(c) i++ } diff --git a/parse_test.go b/parse_test.go index 26af26a..d897538 100644 --- a/parse_test.go +++ b/parse_test.go @@ -556,6 +556,7 @@ func Test_ParseFloat64(t *testing.T) { {strconv.FormatFloat(-math.MaxFloat64, 'g', -1, 64), -math.MaxFloat64, true}, {"5e-324", 0, true}, {"1e-400", 0, true}, + {"25000000000000000000e-18", 0, false}, {"1234567891234567891234567", 0, false}, {"1.2345678912345678", 1.2345678912345678, true}, // large number {"0.11111111111111119", 0, false},