diff --git a/tokio/src/io/util/mem.rs b/tokio/src/io/util/mem.rs index beb9d6ca3..fdd3734fd 100644 --- a/tokio/src/io/util/mem.rs +++ b/tokio/src/io/util/mem.rs @@ -100,6 +100,11 @@ pub struct SimplexStream { /// /// The `max_buf_size` argument is the maximum amount of bytes that can be /// written to a side before the write returns `Poll::Pending`. +/// +/// # Panics +/// +/// This function panics if `max_buf_size` is 0. +#[track_caller] #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] pub fn duplex(max_buf_size: usize) -> (DuplexStream, DuplexStream) { let one = Arc::new(Mutex::new(SimplexStream::new_unsplit(max_buf_size))); @@ -207,6 +212,11 @@ impl Drop for DuplexStream { /// # Ok(()) /// # } /// ``` +/// +/// # Panics +/// +/// This function panics if `max_buf_size` is 0. +#[track_caller] #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] pub fn simplex(max_buf_size: usize) -> (ReadHalf, WriteHalf) { split(SimplexStream::new_unsplit(max_buf_size)) @@ -218,8 +228,14 @@ impl SimplexStream { /// /// The `max_buf_size` argument is the maximum amount of bytes that can be /// written to a buffer before it returns `Poll::Pending`. + /// + /// # Panics + /// + /// This function panics if `max_buf_size` is 0. + #[track_caller] #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] pub fn new_unsplit(max_buf_size: usize) -> SimplexStream { + assert!(max_buf_size > 0, "`max_buf_size` must be greater than 0"); SimplexStream { buffer: BytesMut::new(), is_closed: false, diff --git a/tokio/tests/io_panic.rs b/tokio/tests/io_panic.rs index 048244d8a..6189ecf9a 100644 --- a/tokio/tests/io_panic.rs +++ b/tokio/tests/io_panic.rs @@ -4,7 +4,7 @@ use std::task::{Context, Poll}; use std::{error::Error, pin::Pin}; -use tokio::io::{self, split, AsyncRead, AsyncWrite, ReadBuf}; +use tokio::io::{self, duplex, simplex, split, AsyncRead, AsyncWrite, ReadBuf, SimplexStream}; mod support { pub mod panic; @@ -131,6 +131,42 @@ fn unsplit_panic_caller() -> Result<(), Box> { Ok(()) } +#[test] +fn duplex_zero_capacity_panic_caller() -> Result<(), Box> { + let panic_location_file = test_panic(|| { + let _ = duplex(0); + }); + + // The panic location should be in this file + assert_eq!(&panic_location_file.unwrap(), file!()); + + Ok(()) +} + +#[test] +fn simplex_zero_capacity_panic_caller() -> Result<(), Box> { + let panic_location_file = test_panic(|| { + let _ = simplex(0); + }); + + // The panic location should be in this file + assert_eq!(&panic_location_file.unwrap(), file!()); + + Ok(()) +} + +#[test] +fn new_unsplit_zero_capacity_panic_caller() -> Result<(), Box> { + let panic_location_file = test_panic(|| { + let _ = SimplexStream::new_unsplit(0); + }); + + // The panic location should be in this file + assert_eq!(&panic_location_file.unwrap(), file!()); + + Ok(()) +} + #[test] #[cfg(unix)] fn async_fd_new_panic_caller() -> Result<(), Box> {