From b4c8fd3181f07df7da52f7ffcc519bb7df33cc5f Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 17 Nov 2023 18:48:31 +0200 Subject: [PATCH] Handle potential overflow gracefully --- Cargo.toml | 2 +- src/native/delay.rs | 28 ++++++++++++++++++++++++++-- tests/smoke.rs | 7 +++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 870c40c..8bc3472 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" authors = ["Alex Crichton "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/src/native/delay.rs b/src/native/delay.rs index 69e8fcd..6fb660d 100644 --- a/src/native/delay.rs +++ b/src/native/delay.rs @@ -34,7 +34,12 @@ impl Delay { /// The default timer will be spun up in a helper thread on first use. #[inline] pub fn new(dur: Duration) -> Delay { - Delay::new_handle(Instant::now() + dur, Default::default()) + Delay::new_handle( + Instant::now() + .checked_add(dur) + .unwrap_or_else(Self::max_instant), + Default::default(), + ) } /// Creates a new future which will fire at the time specified by `at`. @@ -74,6 +79,21 @@ impl Delay { } } + fn max_instant() -> Instant { + let mut max = Instant::now(); + let mut duration = Duration::MAX; + + while duration > Duration::ZERO { + if let Some(new_max) = max.checked_add(duration) { + max = new_max; + } else { + duration /= 2; + } + } + + max + } + fn _reset(&mut self, dur: Duration) -> Result<(), ()> { let state = match self.state { Some(ref state) => state, @@ -92,7 +112,11 @@ impl Delay { Err(s) => bits = s, } } - *state.at.lock().unwrap() = Some(Instant::now() + dur); + *state.at.lock().unwrap() = Some( + Instant::now() + .checked_add(dur) + .unwrap_or_else(Self::max_instant), + ); // If we fail to push our node then we've become an inert timer, so // we'll want to clear our `state` field accordingly timeouts.list.push(state)?; diff --git a/tests/smoke.rs b/tests/smoke.rs index b2f172e..9135203 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -29,3 +29,10 @@ async fn reset() -> Result<(), Box> { assert!(i.elapsed() > dur); Ok(()) } + +#[test] +fn overflow() { + // Could have overflown if wasn't implemented correctly + let mut delay = Delay::new(Duration::MAX); + delay.reset(Duration::MAX); +}