0
0
mirror of https://github.com/vim/vim.git synced 2025-09-26 04:04:07 -04:00

patch 9.0.0875: using freed memory when executing delfunc at more prompt

Problem:    Using freed memory when executing delfunc at the more prompt.
Solution:   Check function list not changed in another place. (closes #11437)
This commit is contained in:
Bram Moolenaar
2022-11-13 22:13:33 +00:00
parent 920d311480
commit 398a26f7fc
3 changed files with 89 additions and 28 deletions

View File

@@ -3026,4 +3026,31 @@ func Test_virtcol()
bwipe! bwipe!
endfunc endfunc
func Test_delfunc_while_listing()
CheckRunVimInTerminal
let lines =<< trim END
set nocompatible
for i in range(1, 999)
exe 'func ' .. 'MyFunc' .. i .. '()'
endfunc
endfor
au CmdlineLeave : call timer_start(0, {-> execute('delfunc MyFunc622')})
END
call writefile(lines, 'Xfunctionclear', 'D')
let buf = RunVimInTerminal('-S Xfunctionclear', {'rows': 12})
" This was using freed memory. The height of the terminal must be so that
" the next function to be listed with "j" is the one that is deleted in the
" timer callback, tricky!
call term_sendkeys(buf, ":func /MyFunc\<CR>")
call TermWait(buf, 50)
call term_sendkeys(buf, "j")
call TermWait(buf, 50)
call term_sendkeys(buf, "\<CR>")
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -3792,15 +3792,36 @@ printable_func_name(ufunc_T *fp)
return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name; return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name;
} }
/*
* When "prev_ht_changed" does not equal "ht_changed" give an error and return
* TRUE. Otherwise return FALSE.
*/
static int
function_list_modified(int prev_ht_changed)
{
if (prev_ht_changed != func_hashtab.ht_changed)
{
emsg(_(e_function_list_was_modified));
return TRUE;
}
return FALSE;
}
/* /*
* List the head of the function: "function name(arg1, arg2)". * List the head of the function: "function name(arg1, arg2)".
*/ */
static void static int
list_func_head(ufunc_T *fp, int indent) list_func_head(ufunc_T *fp, int indent)
{ {
int prev_ht_changed = func_hashtab.ht_changed;
int j; int j;
msg_start(); msg_start();
// a timer at the more prompt may have deleted the function
if (function_list_modified(prev_ht_changed))
return FAIL;
if (indent) if (indent)
msg_puts(" "); msg_puts(" ");
if (fp->uf_def_status != UF_NOT_COMPILED) if (fp->uf_def_status != UF_NOT_COMPILED)
@@ -3877,6 +3898,8 @@ list_func_head(ufunc_T *fp, int indent)
msg_clr_eos(); msg_clr_eos();
if (p_verbose > 0) if (p_verbose > 0)
last_set_msg(fp->uf_script_ctx); last_set_msg(fp->uf_script_ctx);
return OK;
} }
/* /*
@@ -4315,7 +4338,7 @@ save_function_name(
void void
list_functions(regmatch_T *regmatch) list_functions(regmatch_T *regmatch)
{ {
int changed = func_hashtab.ht_changed; int prev_ht_changed = func_hashtab.ht_changed;
long_u todo = func_hashtab.ht_used; long_u todo = func_hashtab.ht_used;
hashitem_T *hi; hashitem_T *hi;
@@ -4333,12 +4356,10 @@ list_functions(regmatch_T *regmatch)
: !isdigit(*fp->uf_name) : !isdigit(*fp->uf_name)
&& vim_regexec(regmatch, fp->uf_name, 0))) && vim_regexec(regmatch, fp->uf_name, 0)))
{ {
list_func_head(fp, FALSE); if (list_func_head(fp, FALSE) == FAIL)
if (changed != func_hashtab.ht_changed) return;
{ if (function_list_modified(prev_ht_changed))
emsg(_(e_function_list_was_modified));
return; return;
}
} }
} }
} }
@@ -4542,28 +4563,39 @@ define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free)
if (fp != NULL) if (fp != NULL)
{ {
list_func_head(fp, TRUE); // Check no function was added or removed from a timer, e.g. at
for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j) // the more prompt. "fp" may then be invalid.
int prev_ht_changed = func_hashtab.ht_changed;
if (list_func_head(fp, TRUE) == OK)
{ {
if (FUNCLINE(fp, j) == NULL) for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j)
continue; {
msg_putchar('\n'); if (FUNCLINE(fp, j) == NULL)
msg_outnum((long)(j + 1)); continue;
if (j < 9) msg_putchar('\n');
msg_putchar(' '); msg_outnum((long)(j + 1));
if (j < 99) if (j < 9)
msg_putchar(' '); msg_putchar(' ');
msg_prt_line(FUNCLINE(fp, j), FALSE); if (j < 99)
out_flush(); // show a line at a time msg_putchar(' ');
ui_breakcheck(); if (function_list_modified(prev_ht_changed))
} break;
if (!got_int) msg_prt_line(FUNCLINE(fp, j), FALSE);
{ out_flush(); // show a line at a time
msg_putchar('\n'); ui_breakcheck();
if (fp->uf_def_status != UF_NOT_COMPILED) }
msg_puts(" enddef"); if (!got_int)
else {
msg_puts(" endfunction"); msg_putchar('\n');
if (!function_list_modified(prev_ht_changed))
{
if (fp->uf_def_status != UF_NOT_COMPILED)
msg_puts(" enddef");
else
msg_puts(" endfunction");
}
}
} }
} }
else else

View File

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