Skip to content

Commit 7ccef0b

Browse files
committed
Fix Lz4Decoder to propagate UnexpectedEof error on truncated streams
The LZ4 decoder was silently accepting truncated streams by not validating stream completion in finish(). This issue was discovered by the generic truncated stream test. Added state tracking to Lz4Decoder: - Added stream_ended field to track if remaining == 0 was seen - Modified decode() to set stream_ended = true when stream completes - Updated finish() to check stream_ended and return UnexpectedEof if false This matches the behavior of other decoders (bzip2, gzip, etc.) and ensures applications cannot accidentally accept corrupted or incomplete LZ4 data as valid. The generic truncated test now passes for LZ4.
1 parent a82a5c9 commit 7ccef0b

File tree

1 file changed

+19
-2
lines changed

1 file changed

+19
-2
lines changed

crates/compression-codecs/src/lz4/decoder.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct DecoderContext {
1717
#[derive(Debug)]
1818
pub struct Lz4Decoder {
1919
ctx: Unshared<DecoderContext>,
20+
stream_ended: bool,
2021
}
2122

2223
impl DecoderContext {
@@ -37,6 +38,7 @@ impl Default for Lz4Decoder {
3738
fn default() -> Self {
3839
Self {
3940
ctx: Unshared::new(DecoderContext::new().unwrap()),
41+
stream_ended: false,
4042
}
4143
}
4244
}
@@ -50,6 +52,7 @@ impl Lz4Decoder {
5052
impl DecodeV2 for Lz4Decoder {
5153
fn reinit(&mut self) -> Result<()> {
5254
unsafe { LZ4F_resetDecompressionContext(self.ctx.get_mut().ctx) };
55+
self.stream_ended = false;
5356
Ok(())
5457
}
5558

@@ -74,7 +77,12 @@ impl DecodeV2 for Lz4Decoder {
7477
};
7578
input.advance(input_size);
7679
output.advance(output_size);
77-
Ok(remaining == 0)
80+
81+
let finished = remaining == 0;
82+
if finished {
83+
self.stream_ended = true;
84+
}
85+
Ok(finished)
7886
}
7987

8088
fn flush(&mut self, output: &mut WriteBuffer<'_>) -> Result<bool> {
@@ -92,6 +100,15 @@ impl DecodeV2 for Lz4Decoder {
92100
}
93101

94102
fn finish(&mut self, output: &mut WriteBuffer<'_>) -> Result<bool> {
95-
self.flush(output)
103+
self.flush(output)?;
104+
105+
if self.stream_ended {
106+
Ok(true)
107+
} else {
108+
Err(std::io::Error::new(
109+
std::io::ErrorKind::UnexpectedEof,
110+
"lz4 stream did not finish",
111+
))
112+
}
96113
}
97114
}

0 commit comments

Comments
 (0)