diff options
author | Felix Giese <felix.giese@icloud.com> | 2020-07-26 09:40:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-26 09:40:29 +0200 |
commit | 7f29acd964dfca9c9e90a87af607a7897eb8ea67 (patch) | |
tree | 403af7b7011f78fa6b960e1d50cd18b9106bb820 /tokio/src/time | |
parent | 2d97d5ad15a19665615ed38219d3b7798df7e250 (diff) |
time: fix resetting expired timers causing panics (#2587)
* Add Unit Test demonstrating the issue
This test demonstrates a panic that occurs when the user inserts an
item with an instant in the past, and then tries to reset the timeout
using the returned key
* Guard reset_at against removals of expired items
Trying to remove an already expired Timer Wheel entry (called by
DelayQueue.reset()) causes panics in some cases as described in (#2573)
This prevents this panic by removing the item from the expired queue and
not the wheel in these cases
Fixes: #2473
Diffstat (limited to 'tokio/src/time')
-rw-r--r-- | tokio/src/time/delay_queue.rs | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/tokio/src/time/delay_queue.rs b/tokio/src/time/delay_queue.rs index 55ec7cd6..a947cc6f 100644 --- a/tokio/src/time/delay_queue.rs +++ b/tokio/src/time/delay_queue.rs @@ -427,6 +427,22 @@ impl<T> DelayQueue<T> { } } + /// Removes the key fom the expired queue or the timer wheel + /// depending on its expiration status + /// + /// # Panics + /// Panics if the key is not contained in the expired queue or the wheel + fn remove_key(&mut self, key: &Key) { + use crate::time::wheel::Stack; + + // Special case the `expired` queue + if self.slab[key.index].expired { + self.expired.remove(&key.index, &mut self.slab); + } else { + self.wheel.remove(&key.index, &mut self.slab); + } + } + /// Removes the item associated with `key` from the queue. /// /// There must be an item associated with `key`. The function returns the @@ -456,15 +472,7 @@ impl<T> DelayQueue<T> { /// # } /// ``` pub fn remove(&mut self, key: &Key) -> Expired<T> { - use crate::time::wheel::Stack; - - // Special case the `expired` queue - if self.slab[key.index].expired { - self.expired.remove(&key.index, &mut self.slab); - } else { - self.wheel.remove(&key.index, &mut self.slab); - } - + self.remove_key(key); let data = self.slab.remove(key.index); Expired { @@ -508,7 +516,7 @@ impl<T> DelayQueue<T> { /// # } /// ``` pub fn reset_at(&mut self, key: &Key, when: Instant) { - self.wheel.remove(&key.index, &mut self.slab); + self.remove_key(key); // Normalize the deadline. Values cannot be set to expire in the past. let when = self.normalize_deadline(when); |