LibCompress: Error out when encounters and incomplete stream

If we find ourselves in a situation where zlib can't make any progress,
we don't have any more data to feed in and no output has been produced,
we need to raise an error as the compressed data is incomplete.

This used to lead to an infinite busy loop where we keep calling
zlib to decompressed but is not able. This causes the promise on the
read side of the transformer to never fulfill.

This gives us at least 24 more WPT tests :)
This commit is contained in:
Tete17 2025-05-16 00:05:53 +02:00 committed by Tim Flynn
parent 39cef6eeb5
commit 7a235537e8
Notes: github-actions[bot] 2025-06-14 22:28:10 +00:00
2 changed files with 9 additions and 3 deletions

View file

@ -76,9 +76,15 @@ ErrorOr<Bytes> GenericZlibDecompressor::read_some(Bytes bytes)
}
auto ret = inflate(m_zstream, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR)
return handle_zlib_error(ret);
// We got Z_BUF_ERROR (no progress was possible), no more input, stream is EOF and no output was produced.
// There is no way to get out of this loop, error out.
if (ret == Z_BUF_ERROR && m_zstream->avail_in == 0 && m_stream->is_eof() && bytes.size() == m_zstream->avail_out)
return Error::from_string_literal("No decompression progress on EOF stream");
if (ret == Z_STREAM_END) {
inflateReset(m_zstream);
if (m_zstream->avail_in == 0)

View file

@ -153,13 +153,13 @@ WebIDL::ExceptionOr<void> DecompressionStream::decompress_flush_and_enqueue()
return TRY(decompressor->read_until_eof());
});
if (maybe_buffer.is_error())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Unable to compress flush: {}", maybe_buffer.error())) };
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Unable to decompress flush: {}", maybe_buffer.error())) };
auto buffer = maybe_buffer.release_value();
// Note: LibCompress already throws an error if we call read_until_eof and no more progress can be made
// 2. If the end of the compressed input has not been reached, then throw a TypeError.
if (m_decompressor.visit([](auto const& decompressor) { return !decompressor->is_eof(); }))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "End of compressed input has not been reached"sv };
VERIFY(m_decompressor.visit([](auto const& decompressor) { return decompressor->is_eof(); }));
// 3. If buffer is empty, return.
if (buffer.is_empty())