]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0647: matchfuzzypos() false exact match for long equal-length candidates v9.2.0647
authorglepnir <glephunter@gmail.com>
Sun, 14 Jun 2026 15:53:39 +0000 (15:53 +0000)
committerChristian Brabandt <cb@256bit.org>
Sun, 14 Jun 2026 15:53:39 +0000 (15:53 +0000)
Problem:  When a candidate gets truncated to MATCH_MAX_LEN and ends up
          the same length as the needle, the n == m shortcut would
          return SCORE_MAX with positions 0..n-1, even if the strings
          actually differ.
Solution: Only use the shortcut if the truncated strings are truly equal.
          Otherwise, fall back to regular matching.

Example:
echo matchfuzzypos(['x' .. repeat('a',1024)], repeat('a',1024))

closes: #20475

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/fuzzy.c
src/testdir/test_matchfuzzy.vim
src/version.c

index fddfeb450a415b8e7b86445c65b78f79824847ae..db006be0f97b7a3874a5b5ca18cc841d20486f8d 100644 (file)
@@ -1144,12 +1144,26 @@ match_positions(char_u *needle, char_u *haystack, int_u *positions)
        // Since this method can only be called with a haystack which
        // matches needle. If the lengths of the strings are equal the
        // strings themselves must also be equal (ignoring case).
-       if (positions)
+       // After truncation to MATCH_MAX_LEN n == m can also happen for
+       // unequal strings, so check before taking the shortcut.
+       bool equal = true;
+       for (int i = 0; i < n; i++)
        {
-           for (int i = 0; i < n; i++)
-               positions[i] = i;
+           if (match.lower_needle[i] != match.lower_haystack[i])
+           {
+               equal = false;
+               break;
+           }
+       }
+       if (equal)
+       {
+           if (positions)
+           {
+               for (int i = 0; i < n; i++)
+                   positions[i] = i;
+           }
+           return SCORE_MAX;
        }
-       return SCORE_MAX;
     }
 
     // ensure n * MATCH_MAX_LEN * 2 won't overflow
index 8e1c2f88264fa62cd281dae709abcdc10e771fe1..f6565c7545e0713cf9445d8d4caa1753f0e54b9a 100644 (file)
@@ -331,7 +331,7 @@ func Test_matchfuzzy_long_multiword_no_overflow()
   call assert_equal([[], [], []], matchfuzzypos([word], pat_overflow))
 endfunc
 
-func Test_matchfuzzy_long_candidate()
+func Test_matchfuzzy_oversized_candidate()
   let str = repeat('a', 1024) .. 'z'
   call assert_equal([], matchfuzzy([str], 'az'))
   call assert_equal([[], [], []], matchfuzzypos([str], 'az'))
@@ -346,6 +346,10 @@ func Test_matchfuzzy_long_candidate()
   let e = matchfuzzypos([edge], 'aa')
   call assert_equal([edge], e[0])
   call assert_equal([0, 1023], e[1][0])
+
+  let cand = 'x' .. repeat('a', 1024)
+  call assert_equal([], matchfuzzy([cand], repeat('a', 1024)))
+  call assert_equal([[], [], []], matchfuzzypos([cand], repeat('a', 1024)))
 endfunc
 
 func Test_matchfuzzy_long_candidate_mbyte()
index 959bc0f9af6ce8cf3b94c22255c556fcc3e9f596..7c4111c394846d0616d3bffc9dba3648484d02e3 100644 (file)
@@ -759,6 +759,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    647,
 /**/
     646,
 /**/