1
0
forked from aniani/vim

patch 8.2.0908: crash when changing the function table while listing it

Problem:    Crash when changing the function table while listing it.
Solution:   Bail out when the function table changes. (closes #6209)
This commit is contained in:
Bram Moolenaar
2020-06-05 21:06:10 +02:00
parent 07188fc5ef
commit 3fffa97159
3 changed files with 67 additions and 31 deletions

View File

@@ -3,6 +3,7 @@
source check.vim
CheckFeature timers
source screendump.vim
source shared.vim
source term_util.vim
@@ -424,4 +425,28 @@ func Test_timer_invalid_callback()
call assert_fails('call timer_start(0, "0")', 'E921')
endfunc
func Test_timer_changing_function_list()
CheckRunVimInTerminal
" Create a large number of functions. Should get the "more" prompt.
" The typing "G" triggers the timer, which changes the function table.
let lines =<< trim END
for func in map(range(1,99), "'Func' .. v:val")
exe "func " .. func .. "()"
endfunc
endfor
au CmdlineLeave : call timer_start(0, {-> 0})
END
call writefile(lines, 'XTest_timerchange')
let buf = RunVimInTerminal('-S XTest_timerchange', #{rows: 10})
call term_sendkeys(buf, ":fu\<CR>")
call WaitForAssert({-> assert_match('-- More --', term_getline(buf, 10))})
call term_sendkeys(buf, "G")
call WaitForAssert({-> assert_match('E454', term_getline(buf, 9))})
call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf)
call delete('XTest_timerchange')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -2372,6 +2372,44 @@ untrans_function_name(char_u *name)
return NULL;
}
/*
* List functions. When "regmatch" is NULL all of then.
* Otherwise functions matching "regmatch".
*/
static void
list_functions(regmatch_T *regmatch)
{
long_u used = func_hashtab.ht_used;
long_u todo = used;
hashitem_T *ht_array = func_hashtab.ht_array;
hashitem_T *hi;
for (hi = ht_array; todo > 0 && !got_int; ++hi)
{
if (!HASHITEM_EMPTY(hi))
{
ufunc_T *fp = HI2UF(hi);
--todo;
if ((fp->uf_flags & FC_DEAD) == 0
&& (regmatch == NULL
? !message_filtered(fp->uf_name)
&& !func_name_refcount(fp->uf_name)
: !isdigit(*fp->uf_name)
&& vim_regexec(regmatch, fp->uf_name, 0)))
{
list_func_head(fp, FALSE);
if (used != func_hashtab.ht_used
|| ht_array != func_hashtab.ht_array)
{
emsg(_("E454: function list was modified"));
return;
}
}
}
}
}
/*
* ":function" also supporting nested ":def".
* Returns a pointer to the function or NULL if no function defined.
@@ -2407,7 +2445,6 @@ def_function(exarg_T *eap, char_u *name_arg)
funcdict_T fudi;
static int func_nr = 0; // number for nameless function
int paren;
int todo;
hashitem_T *hi;
int do_concat = TRUE;
linenr_T sourcing_lnum_off;
@@ -2428,22 +2465,7 @@ def_function(exarg_T *eap, char_u *name_arg)
if (ends_excmd2(eap->cmd, eap->arg))
{
if (!eap->skip)
{
todo = (int)func_hashtab.ht_used;
for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
{
if (!HASHITEM_EMPTY(hi))
{
--todo;
fp = HI2UF(hi);
if ((fp->uf_flags & FC_DEAD)
|| message_filtered(fp->uf_name))
continue;
if (!func_name_refcount(fp->uf_name))
list_func_head(fp, FALSE);
}
}
}
list_functions(NULL);
eap->nextcmd = check_nextcmd(eap->arg);
return NULL;
}
@@ -2465,20 +2487,7 @@ def_function(exarg_T *eap, char_u *name_arg)
if (regmatch.regprog != NULL)
{
regmatch.rm_ic = p_ic;
todo = (int)func_hashtab.ht_used;
for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
{
if (!HASHITEM_EMPTY(hi))
{
--todo;
fp = HI2UF(hi);
if ((fp->uf_flags & FC_DEAD) == 0
&& !isdigit(*fp->uf_name)
&& vim_regexec(&regmatch, fp->uf_name, 0))
list_func_head(fp, FALSE);
}
}
list_functions(&regmatch);
vim_regfree(regmatch.regprog);
}
}

View File

@@ -746,6 +746,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
908,
/**/
907,
/**/