vim-patch:9.2.0963: crash when sound-folding a crafted spell file (#41358)

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: vim/vim#21076

6ac008db96

Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
zeertzjq
2026-08-18 09:03:37 +08:00
committed by GitHub
parent cc25b2f13c
commit bce3bf06a3
2 changed files with 15 additions and 1 deletions

View File

@@ -2938,7 +2938,8 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *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
// entries are less than three chars, optimize for that.

View File

@@ -828,5 +828,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