瀏覽代碼

LibCompress: Convert GzipDecompressor from recursive to iterative

This way a gzip compressed file that contains a large amount of small
blocks wont cause a stack overflow.
Idan Horowitz 4 年之前
父節點
當前提交
b3b8c01ebf
共有 1 個文件被更改,包括 69 次插入61 次删除
  1. 69 61
      Userland/Libraries/LibCompress/Gzip.cpp

+ 69 - 61
Userland/Libraries/LibCompress/Gzip.cpp

@@ -70,86 +70,94 @@ GzipDecompressor::~GzipDecompressor()
 // FIXME: Again, there are surely a ton of bugs because the code doesn't check for read errors.
 size_t GzipDecompressor::read(Bytes bytes)
 {
-    if (has_any_error() || m_eof)
-        return 0;
+    size_t total_read = 0;
+    while (total_read < bytes.size()) {
+        if (has_any_error() || m_eof)
+            break;
 
-    if (m_current_member.has_value()) {
-        size_t nread = current_member().m_stream.read(bytes);
-        current_member().m_checksum.update(bytes.trim(nread));
-        current_member().m_nread += nread;
+        auto slice = bytes.slice(total_read);
 
-        if (current_member().m_stream.handle_any_error()) {
-            set_fatal_error();
-            return 0;
-        }
-
-        if (nread < bytes.size()) {
-            LittleEndian<u32> crc32, input_size;
-            m_input_stream >> crc32 >> input_size;
-
-            if (crc32 != current_member().m_checksum.digest()) {
-                // FIXME: Somehow the checksum is incorrect?
+        if (m_current_member.has_value()) {
+            size_t nread = current_member().m_stream.read(slice);
+            current_member().m_checksum.update(slice.trim(nread));
+            current_member().m_nread += nread;
 
+            if (current_member().m_stream.handle_any_error()) {
                 set_fatal_error();
-                return 0;
+                break;
             }
 
-            if (input_size != current_member().m_nread) {
-                set_fatal_error();
-                return 0;
-            }
+            if (nread < slice.size()) {
+                LittleEndian<u32> crc32, input_size;
+                m_input_stream >> crc32 >> input_size;
 
-            m_current_member.clear();
+                if (crc32 != current_member().m_checksum.digest()) {
+                    // FIXME: Somehow the checksum is incorrect?
 
-            return nread + read(bytes.slice(nread));
-        }
+                    set_fatal_error();
+                    break;
+                }
 
-        return nread;
-    } else {
-        m_partial_header_offset += m_input_stream.read(Bytes { m_partial_header, sizeof(BlockHeader) }.slice(m_partial_header_offset));
+                if (input_size != current_member().m_nread) {
+                    set_fatal_error();
+                    break;
+                }
 
-        if (m_input_stream.handle_any_error() || m_input_stream.unreliable_eof()) {
-            m_eof = true;
-            return 0;
-        }
+                m_current_member.clear();
 
-        if (m_partial_header_offset < sizeof(BlockHeader)) {
-            return 0; // partial header read
-        }
-        m_partial_header_offset = 0;
+                total_read += nread;
+                continue;
+            }
 
-        BlockHeader header = *(reinterpret_cast<BlockHeader*>(m_partial_header));
+            total_read += nread;
+            continue;
+        } else {
+            m_partial_header_offset += m_input_stream.read(Bytes { m_partial_header, sizeof(BlockHeader) }.slice(m_partial_header_offset));
 
-        if (!header.valid_magic_number() || !header.supported_by_implementation()) {
-            set_fatal_error();
-            return 0;
-        }
+            if (m_input_stream.handle_any_error() || m_input_stream.unreliable_eof()) {
+                m_eof = true;
+                break;
+            }
 
-        if (header.flags & Flags::FEXTRA) {
-            LittleEndian<u16> subfield_id, length;
-            m_input_stream >> subfield_id >> length;
-            m_input_stream.discard_or_error(length);
-        }
+            if (m_partial_header_offset < sizeof(BlockHeader)) {
+                break; // partial header read
+            }
+            m_partial_header_offset = 0;
 
-        if (header.flags & Flags::FNAME) {
-            String original_filename;
-            m_input_stream >> original_filename;
-        }
+            BlockHeader header = *(reinterpret_cast<BlockHeader*>(m_partial_header));
 
-        if (header.flags & Flags::FCOMMENT) {
-            String comment;
-            m_input_stream >> comment;
-        }
+            if (!header.valid_magic_number() || !header.supported_by_implementation()) {
+                set_fatal_error();
+                break;
+            }
 
-        if (header.flags & Flags::FHCRC) {
-            LittleEndian<u16> crc16;
-            m_input_stream >> crc16;
-            // FIXME: we should probably verify this instead of just assuming it matches
-        }
+            if (header.flags & Flags::FEXTRA) {
+                LittleEndian<u16> subfield_id, length;
+                m_input_stream >> subfield_id >> length;
+                m_input_stream.discard_or_error(length);
+            }
 
-        m_current_member.emplace(header, m_input_stream);
-        return read(bytes);
+            if (header.flags & Flags::FNAME) {
+                String original_filename;
+                m_input_stream >> original_filename;
+            }
+
+            if (header.flags & Flags::FCOMMENT) {
+                String comment;
+                m_input_stream >> comment;
+            }
+
+            if (header.flags & Flags::FHCRC) {
+                LittleEndian<u16> crc16;
+                m_input_stream >> crc16;
+                // FIXME: we should probably verify this instead of just assuming it matches
+            }
+
+            m_current_member.emplace(header, m_input_stream);
+            continue;
+        }
     }
+    return total_read;
 }
 
 bool GzipDecompressor::read_or_error(Bytes bytes)