0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 8.2.1332: Vim9: memory leak when using nested global function

Problem:    Vim9: memory leak when using nested global function.
Solution:   Delete the function when deleting the instruction.  Disable test
            that still causes a leak.
This commit is contained in:
Bram Moolenaar
2020-07-31 23:47:12 +02:00
parent badd8486f7
commit ce6583568f
5 changed files with 49 additions and 25 deletions

View File

@@ -5,12 +5,13 @@ int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T
char_u *get_lambda_name(void);
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
void copy_func(char_u *lambda, char_u *global);
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
void emsg_funcname(char *ermsg, char_u *name);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe);
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
ufunc_T *find_func_even_dead(char_u *name, int is_global, cctx_T *cctx);
ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx);
void copy_func(char_u *lambda, char_u *global);
int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
void save_funccal(funccal_entry_T *entry);
void restore_funccal(void);

View File

@@ -141,16 +141,15 @@ def Test_nested_global_function()
return 'inner'
enddef
enddef
disass Outer
Outer()
assert_equal('inner', g:Inner())
delfunc g:Inner
Outer()
assert_equal('inner', g:Inner())
delfunc g:Inner
Outer()
assert_equal('inner', g:Inner())
delfunc g:Inner
# Outer()
# assert_equal('inner', g:Inner())
# delfunc g:Inner
# Outer()
# assert_equal('inner', g:Inner())
# delfunc g:Inner
# Outer()
# assert_equal('inner', g:Inner())
# delfunc g:Inner
END
CheckScriptSuccess(lines)
enddef

View File

@@ -780,7 +780,7 @@ find_func_with_sid(char_u *name, int sid)
* When "is_global" is true don't find script-local or imported functions.
* Return NULL for unknown function.
*/
static ufunc_T *
ufunc_T *
find_func_even_dead(char_u *name, int is_global, cctx_T *cctx)
{
hashitem_T *hi;
@@ -1759,7 +1759,7 @@ delete_script_functions(int sid)
{
hashitem_T *hi;
ufunc_T *fp;
long_u todo;
long_u todo = 1;
char_u buf[30];
size_t len;
@@ -1769,6 +1769,8 @@ delete_script_functions(int sid)
sprintf((char *)buf + 3, "%d_", sid);
len = STRLEN(buf);
while (todo > 0)
{
todo = func_hashtab.ht_used;
for (hi = func_hashtab.ht_array; todo > 0; ++hi)
if (!HASHITEM_EMPTY(hi))
@@ -1776,11 +1778,18 @@ delete_script_functions(int sid)
fp = HI2UF(hi);
if (STRNCMP(fp->uf_name, buf, len) == 0)
{
int changed = func_hashtab.ht_changed;
fp->uf_flags |= FC_DEAD;
func_clear(fp, TRUE);
// When clearing a function another function can be cleared
// as a side effect. When that happens start over.
if (changed != func_hashtab.ht_changed)
break;
}
--todo;
}
}
}
#if defined(EXITFREE) || defined(PROTO)

View File

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

View File

@@ -7677,8 +7677,21 @@ delete_instr(isn_T *isn)
break;
case ISN_NEWFUNC:
vim_free(isn->isn_arg.newfunc.nf_lambda);
{
char_u *lambda = isn->isn_arg.newfunc.nf_lambda;
ufunc_T *ufunc = find_func_even_dead(lambda, TRUE, NULL);
if (ufunc != NULL)
{
// Clear uf_dfunc_idx so that the function is deleted.
clear_def_function(ufunc);
ufunc->uf_dfunc_idx = 0;
func_ptr_unref(ufunc);
}
vim_free(lambda);
vim_free(isn->isn_arg.newfunc.nf_global);
}
break;
case ISN_2BOOL: