]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Add early return when prev_length already exceeds lookahead
authorNathan Moin Vaziri <nathan@nathanm.com>
Sun, 12 Apr 2026 17:00:09 +0000 (10:00 -0700)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Wed, 6 May 2026 12:06:20 +0000 (14:06 +0200)
Near end-of-input the caller's prev_length can exceed the
current lookahead, making the chain walk pointless since no
match can be longer than the available input. The non-slow
path never clamped this case — break_matching was slow-path
only — leaving the output contract unguarded.

Together with the existing `if (len >= lookahead)` early
return in the update block — which stops the chain walk as
soon as a match reaches lookahead — this ensures no
unnecessary chain steps are taken. madler/zlib does the full
chain walk when prev_length exceeds lookahead and clamps
best_len at the function exit resulting in extra work.

match_tpl.h

index 05b2e82c1bd4df9d4091e35f689d803a0cbea34b..88f4588a133eb998faf19d25cd8ed62209d868f0 100644 (file)
@@ -53,8 +53,9 @@ Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
     /* The code is optimized for STD_MAX_MATCH-2 multiple of 16. */
     Assert(STD_MAX_MATCH == 258, "Code too clever");
 
-    scan = window + strstart;
     best_len = s->prev_length ? s->prev_length : STD_MIN_MATCH-1;
+    if (best_len >= lookahead)
+        return lookahead;
 
     /* Calculate read offset which should only extend an extra byte
      * to find the next best match length.
@@ -66,6 +67,7 @@ Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, uint32_t cur_match) {
             offset -= 4;
     }
 
+    scan = window + strstart;
     scan_start = zng_memread_8(scan);
     scan_end = zng_memread_8(scan+offset);
     mbase_end  = (mbase_start+offset);