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

patch 8.2.1711: Vim9: leaking memory when using partial

Problem:    Vim9: leaking memory when using partial.
Solution:   Do delete the function even when it was compiled.
This commit is contained in:
Bram Moolenaar
2020-09-19 15:16:50 +02:00
parent 77b20977dc
commit fdeab65db6
5 changed files with 45 additions and 17 deletions

View File

@@ -17,5 +17,6 @@ int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx
void set_function_type(ufunc_T *ufunc); void set_function_type(ufunc_T *ufunc);
void delete_instr(isn_T *isn); void delete_instr(isn_T *isn);
void clear_def_function(ufunc_T *ufunc); void clear_def_function(ufunc_T *ufunc);
void unlink_def_function(ufunc_T *ufunc);
void free_def_functions(void); void free_def_functions(void);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -1049,6 +1049,21 @@ cleanup_function_call(funccall_T *fc)
} }
} }
} }
/*
* There are two kinds of function names:
* 1. ordinary names, function defined with :function or :def
* 2. numbered functions and lambdas
* For the first we only count the name stored in func_hashtab as a reference,
* using function() does not count as a reference, because the function is
* looked up by name.
*/
static int
func_name_refcount(char_u *name)
{
return isdigit(*name) || *name == '<';
}
/* /*
* Unreference "fc": decrement the reference count and free it when it * Unreference "fc": decrement the reference count and free it when it
* becomes zero. "fp" is detached from "fc". * becomes zero. "fp" is detached from "fc".
@@ -1172,6 +1187,8 @@ func_free(ufunc_T *fp, int force)
if ((fp->uf_flags & FC_DEAD) == 0 || force) if ((fp->uf_flags & FC_DEAD) == 0 || force)
{ {
if (fp->uf_dfunc_idx > 0)
unlink_def_function(fp);
VIM_CLEAR(fp->uf_name_exp); VIM_CLEAR(fp->uf_name_exp);
vim_free(fp); vim_free(fp);
} }
@@ -1185,7 +1202,8 @@ func_free(ufunc_T *fp, int force)
func_clear_free(ufunc_T *fp, int force) func_clear_free(ufunc_T *fp, int force)
{ {
func_clear(fp, force); func_clear(fp, force);
if (force || fp->uf_dfunc_idx == 0 || (fp->uf_flags & FC_COPY)) if (force || fp->uf_dfunc_idx == 0 || func_name_refcount(fp->uf_name)
|| (fp->uf_flags & FC_COPY))
func_free(fp, force); func_free(fp, force);
else else
fp->uf_flags |= FC_DEAD; fp->uf_flags |= FC_DEAD;
@@ -1730,20 +1748,6 @@ call_user_func_check(
return error; return error;
} }
/*
* There are two kinds of function names:
* 1. ordinary names, function defined with :function
* 2. numbered functions and lambdas
* For the first we only count the name stored in func_hashtab as a reference,
* using function() does not count as a reference, because the function is
* looked up by name.
*/
static int
func_name_refcount(char_u *name)
{
return isdigit(*name) || *name == '<';
}
static funccal_entry_T *funccal_stack = NULL; static funccal_entry_T *funccal_stack = NULL;
/* /*

View File

@@ -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 */
/**/
1711,
/**/ /**/
1710, 1710,
/**/ /**/

View File

@@ -2593,6 +2593,9 @@ compile_lambda(char_u **arg, cctx_T *cctx)
// The return type will now be known. // The return type will now be known.
set_function_type(ufunc); set_function_type(ufunc);
// The function reference count will be 1. When the ISN_FUNCREF
// instruction is deleted the reference count is decremented and the
// function is freed.
return generate_FUNCREF(cctx, ufunc); return generate_FUNCREF(cctx, ufunc);
} }
@@ -7424,6 +7427,18 @@ clear_def_function(ufunc_T *ufunc)
} }
} }
/*
* Used when a user function is about to be deleted: remove the pointer to it.
* The entry in def_functions is then unused.
*/
void
unlink_def_function(ufunc_T *ufunc)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
dfunc->df_ufunc = NULL;
}
#if defined(EXITFREE) || defined(PROTO) #if defined(EXITFREE) || defined(PROTO)
/* /*
* Free all functions defined with ":def". * Free all functions defined with ":def".

View File

@@ -270,12 +270,18 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
{ {
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ectx->ec_dfunc_idx; + ectx->ec_dfunc_idx;
int argcount = ufunc_argcount(dfunc->df_ufunc); int argcount;
int top = ectx->ec_frame_idx - argcount; int top;
int idx; int idx;
typval_T *tv; typval_T *tv;
int closure_in_use = FALSE; int closure_in_use = FALSE;
if (dfunc->df_ufunc == NULL)
// function was freed
return OK;
argcount = ufunc_argcount(dfunc->df_ufunc);
top = ectx->ec_frame_idx - argcount;
// Check if any created closure is still in use. // Check if any created closure is still in use.
for (idx = 0; idx < dfunc->df_closure_count; ++idx) for (idx = 0; idx < dfunc->df_closure_count; ++idx)
{ {