diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-06-05 21:06:10 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-06-05 21:06:10 +0200 |
commit | 3fffa97159a427067b60c80ed4645e168cc5c4bd (patch) | |
tree | f0fb9f2fd843478461584c9f6444c8c15d0ae1c5 | |
parent | 07188fc5ef2366a3b1952e8686a4031b44152d59 (diff) | |
download | vim-git-3fffa97159a427067b60c80ed4645e168cc5c4bd.tar.gz |
patch 8.2.0908: crash when changing the function table while listing itv8.2.0908
Problem: Crash when changing the function table while listing it.
Solution: Bail out when the function table changes. (closes #6209)
-rw-r--r-- | src/testdir/test_timers.vim | 25 | ||||
-rw-r--r-- | src/userfunc.c | 71 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 67 insertions, 31 deletions
diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim index 639f5c2d1..829e94b5d 100644 --- a/src/testdir/test_timers.vim +++ b/src/testdir/test_timers.vim @@ -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 diff --git a/src/userfunc.c b/src/userfunc.c index 469dcc1a5..b495769a9 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2373,6 +2373,44 @@ untrans_function_name(char_u *name) } /* + * 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(®match, fp->uf_name, 0)) - list_func_head(fp, FALSE); - } - } + list_functions(®match); vim_regfree(regmatch.regprog); } } diff --git a/src/version.c b/src/version.c index 3fccc702b..20c0e0dec 100644 --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 908, +/**/ 907, /**/ 906, |