Repository: sharksforarms/deku
Pull request #530 (2025-03-03 03:26:45)

Pin rustc-hash to 2.1.0
Pin rustc-hash that is used internally for testing. This library updated it's internal algorithm in newer versions, but we only use it to compare the bytes written. See https://github.com/rust-lang/rustc-hash/blob/master/CHANGELOG.md#211

This was found in https://github.com/sharksforarms/deku/pull/529 and https://github.com/sharksforarms/deku/pull/528 since we don't have a lockfile.

github-actions[bot]: ## Benchmark for 9605607
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| count_from_u8_specialize | **96.7±1.23ns** | 99.4±0.52ns | **+2.79%** |
| count_no_specialize | 2.4±0.01µs | 2.4±0.02µs | 0.00% |
| count_specialize | 96.6±1.02ns | 97.6±1.71ns | +1.04% |
| deku_read_bits | 1228.4±20.08ns | **1194.6±13.27ns** | **-2.75%** |
| deku_read_byte | 5.3±0.03ns | **4.6±0.59ns** | **-13.21%** |
| deku_read_enum | 4.3±0.07ns | **3.8±0.05ns** | **-11.63%** |
| deku_read_vec | 30.6±0.34ns | 30.8±0.61ns | +0.65% |
| deku_write_bits | **244.5±4.86ns** | 263.5±25.14ns | **+7.77%** |
| deku_write_byte | 24.0±0.22ns | 24.0±0.31ns | 0.00% |
| deku_write_enum | 22.8±0.23ns | 22.8±0.33ns | 0.00% |
| deku_write_vec | 506.3±18.52ns | **486.5±4.87ns** | **-3.91%** |
| read_all | 5.1±0.05µs | **4.3±0.11µs** | **-15.69%** |
| read_all_bytes | 5.2±0.07µs | **4.2±0.05µs** | **-19.23%** |

  </details>
  

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 4aa5c9a..6acf775 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -41,7 +41,7 @@ hexlit = "0.5.5"
 criterion = "0.5.1"
 alloc_counter = "0.0.4"
 trybuild = "1.0.99"
-rustc-hash = "2.0.0"
+rustc-hash = "=2.1.0"
 env_logger = "0.11.5"
 assert_hex = "0.4.1"
 
diff --git a/src/reader.rs b/src/reader.rs
index 1ff56a7..a924ada 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -21,9 +21,6 @@ pub enum ReaderRet {
     Bits(Option<BitVec<u8, Msb0>>),
 }
 
-/// Max bits requested from [`Reader::read_bits`] during one call
-pub const MAX_BITS_AMT: usize = 128;
-
 #[derive(Debug)]
 enum Leftover {
     Byte(u8),
@@ -214,7 +211,7 @@ impl<'a, R: Read + Seek> Reader<'a, R> {
     ///   `self.bits_read` will increase by `amt`
     ///
     /// # Params
-    /// `amt`    - Amount of bits that will be read. Must be <= [`MAX_BITS_AMT`].
+    /// `amt`    - Amount of bits that will be read
     #[inline(never)]
     #[cfg(feature = "bits")]
     pub fn read_bits(
@@ -282,8 +279,8 @@ impl<'a, R: Read + Seek> Reader<'a, R> {
                 }
 
                 // read in new bytes
-                let mut buf = [0; MAX_BITS_AMT];
-                if let Err(e) = self.inner.read_exact(&mut buf[..bytes_len]) {
+                let mut buf = vec![0; bytes_len];
+                if let Err(e) = self.inner.read_exact(&mut buf) {
                     if e.kind() == ErrorKind::UnexpectedEof {
                         return Err(DekuError::Incomplete(NeedSize::new(amt)));
                     }
@@ -803,4 +800,20 @@ mod tests {
         let bits = reader.read_bits(4, Order::Msb0).unwrap();
         assert_eq!(bits, Some(bitvec![u8, Msb0; 0, 1, 0, 1]));
     }
+
+    #[cfg(feature = "bits")]
+    #[test]
+    fn test_long_unaligned_bytes_read() {
+        let input = vec![0xff; 0xff * 2];
+        let mut cursor = Cursor::new(input);
+        let mut reader = Reader::new(&mut cursor);
+
+        // read 1 bits to make this unaligned
+        let bits = reader.read_bits(1, Order::Lsb0).unwrap();
+        assert_eq!(bits, Some(bitvec![u8, Msb0; 1]));
+        // Now, read the bytes
+        let mut out = vec![0x00; 0xff * 2];
+        // doesn't crash
+        let _ = reader.read_bytes(0xfe * 2, &mut out, Order::Lsb0).unwrap();
+    }
 }


Test patch:
diff --git a/tests/test_alloc.rs b/tests/test_alloc.rs
index eee3319..9050c01 100644
--- a/tests/test_alloc.rs
+++ b/tests/test_alloc.rs
@@ -66,7 +66,7 @@ mod tests {
                 let _ = TestDeku::from_reader((&mut cursor, 0)).unwrap();
             })
             .0,
-            (5, 0, 5)
+            (6, 0, 6)
         );
     }