]> granicus.if.org Git - xz/commitdiff
Fix data corruption in LZ encoder with LZMA_SYNC_FLUSH.
authorLasse Collin <lasse.collin@tukaani.org>
Thu, 24 Apr 2008 15:38:00 +0000 (18:38 +0300)
committerLasse Collin <lasse.collin@tukaani.org>
Thu, 24 Apr 2008 15:38:00 +0000 (18:38 +0300)
src/liblzma/lz/lz_encoder.c
src/liblzma/lz/lz_encoder.h
src/liblzma/lz/match_c.h

index 43e6d3b473104665e9e6990b8573000258b9767a..488095ca5801b8a7490e5a68ad0d4b3fe5c71a2b 100644 (file)
@@ -188,6 +188,7 @@ lzma_lz_encoder_reset(lzma_lz_encoder *lz, lzma_allocator *allocator,
        lz->read_pos = 0;
        lz->read_limit = 0;
        lz->write_pos = 0;
+       lz->pending = 0;
 
 
        //////////////////
@@ -443,6 +444,21 @@ fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
        if (ret == LZMA_OK && coder->lz.uncompressed_size == 0)
                coder->lz.sequence = SEQ_FINISH;
 
+       // Restart the match finder after finished LZMA_SYNC_FLUSH.
+       if (coder->lz.pending > 0
+                       && coder->lz.read_pos < coder->lz.read_limit) {
+               // Match finder may update coder->pending and expects it to
+               // start from zero, so use a temporary variable.
+               const size_t pending = coder->lz.pending;
+               coder->lz.pending = 0;
+
+               // Rewind read_pos so that the match finder can hash
+               // the pending bytes.
+               assert(coder->lz.read_pos >= pending);
+               coder->lz.read_pos -= pending;
+               coder->lz.skip(&coder->lz, pending);
+       }
+
        return ret;
 }
 
index 78ac4a3641f453b450271e4cefca3555f639f730..1e47af2d3b42cee1bdda027a486e4ab6355bd00c 100644 (file)
@@ -84,6 +84,10 @@ struct lzma_lz_encoder_s {
        /// to buffer[write_pos].
        size_t write_pos;
 
+       /// Number of bytes not hashed before read_pos. This is needed to
+       /// restart the match finder after LZMA_SYNC_FLUSH.
+       size_t pending;
+
        /// Number of bytes that must be kept available in our input history.
        /// That is, once keep_size_before bytes have been processed,
        /// buffer[read_pos - keep_size_before] is the oldest byte that
index e1ee6a078eaf90dd7a4e1a7c65d14bb59e968a4b..664db2900adc02bddca45e7f877327cdd5e72fb2 100644 (file)
@@ -104,6 +104,14 @@ do { \
 } while (0)
 
 
+#define move_pending() \
+do { \
+       ++lz->read_pos; \
+       assert(lz->read_pos <= lz->write_pos); \
+       ++lz->pending; \
+} while (0)
+
+
 //////////////////////
 // Global constants //
 //////////////////////
@@ -123,13 +131,15 @@ LZMA_GET_MATCHES(LZMA_MATCH_FINDER_NAME_LOWER)
                len_limit = lz->match_max_len;
        } else {
                len_limit = lz->write_pos - lz->read_pos;
-               if (len_limit < MIN_MATCH_CHECK) {
+               if (len_limit < MIN_MATCH_CHECK || lz->sequence == SEQ_FLUSH) {
                        distances[0] = 0;
-                       move_pos();
+                       move_pending();
                        return;
                }
        }
 
+       assert(lz->pending == 0);
+
        int32_t offset = 1;
        const uint32_t match_min_pos
                        = lz->read_pos + lz->offset > lz->cyclic_buffer_size
@@ -291,7 +301,7 @@ LZMA_SKIP(LZMA_MATCH_FINDER_NAME_LOWER)
        do {
 #ifdef IS_HASH_CHAIN
                if (lz->write_pos - lz->read_pos < NUM_HASH_BYTES) {
-                       move_pos();
+                       move_pending();
                        continue;
                }
 #else
@@ -300,8 +310,9 @@ LZMA_SKIP(LZMA_MATCH_FINDER_NAME_LOWER)
                        len_limit = lz->match_max_len;
                } else {
                        len_limit = lz->write_pos - lz->read_pos;
-                       if (len_limit < MIN_MATCH_CHECK) {
-                               move_pos();
+                       if (len_limit < MIN_MATCH_CHECK
+                                       || lz->sequence == SEQ_FLUSH) {
+                               move_pending();
                                continue;
                        }
                }
@@ -311,6 +322,8 @@ LZMA_SKIP(LZMA_MATCH_FINDER_NAME_LOWER)
                        : 0;
 #endif
 
+               assert(lz->pending == 0);
+
                const uint8_t *cur = lz->buffer + lz->read_pos;
 
 #ifdef HASH_ARRAY_2