Repository: trifectatechfoundation/bzip2-rs (language: rust)

Issue:
Infinite loop after decoding error
Similar to behavior in #96 but different enough to warrant its own issue. Notably #97 does not fix this problem.

After a decoding error `try_finish` goes into an infinite loop:
```
#[test]
fn write_invalid() {
    let contents = b"BZh\xfb";
    let mut decoder = bzip2::write::BzDecoder::new(Vec::new());
    dbg!(decoder.write(&contents[..]));
    dbg!(decoder.try_finish());
}
```

I'm explicitly calling `try_finish` here to show the problem. But since the `Drop` implementation calls `try_finish` this cannot be avoided by not calling `try_finish`.


Discussion / hints:

Fix patch:
diff --git a/src/write.rs b/src/write.rs
index 5d80000e..24d5e247 100644
--- a/src/write.rs
+++ b/src/write.rs
@@ -254,11 +254,13 @@ impl<W: Write> Write for BzDecoder<W> {
             let res = self.data.decompress_vec(data, &mut self.buf);
             let written = (self.total_in() - before) as usize;
 
-            let res = res.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
+            // make sure that a subsequent call exits early when there is nothing useful left to do
+            self.done |= matches!(res, Err(_) | Ok(Status::StreamEnd));
 
-            if res == Status::StreamEnd {
-                self.done = true;
+            if let Err(e) = res {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput, e));
             }
+
             if written > 0 || data.is_empty() || self.done {
                 return Ok(written);
             }
@@ -309,6 +311,14 @@ mod tests {
         assert_eq!(&data[..], b"");
     }
 
+    #[test]
+    fn write_invalid() {
+        // see https://github.com/trifectatechfoundation/bzip2-rs/issues/98
+        let mut d = BzDecoder::new(Vec::new());
+        let e = d.write(b"BZh\xfb").unwrap_err();
+        assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput);
+    }
+
     #[test]
     fn qc() {
         ::quickcheck::quickcheck(test as fn(_) -> _);


Test patch: