From 3a192734d5e790e326e7b834a230d9761b6742f0 Mon Sep 17 00:00:00 2001 From: Sasha Mitchell Date: Wed, 30 Sep 2026 19:57:59 +0700 Subject: [PATCH] fix: reject a duration sum that wraps past 2^64 1<<63 ns plus 1<<63 ns wraps the uint64 total to 0, and that 0 passes the range check. ParseDuration returned 0s. Signed-off-by: Sasha Mitchell --- duration.go | 6 ++++++ duration_test.go | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/duration.go b/duration.go index fc4de0d..f4fb550 100644 --- a/duration.go +++ b/duration.go @@ -240,6 +240,12 @@ func ParseDuration(s string) (time.Duration, error) { } } + // The sum is a uint64. 1<<63 ns plus 1<<63 ns wraps to 0, and 0 is not + // greater than maxUint64, so the range check below misses it. + if d > ^uint64(0)-v { + return 0, parseDurationError(orig, "numerical overflow") + } + d += v if d > maxUint64 { return 0, parseDurationError(orig, "numerical overflow") diff --git a/duration_test.go b/duration_test.go index 9a6dc39..fc4062d 100644 --- a/duration_test.go +++ b/duration_test.go @@ -256,6 +256,16 @@ func TestDurationParser_Overflow(t *testing.T) { // time.Duration(math.MinInt64)). input: "9223372036854775808ns", }, + { + name: "two values of 1<<63 wrap the uint64 sum to zero", + // Each token is 1<<63 ns. The sum is 1<<64, which wraps to 0 + // before d > maxUint64 can reject it. + input: "9223372036854775808ns 9223372036854775808ns", + }, + { + name: "negative pair of 1<<63 also wraps the uint64 sum to zero", + input: "-9223372036854775808ns 9223372036854775808ns", + }, } for _, tt := range overflows {