Skip to content

fix: reject incomplete Huffman trees with max code length > 1#190

Merged
oyvindln merged 1 commit intoFrommi:masterfrom
lilith:fix-invalid-huffman-tree-137
Feb 23, 2026
Merged

fix: reject incomplete Huffman trees with max code length > 1#190
oyvindln merged 1 commit intoFrommi:masterfrom
lilith:fix-invalid-huffman-tree-137

Conversation

@lilith
Copy link
Copy Markdown
Contributor

@lilith lilith commented Feb 22, 2026

Summary

Fixes #137.

The previous Huffman tree validation in init_tree only rejected incomplete trees when used_symbols > 1. This allowed a single symbol with a code length > 1 (e.g., code length 2 or higher) through validation, even though such a tree doesn't form a valid prefix code. zlib rejects these streams; miniz_oxide accepted them.

Changes

Over-subscription detection: Added an early left < 0 check at each code length step, matching zlib's inftrees.c logic. The previous code only checked completeness after the loop, missing cases where the tree was over-subscribed partway through.

Incomplete tree rejection: Replaced the used_symbols > 1 condition with max_code_len > 1, matching zlib's max != 1 check:

  • Code length (hufflen) tables: must always be complete (unchanged)
  • Literal/length and distance tables: incomplete codes are allowed only when max_code_len <= 1:
    • max_code_len == 0: all symbols unused (e.g., a distance table with no backreferences)
    • max_code_len == 1: a single symbol with a 1-bit code (e.g., an EOB-only litlen table)
  • max_code_len > 1 with an incomplete tree → rejected

Reference

The fix matches zlib's inftrees.c lines 126-133:

left = 1;
for (len = 1; len <= MAXBITS; len++) {
    left <<= 1;
    left -= count[len];
    if (left < 0) return -1;        /* over-subscribed */
}
if (left > 0 && (type == CODES || max != 1))
    return -1;                      /* incomplete set */

Test plan

Fixes Frommi#137. The previous validation only rejected incomplete Huffman
trees when more than one symbol had a non-zero code length. This allowed
single-symbol trees with code lengths > 1 that don't form valid prefix
codes to pass validation, even though zlib rejects them.

The fix replaces the `used_symbols > 1` check with early over-subscription
detection (left < 0 at each step) and an incomplete-tree check matching
zlib's inftrees.c logic:

- Code length (hufflen) tables must always be complete
- Literal/length and distance tables allow incomplete codes only when
  max_code_len <= 1 (all symbols unused, or a single symbol with a
  1-bit code like an EOB-only block)

Includes regression test with the exact vector from issue Frommi#137.
@oyvindln oyvindln marked this pull request as ready for review February 23, 2026 01:50
@oyvindln
Copy link
Copy Markdown
Collaborator

oyvindln commented Feb 23, 2026

Seems good

Thanks for fixing this

@oyvindln oyvindln merged commit c40992a into Frommi:master Feb 23, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

miniz_oxide accepts invalid literal/length trees

2 participants