diff --git a/internal/bytesconv/bytesconv.go b/internal/bytesconv/bytesconv.go index 898e22221..be0a3210c 100644 --- a/internal/bytesconv/bytesconv.go +++ b/internal/bytesconv/bytesconv.go @@ -42,6 +42,7 @@ package bytesconv import ( + "math" "net/http" "time" "unsafe" @@ -162,12 +163,13 @@ func ParseUintBuf(b []byte) (int, int, error) { } return v, i, nil } - vNew := 10*v + int(k) - // Test for overflow. - if vNew < v { + // Test for overflow before multiplying, because 10*v may wrap around + // to a value that is still greater than v, which would make a + // post-multiplication check unreliable. + if v > (math.MaxInt-int(k))/10 { return -1, i, errTooLongInt } - v = vNew + v = 10*v + int(k) } return v, n, nil } diff --git a/internal/bytesconv/bytesconv_64_test.go b/internal/bytesconv/bytesconv_64_test.go index c72467669..0be2873e9 100644 --- a/internal/bytesconv/bytesconv_64_test.go +++ b/internal/bytesconv/bytesconv_64_test.go @@ -104,6 +104,12 @@ func TestParseUintError(t *testing.T) { {"-9223372036854775808"}, {"9223372036854775808"}, {"18446744073709551615"}, + // Values whose intermediate 10*v wraps past 2^64 and lands back on a + // positive number, which a post-multiplication overflow check misses. + {"21000000000000000000"}, + {"25000000000000000000"}, + {"46000000000000000000"}, + {"83000000000000000000"}, } { n, err := ParseUint(S2b(v.s)) if err == nil {