async-rs / async-std

Async version of the Rust standard library

Home Page:https://async.rs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

File::read with a zero-sized buffer closes the stream

abr-egn opened this issue · comments

Calling File::read with a zero-sized buffer results in all subsequent reads returning 0 even when more data exists.

Minimal repro:

use futures::AsyncReadExt;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

#[async_std::main]
async fn main() -> Result<()> {
    let path = std::path::Path::new("testfile");
    async_std::fs::write(path, [0; 8]).await?;
    let mut file = async_std::fs::File::open(path).await?;
    let mut buf = [0; 2];
    assert_eq!(2, file.read(&mut buf).await?);
    assert_eq!(0, file.read(&mut []).await?);
    assert_eq!(2, file.read(&mut buf).await?);  // this fails

    Ok(())
}

This is easily encountered when reading a stream into fixed-size chunks, e.g. repeatedly calling

async fn read_exact_or_to_end<T>(buf: &mut [u8], source: &mut T) -> Result<usize>
where
    T: AsyncRead + Unpin,
{
    let mut total_bytes_read = 0;
    loop {
        let bytes_read = match dbg!(source.read(&mut buf[total_bytes_read..]).await?) {
            0 => break,
            n => n,
        };
        total_bytes_read += bytes_read;
    }

    Ok(total_bytes_read)
}

This is straightforwardly worked around by checking if the number of bytes read is the size of the buffer, but it's easy to accidentally encounter and a hassle to debug.

This seems to have been fixed in 64b7791, shortly after the 1.12 release.