fix(nix-compat/wire/bytes/reader): handle zero cases

Legitimate zero-length reads could cause spurious unexpected EOF,
since we implicitly assumed buffers always have remaining capacity.

For the buffered case, `consume(0)` could cause panics after either
`poll_fill_buf` or `poll_read` had returned `Poll::Pending`.

The bytes_read/with_limited logic receives a stylistic cleanup to make
it obvious that bytes_read is always written before being used.

Change-Id: I46aa47113309552dcef9532b5d4009d2186db9cd
Reviewed-on: https://cl.snix.dev/c/snix/+/30492
Tested-by: besadii
Reviewed-by: Brian Olsen <brian@maven-group.org>
Reviewed-by: Florian Klink <flokli@flokli.de>
This commit is contained in:
edef 2025-05-09 16:56:08 +00:00
parent 9a8a9c6b67
commit 83c3305863

View file

@ -129,6 +129,11 @@ impl<R: AsyncRead + Unpin, T: Tag> AsyncRead for BytesReader<R, T> {
) -> Poll<io::Result<()>> { ) -> Poll<io::Result<()>> {
let this = &mut self.state; let this = &mut self.state;
// reading nothing always succeeds
if buf.remaining() == 0 {
return Ok(()).into();
}
loop { loop {
match this { match this {
State::Body { State::Body {
@ -147,11 +152,8 @@ impl<R: AsyncRead + Unpin, T: Tag> AsyncRead for BytesReader<R, T> {
Pin::new(reader.as_mut().unwrap()) Pin::new(reader.as_mut().unwrap())
}; };
let mut bytes_read = 0; let bytes_read = ready!(with_limited(buf, remaining, |buf| {
ready!(with_limited(buf, remaining, |buf| { reader.poll_read(cx, buf).map_ok(|()| buf.filled().len())
let ret = reader.poll_read(cx, buf);
bytes_read = buf.filled().len();
ret
}))?; }))?;
*consumed += bytes_read as u64; *consumed += bytes_read as u64;
@ -262,7 +264,11 @@ impl<R: AsyncBufRead + Unpin, T: Tag> AsyncBufRead for BytesReader<R, T> {
reader.consume(amt); reader.consume(amt);
} }
State::ReadTrailer(_) => unreachable!(), State::ReadTrailer(_) => {
if amt != 0 {
unreachable!();
}
}
State::ReleaseTrailer { consumed, data } => { State::ReleaseTrailer { consumed, data } => {
*consumed = amt *consumed = amt
.checked_add(*consumed as usize) .checked_add(*consumed as usize)