Skip to content

Commit

Permalink
sync: prevent lock poisoning in watch::Receiver::wait_for (#6021)
Browse files Browse the repository at this point in the history
  • Loading branch information
uklotzde authored Sep 24, 2023
1 parent 02aacf5 commit e76c06b
Showing 1 changed file with 18 additions and 3 deletions.
21 changes: 18 additions & 3 deletions tokio/src/sync/watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ impl<T> Receiver<T> {
changed_impl(&self.shared, &mut self.version).await
}

/// Waits for a value that satisifes the provided condition.
/// Waits for a value that satisfies the provided condition.
///
/// This method will call the provided closure whenever something is sent on
/// the channel. Once the closure returns `true`, this method will return a
Expand Down Expand Up @@ -772,8 +772,23 @@ impl<T> Receiver<T> {
let has_changed = self.version != new_version;
self.version = new_version;

if (!closed || has_changed) && f(&inner) {
return Ok(Ref { inner, has_changed });
if !closed || has_changed {
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&inner)));
match result {
Ok(true) => {
return Ok(Ref { inner, has_changed });
}
Ok(false) => {
// Skip the value.
}
Err(panicked) => {
// Drop the read-lock to avoid poisoning it.
drop(inner);
// Forward the panic to the caller.
panic::resume_unwind(panicked);
// Unreachable
}
};
}
}

Expand Down

0 comments on commit e76c06b

Please sign in to comment.