From 530f8716d4dac4244f75675cd131bb620c3bfd42 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Tue, 12 May 2026 21:20:39 -0400 Subject: [PATCH 1/2] fix: restore strict overflow check in float parser --- parse.go | 7 ++++--- parse_test.go | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/parse.go b/parse.go index 6936303..ae4d4a8 100644 --- a/parse.go +++ b/parse.go @@ -240,16 +240,17 @@ func parseFloat[S byteSeq](fn string, s S) (float64, error) { } var intPart uint64 + const maxUint64Div10 = ^uint64(0) / 10 + const maxUint64Mod10 = ^uint64(0) % 10 for i < len(s) { c := s[i] - '0' if c > 9 { break } - nn := intPart*10 + uint64(c) - if nn < intPart { + if intPart > maxUint64Div10 || (intPart == maxUint64Div10 && uint64(c) > maxUint64Mod10) { 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}, From 527e0cc3f61e25345c5a91db466e211a07d3178d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 01:37:21 +0000 Subject: [PATCH 2/2] refactor: share uint64 overflow cutoff constants Agent-Logs-Url: https://github.com/gofiber/utils/sessions/f1341fc1-b18d-4310-ab22-63cc07523d84 Co-authored-by: gaby <835733+gaby@users.noreply.github.com> --- parse.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/parse.go b/parse.go index ae4d4a8..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 @@ -240,14 +240,12 @@ func parseFloat[S byteSeq](fn string, s S) (float64, error) { } var intPart uint64 - const maxUint64Div10 = ^uint64(0) / 10 - const maxUint64Mod10 = ^uint64(0) % 10 for i < len(s) { c := s[i] - '0' if c > 9 { break } - if intPart > maxUint64Div10 || (intPart == maxUint64Div10 && uint64(c) > maxUint64Mod10) { + if intPart > maxUint64Cutoff || (intPart == maxUint64Cutoff && uint64(c) > maxUint64Cutlim) { return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange} } intPart = intPart*10 + uint64(c)