Consider the test case added in https://github.com/SerenityOS/serenity/compare/master...nico:serenity:deflate-peek?expand=1
It adds a canonical code that uses 1 bit for symbol 0, 2 bits for symbol 1, 3 bits for symbol 2, and so on, and then 15 bits each for symbols 14 and 15.
(15 is the longest allowed code length in deflate.)
It then uses a bit stream that contains one 0
, one 10
, one 110
, and so on, to encode each symbol from 0 to 15 once. That's 15 * 16 / 2 + 15 == 135 bits in total. It's one bit short of a multiple of 8, so the bitstream also contains a single trailing 0 bit.
The bitstream decodes to the symbols 0, 1, 2, ..., 14, 15 – and then the final trailing 0
bit should decode to 0 again.
But instead the final read results in:
(cd Tests/LibCompress; ../../Build/lagom/bin/TestDeflate canonical_code_lopsided)
Running 1 cases out of 14.
Running test 'canonical_code_lopsided'.
FAIL: /Users/thakis/src/serenity/Tests/LibCompress/TestDeflate.cpp:104: Reached end-of-stream without collecting the required number of bits
That's because CanonicalCode::read_symbol
does a TRY(stream.peek_bits<size_t>(m_max_prefixed_code_length));
to look up 8 bits into the future, for the fast lookup added in #18075. However, #21890 made it a mistake to look up at more bits than remain in the stream – even when just peeking.
If I change LittleEndianInputBitStream's ctor to use UnsatisfiableReadBehavior::FillWithZero as default argument, the test starts passing.
I'm not sure what the nicest fix is:
discard_previously_peeked_bits
with more bits than available?The first seems a bit nicer, probably.
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too