Commit: patch 9.2.0963: crash when sound-folding a crafted spell file

Christian Brabandt <[email protected]>
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0963: crash when sound-folding a crafted spell file

Commit: https://github.com/vim/vim/commit/6ac008db969677304ba888854e5d44a32ce79853
Author: Christian Brabandt <[email protected]>
Date:   Mon Aug 17 20:29:53 2026 +0000

    patch 9.2.0963: crash when sound-folding a crafted spell file
    
    Problem:  A SAL rule longer than MAXWLEN is silently truncated to an
              empty lead.  set_sal_first() then reorders the sl_sal entries
              by their index byte and can move the terminating sentinel out
              of the last slot, so spell_soundfold_wsal() reads past the end
              of the array, e.g. when soundfold() or spellsuggest() is used
              (Erick Alex).
    Solution: Bound the sound-folding loops against sl_sal.ga_len.
    
    closes: #21076
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/spell.c b/src/spell.c
index de807d905..f1cfdd8c2 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -3356,7 +3356,7 @@ spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res)
 	if (n >= 0)
 	{
 	    // check all rules for the same letter
-	    for (; (s = smp[n].sm_lead)[0] == c; ++n)
+	    for (; n < slang->sl_sal.ga_len && (s = smp[n].sm_lead)[0] == c; ++n)
 	    {
 		// Quickly skip entries that don't match the word.  Most
 		// entries are less than three chars, optimize for that.
@@ -3646,7 +3646,8 @@ spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
 	    // Check all rules for the same index byte.
 	    // If c is 0x300 need extra check for the end of the array, as
 	    // (c & 0xff) is NUL.
-	    for (; ((ws = smp[n].sm_lead_w)[0] & 0xff) == (c & 0xff)
+	    for (; n < slang->sl_sal.ga_len
+			&& ((ws = smp[n].sm_lead_w)[0] & 0xff) == (c & 0xff)
 							 && ws[0] != NUL; ++n)
 	    {
 		// Quickly skip entries that don't match the word.  Most
diff --git a/src/testdir/test_spell_utf8.vim b/src/testdir/test_spell_utf8.vim
index fa9284be1..a24bdc47a 100644
--- a/src/testdir/test_spell_utf8.vim
+++ b/src/testdir/test_spell_utf8.vim
@@ -827,5 +827,18 @@ func Test_spell_suggest_too_long()
   bwipe!
 endfunc
 
+" A SAL rule that is too long to case-fold must not move the sentinel entry
+" out of its last position in the sl_sal array.
+func Test_spellfile_long_sal_rule()
+  call writefile(['1', 'ab'], 'Xlongsal.dic', 'D')
+  call writefile(['SAL ' .. repeat('w', 299) .. ' a',
+        \ "SAL a\u00e9 a"], 'Xlongsal.aff', 'D')
+  mkspell! Xlongsal Xlongsal
+  set spelllang=Xlongsal.utf-8.spl spell
+  " must not crash
+  call soundfold('ab')
+  set spelllang& spell&
+  call delete('Xlongsal.utf-8.spl')
+endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index a5c38c915..56e866a62 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    963,
 /**/
     962,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1ww4Ce-00931B-4b%40256bit.org.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.