lcpit_matchfinder: fix limiting nice_match_len
authorEric Biggers <ebiggers3@gmail.com>
Sun, 14 Apr 2019 06:21:42 +0000 (23:21 -0700)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 14 Apr 2019 06:21:42 +0000 (23:21 -0700)
The "normal" mode of the lcp-interval tree matchfinder supports finding
matches up to LCP_MAX bytes.  The "huge" mode, which is needed on
buffers larger than 64 MiB, supports up to HUGE_LCP_MAX bytes.
nice_match_len must be limited to the appropriate one of these values.

But nice_match_len is limited by lcpit_matchfinder_init().  That's
wrong, because it only knows whether huge mode *might* be used later,
based on max_bufsize.  Which mode to use is actually decided on a
buffer-by-buffer basis by lcpit_matchfinder_load_buffer().

Thus, limit nice_match_len in lcpit_matchfinder_load_buffer() instead.

This fixes a crash or incorrect output during LZMS compression with a
compression level > 50 and a chunk size > 64 MiB.

include/wimlib/lcpit_matchfinder.h
src/lcpit_matchfinder.c

index 662eae1..6391a48 100644 (file)
@@ -37,6 +37,7 @@ struct lcpit_matchfinder {
        u32 min_match_len;
        u32 nice_match_len;
        u32 next[2];
+       u32 orig_nice_match_len;
 };
 
 struct lz_match {
index a2d6a1e..b5a14e9 100644 (file)
@@ -593,9 +593,7 @@ lcpit_matchfinder_init(struct lcpit_matchfinder *mf, size_t max_bufsize,
        }
 
        mf->min_match_len = min_match_len;
-       mf->nice_match_len = min(nice_match_len,
-                                (max_bufsize <= MAX_NORMAL_BUFSIZE) ?
-                                LCP_MAX : HUGE_LCP_MAX);
+       mf->orig_nice_match_len = nice_match_len;
        return true;
 }
 
@@ -664,6 +662,7 @@ lcpit_matchfinder_load_buffer(struct lcpit_matchfinder *mf, const u8 *T, u32 n)
        build_SA(mf->intervals, T, n, mf->pos_data);
        build_ISA(mf->pos_data, mf->intervals, n);
        if (n <= MAX_NORMAL_BUFSIZE) {
+               mf->nice_match_len = min(mf->orig_nice_match_len, LCP_MAX);
                for (u32 i = 0; i < PREFETCH_SAFETY; i++) {
                        mf->intervals[n + i] = 0;
                        mf->pos_data[n + i] = 0;
@@ -673,6 +672,7 @@ lcpit_matchfinder_load_buffer(struct lcpit_matchfinder *mf, const u8 *T, u32 n)
                build_LCPIT(mf->intervals, mf->pos_data, n);
                mf->huge_mode = false;
        } else {
+               mf->nice_match_len = min(mf->orig_nice_match_len, HUGE_LCP_MAX);
                for (u32 i = 0; i < PREFETCH_SAFETY; i++) {
                        mf->intervals64[n + i] = 0;
                        mf->pos_data[n + i] = 0;