From 7a6556ac3c74d57e89204f6246df1ccfd744acfc Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:29:14 +0000 Subject: [PATCH] fix: resolve potential infinite loop and panic in Huffman table generation This commit addresses a test hang observed in `tests/offset_tests.rs` (specifically `test_offset_12_pattern`) by hardening the Huffman table generation logic in `src/decompress/mod.rs`. Changes: - **Fix `bsr32` Underflow:** Added a check for `diff == 0` before calling `bsr32` in the canonical codeword generation loop. When the table is fully utilized for a given bit length, `codeword ^ mask` can be 0, causing `bsr32` (implemented as `31 - leading_zeros`) to underflow/panic in debug builds or produce undefined shifts. The logic now correctly resets `codeword` to 0 in this edge case (wrapping around). - **Add Loop Guards:** Introduced explicit iteration limits to the nested loops in `build_decode_table`. If the loops exceed safe bounds (indicating an infinite loop due to invalid Huffman data or logic errors), the function now returns `false` (error) instead of hanging indefinitely. This prevents the process from getting stuck. This ensures robust handling of edge-case Huffman trees and prevents both crashes and hangs during table construction. Co-authored-by: 404Setup <153366651+404Setup@users.noreply.github.com> --- src/decompress/mod.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/decompress/mod.rs b/src/decompress/mod.rs index fc0583b..b3dfc8d 100644 --- a/src/decompress/mod.rs +++ b/src/decompress/mod.rs @@ -1776,9 +1776,19 @@ fn build_decode_table( return true; } let mut cur_table_end: usize = 1 << len; + let mut outer_iters = 0; while len <= table_bits { + outer_iters += 1; + if outer_iters > 100 { + return false; + } let mut count = len_counts[len]; + let mut inner_iters = 0; while count > 0 { + inner_iters += 1; + if inner_iters > 100000 { + return false; + } decode_table[codeword as usize] = make_decode_table_entry(decode_results, sorted_syms[sym_ptr] as usize, len as u32); sym_ptr += 1; @@ -1792,9 +1802,14 @@ fn build_decode_table( } return true; } - let bit = 1 << bsr32(codeword ^ ((cur_table_end as u32) - 1)); - codeword &= bit - 1; - codeword |= bit; + let diff = codeword ^ ((cur_table_end as u32) - 1); + if diff == 0 { + codeword = 0; + } else { + let bit = 1 << bsr32(diff); + codeword &= bit - 1; + codeword |= bit; + } count -= 1; } loop {