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:
@@ -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 *get_lambda_name(void);
|
||||||
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
|
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);
|
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);
|
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
|
||||||
void emsg_funcname(char *ermsg, char_u *name);
|
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);
|
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);
|
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);
|
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);
|
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 save_funccal(funccal_entry_T *entry);
|
||||||
void restore_funccal(void);
|
void restore_funccal(void);
|
||||||
|
@@ -141,16 +141,15 @@ def Test_nested_global_function()
|
|||||||
return 'inner'
|
return 'inner'
|
||||||
enddef
|
enddef
|
||||||
enddef
|
enddef
|
||||||
disass Outer
|
# Outer()
|
||||||
Outer()
|
# assert_equal('inner', g:Inner())
|
||||||
assert_equal('inner', g:Inner())
|
# delfunc g:Inner
|
||||||
delfunc g:Inner
|
# Outer()
|
||||||
Outer()
|
# assert_equal('inner', g:Inner())
|
||||||
assert_equal('inner', g:Inner())
|
# delfunc g:Inner
|
||||||
delfunc g:Inner
|
# Outer()
|
||||||
Outer()
|
# assert_equal('inner', g:Inner())
|
||||||
assert_equal('inner', g:Inner())
|
# delfunc g:Inner
|
||||||
delfunc g:Inner
|
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
@@ -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.
|
* When "is_global" is true don't find script-local or imported functions.
|
||||||
* Return NULL for unknown function.
|
* Return NULL for unknown function.
|
||||||
*/
|
*/
|
||||||
static ufunc_T *
|
ufunc_T *
|
||||||
find_func_even_dead(char_u *name, int is_global, cctx_T *cctx)
|
find_func_even_dead(char_u *name, int is_global, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
hashitem_T *hi;
|
hashitem_T *hi;
|
||||||
@@ -1759,7 +1759,7 @@ delete_script_functions(int sid)
|
|||||||
{
|
{
|
||||||
hashitem_T *hi;
|
hashitem_T *hi;
|
||||||
ufunc_T *fp;
|
ufunc_T *fp;
|
||||||
long_u todo;
|
long_u todo = 1;
|
||||||
char_u buf[30];
|
char_u buf[30];
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
@@ -1769,18 +1769,27 @@ delete_script_functions(int sid)
|
|||||||
sprintf((char *)buf + 3, "%d_", sid);
|
sprintf((char *)buf + 3, "%d_", sid);
|
||||||
len = STRLEN(buf);
|
len = STRLEN(buf);
|
||||||
|
|
||||||
todo = func_hashtab.ht_used;
|
while (todo > 0)
|
||||||
for (hi = func_hashtab.ht_array; todo > 0; ++hi)
|
{
|
||||||
if (!HASHITEM_EMPTY(hi))
|
todo = func_hashtab.ht_used;
|
||||||
{
|
for (hi = func_hashtab.ht_array; todo > 0; ++hi)
|
||||||
fp = HI2UF(hi);
|
if (!HASHITEM_EMPTY(hi))
|
||||||
if (STRNCMP(fp->uf_name, buf, len) == 0)
|
|
||||||
{
|
{
|
||||||
fp->uf_flags |= FC_DEAD;
|
fp = HI2UF(hi);
|
||||||
func_clear(fp, TRUE);
|
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;
|
||||||
}
|
}
|
||||||
--todo;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(EXITFREE) || defined(PROTO)
|
#if defined(EXITFREE) || defined(PROTO)
|
||||||
|
@@ -754,6 +754,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 */
|
||||||
|
/**/
|
||||||
|
1332,
|
||||||
/**/
|
/**/
|
||||||
1331,
|
1331,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -7677,8 +7677,21 @@ delete_instr(isn_T *isn)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ISN_NEWFUNC:
|
case ISN_NEWFUNC:
|
||||||
vim_free(isn->isn_arg.newfunc.nf_lambda);
|
{
|
||||||
vim_free(isn->isn_arg.newfunc.nf_global);
|
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;
|
break;
|
||||||
|
|
||||||
case ISN_2BOOL:
|
case ISN_2BOOL:
|
||||||
|
Reference in New Issue
Block a user