diff --git a/crates/async-compression/src/generic/bufread/decoder.rs b/crates/async-compression/src/generic/bufread/decoder.rs index ce827b3c..eb951a58 100644 --- a/crates/async-compression/src/generic/bufread/decoder.rs +++ b/crates/async-compression/src/generic/bufread/decoder.rs @@ -81,9 +81,8 @@ impl Decoder { } } - // The decode stage might consume all the input, - // the next stage might need to poll again if it's empty. - first = true; + // Poll again only if the decode stage consumed all the input. + first = input.unwritten().is_empty(); State::Next } else { State::Done diff --git a/crates/async-compression/tests/utils/test_cases.rs b/crates/async-compression/tests/utils/test_cases.rs index af79c4b1..f30efe3c 100644 --- a/crates/async-compression/tests/utils/test_cases.rs +++ b/crates/async-compression/tests/utils/test_cases.rs @@ -232,6 +232,24 @@ macro_rules! io_test_cases { assert_eq!(output, &[1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1][..]); } + #[test] + #[ntest::timeout(1000)] + fn corrupt_second_member() { + let first = sync::compress(&[1, 2, 3, 4, 5, 6]); + let mut second = sync::compress(&[0; 2048]); + let corrupt = second.len() - 2; + second[corrupt] ^= 0xff; + let compressed = [first, second].join(&[][..]); + + let input = InputStream::new(vec![compressed]); + let result = std::panic::catch_unwind(|| { + let mut decoder = bufread::Decoder::new(bufread::from(&input)); + decoder.multiple_members(true); + read::to_vec(decoder) + }); + assert!(result.is_err()); + } + #[test] #[ntest::timeout(1000)] fn truncated() {