mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.1712: Vim9: leaking memory when calling a lambda
Problem: Vim9: leaking memory when calling a lambda. Solution: Decrement function reference from ISN_DCALL.
This commit is contained in:
@@ -12,6 +12,7 @@ char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *e
|
|||||||
ufunc_T *find_func_even_dead(char_u *name, int is_global, cctx_T *cctx);
|
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);
|
||||||
int func_is_global(ufunc_T *ufunc);
|
int func_is_global(ufunc_T *ufunc);
|
||||||
|
int func_name_refcount(char_u *name);
|
||||||
void copy_func(char_u *lambda, char_u *global);
|
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);
|
||||||
|
@@ -1058,7 +1058,7 @@ cleanup_function_call(funccall_T *fc)
|
|||||||
* using function() does not count as a reference, because the function is
|
* using function() does not count as a reference, because the function is
|
||||||
* looked up by name.
|
* looked up by name.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
func_name_refcount(char_u *name)
|
func_name_refcount(char_u *name)
|
||||||
{
|
{
|
||||||
return isdigit(*name) || *name == '<';
|
return isdigit(*name) || *name == '<';
|
||||||
@@ -1176,8 +1176,9 @@ func_clear(ufunc_T *fp, int force)
|
|||||||
* Free a function and remove it from the list of functions. Does not free
|
* Free a function and remove it from the list of functions. Does not free
|
||||||
* what a function contains, call func_clear() first.
|
* what a function contains, call func_clear() first.
|
||||||
* When "force" is TRUE we are exiting.
|
* When "force" is TRUE we are exiting.
|
||||||
|
* Returns OK when the function was actually freed.
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
func_free(ufunc_T *fp, int force)
|
func_free(ufunc_T *fp, int force)
|
||||||
{
|
{
|
||||||
// Only remove it when not done already, otherwise we would remove a newer
|
// Only remove it when not done already, otherwise we would remove a newer
|
||||||
@@ -1191,7 +1192,9 @@ func_free(ufunc_T *fp, int force)
|
|||||||
unlink_def_function(fp);
|
unlink_def_function(fp);
|
||||||
VIM_CLEAR(fp->uf_name_exp);
|
VIM_CLEAR(fp->uf_name_exp);
|
||||||
vim_free(fp);
|
vim_free(fp);
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1890,9 +1893,13 @@ free_all_functions(void)
|
|||||||
++skipped;
|
++skipped;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
func_free(fp, FALSE);
|
if (func_free(fp, FALSE) == OK)
|
||||||
skipped = 0;
|
{
|
||||||
break;
|
skipped = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// did not actually free it
|
||||||
|
++skipped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -750,6 +750,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 */
|
||||||
|
/**/
|
||||||
|
1712,
|
||||||
/**/
|
/**/
|
||||||
1711,
|
1711,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -1452,7 +1452,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
|||||||
ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL
|
ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL
|
||||||
: ISN_UCALL)) == NULL)
|
: ISN_UCALL)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (ufunc->uf_def_status != UF_NOT_COMPILED)
|
if (isn->isn_type == ISN_DCALL)
|
||||||
{
|
{
|
||||||
isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
|
isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
|
||||||
isn->isn_arg.dfunc.cdf_argcount = argcount;
|
isn->isn_arg.dfunc.cdf_argcount = argcount;
|
||||||
@@ -2634,8 +2634,8 @@ compile_lambda_call(char_u **arg, cctx_T *cctx)
|
|||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10);
|
ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10);
|
||||||
|
|
||||||
// The function will have one line: "return {expr}".
|
// The function will have one line: "return {expr}". Compile it into
|
||||||
// Compile it into instructions.
|
// instructions so that we get any errors right now.
|
||||||
compile_def_function(ufunc, TRUE, cctx);
|
compile_def_function(ufunc, TRUE, cctx);
|
||||||
|
|
||||||
// compile the arguments
|
// compile the arguments
|
||||||
@@ -7285,7 +7285,19 @@ delete_instr(isn_T *isn)
|
|||||||
{
|
{
|
||||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
+ isn->isn_arg.funcref.fr_func;
|
+ isn->isn_arg.funcref.fr_func;
|
||||||
func_ptr_unref(dfunc->df_ufunc);
|
|
||||||
|
if (func_name_refcount(dfunc->df_ufunc->uf_name))
|
||||||
|
func_ptr_unref(dfunc->df_ufunc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ISN_DCALL:
|
||||||
|
{
|
||||||
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
|
+ isn->isn_arg.dfunc.cdf_idx;
|
||||||
|
|
||||||
|
if (func_name_refcount(dfunc->df_ufunc->uf_name))
|
||||||
|
func_ptr_unref(dfunc->df_ufunc);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -7333,7 +7345,6 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_COMPARESPECIAL:
|
case ISN_COMPARESPECIAL:
|
||||||
case ISN_COMPARESTRING:
|
case ISN_COMPARESTRING:
|
||||||
case ISN_CONCAT:
|
case ISN_CONCAT:
|
||||||
case ISN_DCALL:
|
|
||||||
case ISN_DROP:
|
case ISN_DROP:
|
||||||
case ISN_ECHO:
|
case ISN_ECHO:
|
||||||
case ISN_ECHOERR:
|
case ISN_ECHOERR:
|
||||||
|
Reference in New Issue
Block a user