0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 9.1.1071: args missing after failing to redefine a function

Problem:  Arguments of a function are missing after failing to redefine
          it (after 8.2.2505), and heap-use-after-free with script-local
          function (after 9.1.1063).
Solution: Don't clear arguments or free uf_name_exp when failing to
          redefine an existing function (zeertzjq)

closes: #16567

Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2025-02-02 19:03:17 +01:00
committed by Christian Brabandt
parent edf0f7db28
commit 04d2a3fdc0
3 changed files with 45 additions and 5 deletions

View File

@@ -473,6 +473,43 @@ func Test_func_def_error()
" Try to list functions using an invalid search pattern " Try to list functions using an invalid search pattern
call assert_fails('function /\%(/', 'E53:') call assert_fails('function /\%(/', 'E53:')
" Use a script-local function to cover uf_name_exp.
func s:TestRedefine(arg1 = 1, arg2 = 10)
let caught_E122 = 0
try
func s:TestRedefine(arg1 = 1, arg2 = 10)
endfunc
catch /E122:/
let caught_E122 = 1
endtry
call assert_equal(1, caught_E122)
let caught_E127 = 0
try
func! s:TestRedefine(arg1 = 1, arg2 = 10)
endfunc
catch /E127:/
let caught_E127 = 1
endtry
call assert_equal(1, caught_E127)
" The failures above shouldn't cause heap-use-after-free here.
return [a:arg1 + a:arg2, expand('<stack>')]
endfunc
let stacks = []
" Call the function twice.
" Failing to redefine a function shouldn't clear its argument list.
for i in range(2)
let [val, stack] = s:TestRedefine(1000)
call assert_equal(1010, val)
call assert_match(expand('<SID>') .. 'TestRedefine\[20\]$', stack)
call add(stacks, stack)
endfor
call assert_equal(stacks[0], stacks[1])
delfunc s:TestRedefine
endfunc endfunc
" Test for deleting a function " Test for deleting a function

View File

@@ -5404,13 +5404,13 @@ define_function(
emsg_funcname(e_name_already_defined_str, name); emsg_funcname(e_name_already_defined_str, name);
else else
emsg_funcname(e_function_str_already_exists_add_bang_to_replace, name); emsg_funcname(e_function_str_already_exists_add_bang_to_replace, name);
goto erret; goto errret_keep;
} }
if (fp->uf_calls > 0) if (fp->uf_calls > 0)
{ {
emsg_funcname( emsg_funcname(
e_cannot_redefine_function_str_it_is_in_use, name); e_cannot_redefine_function_str_it_is_in_use, name);
goto erret; goto errret_keep;
} }
if (fp->uf_refcount > 1) if (fp->uf_refcount > 1)
{ {
@@ -5630,9 +5630,6 @@ erret:
ga_init(&fp->uf_def_args); ga_init(&fp->uf_def_args);
} }
errret_2: errret_2:
ga_clear_strings(&newargs);
ga_clear_strings(&default_args);
ga_clear_strings(&newlines);
if (fp != NULL) if (fp != NULL)
{ {
VIM_CLEAR(fp->uf_arg_types); VIM_CLEAR(fp->uf_arg_types);
@@ -5642,6 +5639,10 @@ errret_2:
} }
if (free_fp) if (free_fp)
VIM_CLEAR(fp); VIM_CLEAR(fp);
errret_keep:
ga_clear_strings(&newargs);
ga_clear_strings(&default_args);
ga_clear_strings(&newlines);
ret_free: ret_free:
ga_clear_strings(&argtypes); ga_clear_strings(&argtypes);
ga_clear(&arg_objm); ga_clear(&arg_objm);

View File

@@ -704,6 +704,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 */
/**/
1071,
/**/ /**/
1070, 1070,
/**/ /**/