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

5 views
Skip to first unread message

Christian Brabandt

unread,
Aug 17, 2026, 4:45:13 PM (18 hours ago) Aug 17
to vim...@googlegroups.com
patch 9.2.0963: crash when sound-folding a crafted spell file

Commit: https://github.com/vim/vim/commit/6ac008db969677304ba888854e5d44a32ce79853
Author: Christian Brabandt <c...@256bit.org>
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) <nor...@anthropic.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

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,
/**/
Reply all
Reply to author
Forward
0 new messages