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

LibCompress: Convert DeflateDecompressor from recursive to iterative

This way a deflate blob that contains a large amount of small blocks
wont cause a stack overflow.
This commit is contained in:
Idan Horowitz 2021-03-19 16:20:00 +02:00 committed by Andreas Kling
parent b02be11a6f
commit 974a981ded

View file

@ -223,19 +223,23 @@ DeflateDecompressor::~DeflateDecompressor()
size_t DeflateDecompressor::read(Bytes bytes) size_t DeflateDecompressor::read(Bytes bytes)
{ {
size_t total_read = 0;
while (total_read < bytes.size()) {
if (has_any_error()) if (has_any_error())
return 0; break;
auto slice = bytes.slice(total_read);
if (m_state == State::Idle) { if (m_state == State::Idle) {
if (m_read_final_bock) if (m_read_final_bock)
return 0; break;
m_read_final_bock = m_input_stream.read_bit(); m_read_final_bock = m_input_stream.read_bit();
const auto block_type = m_input_stream.read_bits(2); const auto block_type = m_input_stream.read_bits(2);
if (m_input_stream.has_any_error()) { if (m_input_stream.has_any_error()) {
set_fatal_error(); set_fatal_error();
return 0; break;
} }
if (block_type == 0b00) { if (block_type == 0b00) {
@ -246,25 +250,25 @@ size_t DeflateDecompressor::read(Bytes bytes)
if (m_input_stream.has_any_error()) { if (m_input_stream.has_any_error()) {
set_fatal_error(); set_fatal_error();
return 0; break;
} }
if ((length ^ 0xffff) != negated_length) { if ((length ^ 0xffff) != negated_length) {
set_fatal_error(); set_fatal_error();
return 0; break;
} }
m_state = State::ReadingUncompressedBlock; m_state = State::ReadingUncompressedBlock;
new (&m_uncompressed_block) UncompressedBlock(*this, length); new (&m_uncompressed_block) UncompressedBlock(*this, length);
return read(bytes); continue;
} }
if (block_type == 0b01) { if (block_type == 0b01) {
m_state = State::ReadingCompressedBlock; m_state = State::ReadingCompressedBlock;
new (&m_compressed_block) CompressedBlock(*this, CanonicalCode::fixed_literal_codes(), CanonicalCode::fixed_distance_codes()); new (&m_compressed_block) CompressedBlock(*this, CanonicalCode::fixed_literal_codes(), CanonicalCode::fixed_distance_codes());
return read(bytes); continue;
} }
if (block_type == 0b10) { if (block_type == 0b10) {
@ -274,63 +278,67 @@ size_t DeflateDecompressor::read(Bytes bytes)
if (m_input_stream.has_any_error()) { if (m_input_stream.has_any_error()) {
set_fatal_error(); set_fatal_error();
return 0; break;
} }
m_state = State::ReadingCompressedBlock; m_state = State::ReadingCompressedBlock;
new (&m_compressed_block) CompressedBlock(*this, literal_codes, distance_codes); new (&m_compressed_block) CompressedBlock(*this, literal_codes, distance_codes);
return read(bytes); continue;
} }
set_fatal_error(); set_fatal_error();
return 0; break;
} }
if (m_state == State::ReadingCompressedBlock) { if (m_state == State::ReadingCompressedBlock) {
auto nread = m_output_stream.read(bytes); auto nread = m_output_stream.read(slice);
while (nread < bytes.size() && m_compressed_block.try_read_more()) { while (nread < slice.size() && m_compressed_block.try_read_more()) {
nread += m_output_stream.read(bytes.slice(nread)); nread += m_output_stream.read(slice.slice(nread));
} }
if (m_input_stream.has_any_error()) { if (m_input_stream.has_any_error()) {
set_fatal_error(); set_fatal_error();
return 0; break;
} }
if (nread == bytes.size()) total_read += nread;
return nread; if (nread == slice.size())
break;
m_compressed_block.~CompressedBlock(); m_compressed_block.~CompressedBlock();
m_state = State::Idle; m_state = State::Idle;
return nread + read(bytes.slice(nread)); continue;
} }
if (m_state == State::ReadingUncompressedBlock) { if (m_state == State::ReadingUncompressedBlock) {
auto nread = m_output_stream.read(bytes); auto nread = m_output_stream.read(slice);
while (nread < bytes.size() && m_uncompressed_block.try_read_more()) { while (nread < slice.size() && m_uncompressed_block.try_read_more()) {
nread += m_output_stream.read(bytes.slice(nread)); nread += m_output_stream.read(slice.slice(nread));
} }
if (m_input_stream.has_any_error()) { if (m_input_stream.has_any_error()) {
set_fatal_error(); set_fatal_error();
return 0; break;
} }
if (nread == bytes.size()) total_read += nread;
return nread; if (nread == slice.size())
break;
m_uncompressed_block.~UncompressedBlock(); m_uncompressed_block.~UncompressedBlock();
m_state = State::Idle; m_state = State::Idle;
return nread + read(bytes.slice(nread)); continue;
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
return total_read;
}
bool DeflateDecompressor::read_or_error(Bytes bytes) bool DeflateDecompressor::read_or_error(Bytes bytes)
{ {