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 {