1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 04:17:35 +00:00

LibCompress: Fix off-by-one error in generate_huffman_lengths

Previously we would calculate the index of the first parent node as
heap.size() (which is initialized to non_zero_freqs), so in the edge
case in which all symbols had a non-zero frequency, we would use the
Size-index entry in the array for both the first symbol's leaf node,
and the first parent node.

The result would either be a non-optimal huffman code (bad), or an
illegal huffman code that would then go on to crash due to an error
check in CanonicalCode::from_bytes. (worse)

We now store parent nodes starting at heap.size() - 1, which eliminates
the potential overlap, and resolves the issue.
This commit is contained in:
Idan Horowitz 2023-12-01 20:42:54 +02:00 committed by Tim Schumacher
parent ec081a2ef5
commit b749167506
4 changed files with 21 additions and 3 deletions

View file

@ -625,7 +625,7 @@ void DeflateCompressor::generate_huffman_lengths(Array<u8, Size>& lengths, Array
u16 heap_keys[Size]; // Used for O(n) heap construction
u16 heap_values[Size];
u16 huffman_links[Size * 2 + 1] = { 0 };
u16 huffman_links[Size * 2] = { 0 };
size_t non_zero_freqs = 0;
for (size_t i = 0; i < Size; i++) {
auto frequency = frequencies[i];
@ -657,7 +657,7 @@ void DeflateCompressor::generate_huffman_lengths(Array<u8, Size>& lengths, Array
u16 second_lowest_frequency = heap.peek_min_key();
u16 second_lowest_link = heap.pop_min();
u16 new_link = heap.size() + 2;
u16 new_link = heap.size() + 1;
heap.insert(lowest_frequency + second_lowest_frequency, new_link);
@ -676,7 +676,7 @@ void DeflateCompressor::generate_huffman_lengths(Array<u8, Size>& lengths, Array
non_zero_freqs++;
size_t bit_length = 1;
while (link != 2) {
while (link != 1) {
bit_length++;
link = huffman_links[link];
}