Skip to content

Fix panic in Arbitrary for Duration on nanosecond carry overflow - #657

Open
matthiasgoergens wants to merge 1 commit into
proptest-rs:mainfrom
matthiasgoergens:duration-arbitrary-overflow
Open

Fix panic in Arbitrary for Duration on nanosecond carry overflow#657
matthiasgoergens wants to merge 1 commit into
proptest-rs:mainfrom
matthiasgoergens:duration-arbitrary-overflow

Conversation

@matthiasgoergens

Copy link
Copy Markdown

any::<Duration>() can panic: Duration::new aborts when carrying whole seconds out of the nanosecond argument overflows the seconds counter, and the strategy maps any::<(u64, u32)>() straight into Duration::new(a, b). With uniform generation the failing corner (a within carry range of u64::MAX and b >= 1_000_000_000) has probability around 2^-64 per case, which is presumably why it has never been reported.

I ran into it while experimenting with a port of Hypothesis's Conjecture engine (choice-tape generation and shrinking) to proptest: its edge-case-biased generator deliberately produces boundary values like u64::MAX seconds, and this panic fell out of the very first full test run. I plan to propose that work separately; this fix stands on its own.

The fix keeps the nanosecond argument free of whole seconds when the seconds value is within carry range of u64::MAX; all other draws are unchanged. The regression test drives the actual strategy with a PassThrough RNG fed all-ones bytes, which deterministically forces (u64::MAX, u32::MAX) through generation; it panics without the fix.

Duration::new panics when carrying whole seconds out of the nanosecond
argument overflows the seconds counter, so any::<Duration>() could in
principle generate (u64::MAX, >= 1_000_000_000) and abort the test run.
Under uniform generation this corner has probability ~2^-64 per case,
which is presumably why it was never seen; it surfaced immediately while
experimenting with a port of Hypothesis's edge-case-biased generation
(which deliberately produces boundary values like u64::MAX).

Keep the nanoseconds free of whole seconds when the seconds value is
within carry range of u64::MAX; all other draws are unchanged. The
regression test drives the actual strategy with a PassThrough RNG fed
all-ones bytes, which deterministically forces the worst case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug This is a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants