mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-07 00:00:09 +02:00
sync: fix panic in Chan::recv_many when called with non-empty vector on closed channel (#7991)
`Chan::recv_many` intends to assert that no slots have been consumed when exiting with `Ready` via the `rx_closed` code path. Instead of asserting no items were added to the buffer, it asserted buffer emptiness, incorrectly making assumptions about the provided buffer. When `recv_many` was called on an empty channel with idle semaphore after the receiver was closed, the method would panic. The branch coverage had been previously missing. This changeset corrects the assertion and adds tests covering the code path. Fixes #7990.
This commit is contained in:
committed by
Alice Ryhl
parent
f320197693
commit
bf18ed452d
@@ -306,13 +306,11 @@ impl<T, S: Semaphore> Rx<T, S> {
|
||||
return Ready(Some(value));
|
||||
}
|
||||
Some(Read::Closed) => {
|
||||
// TODO: This check may not be required as it most
|
||||
// likely can only return `true` at this point. A
|
||||
// channel is closed when all tx handles are
|
||||
// A channel is closed when all tx handles are
|
||||
// dropped. Dropping a tx handle releases memory,
|
||||
// which ensures that if dropping the tx handle is
|
||||
// visible, then all messages sent are also visible.
|
||||
assert!(self.inner.semaphore.is_idle());
|
||||
debug_assert!(self.inner.semaphore.is_idle());
|
||||
coop.made_progress();
|
||||
return Ready(None);
|
||||
}
|
||||
@@ -380,13 +378,11 @@ impl<T, S: Semaphore> Rx<T, S> {
|
||||
if number_added > 0 {
|
||||
self.inner.semaphore.add_permits(number_added);
|
||||
}
|
||||
// TODO: This check may not be required as it most
|
||||
// likely can only return `true` at this point. A
|
||||
// channel is closed when all tx handles are
|
||||
// A channel is closed when all tx handles are
|
||||
// dropped. Dropping a tx handle releases memory,
|
||||
// which ensures that if dropping the tx handle is
|
||||
// visible, then all messages sent are also visible.
|
||||
assert!(self.inner.semaphore.is_idle());
|
||||
debug_assert!(self.inner.semaphore.is_idle());
|
||||
coop.made_progress();
|
||||
return Ready(number_added);
|
||||
}
|
||||
@@ -415,7 +411,7 @@ impl<T, S: Semaphore> Rx<T, S> {
|
||||
try_recv!();
|
||||
|
||||
if rx_fields.rx_closed && self.inner.semaphore.is_idle() {
|
||||
assert!(buffer.is_empty());
|
||||
debug_assert_eq!(buffer.len(), initial_length);
|
||||
coop.made_progress();
|
||||
Ready(0usize)
|
||||
} else {
|
||||
|
||||
@@ -358,6 +358,30 @@ async fn send_recv_many_unbounded_capacity() {
|
||||
assert_eq!(expected, buffer);
|
||||
}
|
||||
|
||||
#[maybe_tokio_test]
|
||||
async fn recv_many_with_non_empty_buffer_bounded_rx_closed_and_idle() {
|
||||
let (_tx, mut rx) = mpsc::channel::<i32>(1);
|
||||
|
||||
let mut buffer: Vec<i32> = vec![1];
|
||||
|
||||
rx.close();
|
||||
|
||||
assert_eq!(0, rx.recv_many(&mut buffer, 1).await);
|
||||
assert_eq!(vec![1], buffer);
|
||||
}
|
||||
|
||||
#[maybe_tokio_test]
|
||||
async fn recv_many_with_non_empty_buffer_unbounded_rx_closed_and_idle() {
|
||||
let (_tx, mut rx) = mpsc::unbounded_channel::<i32>();
|
||||
|
||||
let mut buffer: Vec<i32> = vec![1];
|
||||
|
||||
rx.close();
|
||||
|
||||
assert_eq!(0, rx.recv_many(&mut buffer, 1).await);
|
||||
assert_eq!(vec![1], buffer);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(feature = "full")]
|
||||
async fn async_send_recv_unbounded() {
|
||||
|
||||
Reference in New Issue
Block a user