Skip to content

Commit fdeab65

Browse files
committed
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.
1 parent 77b2097 commit fdeab65

5 files changed

Lines changed: 45 additions & 17 deletions

File tree

src/proto/vim9compile.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx
1717
void set_function_type(ufunc_T *ufunc);
1818
void delete_instr(isn_T *isn);
1919
void clear_def_function(ufunc_T *ufunc);
20+
void unlink_def_function(ufunc_T *ufunc);
2021
void free_def_functions(void);
2122
/* vim: set ft=c : */

src/userfunc.c

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,21 @@ cleanup_function_call(funccall_T *fc)
10491049
}
10501050
}
10511051
}
1052+
1053+
/*
1054+
* There are two kinds of function names:
1055+
* 1. ordinary names, function defined with :function or :def
1056+
* 2. numbered functions and lambdas
1057+
* For the first we only count the name stored in func_hashtab as a reference,
1058+
* using function() does not count as a reference, because the function is
1059+
* looked up by name.
1060+
*/
1061+
static int
1062+
func_name_refcount(char_u *name)
1063+
{
1064+
return isdigit(*name) || *name == '<';
1065+
}
1066+
10521067
/*
10531068
* Unreference "fc": decrement the reference count and free it when it
10541069
* becomes zero. "fp" is detached from "fc".
@@ -1172,6 +1187,8 @@ func_free(ufunc_T *fp, int force)
11721187

11731188
if ((fp->uf_flags & FC_DEAD) == 0 || force)
11741189
{
1190+
if (fp->uf_dfunc_idx > 0)
1191+
unlink_def_function(fp);
11751192
VIM_CLEAR(fp->uf_name_exp);
11761193
vim_free(fp);
11771194
}
@@ -1185,7 +1202,8 @@ func_free(ufunc_T *fp, int force)
11851202
func_clear_free(ufunc_T *fp, int force)
11861203
{
11871204
func_clear(fp, force);
1188-
if (force || fp->uf_dfunc_idx == 0 || (fp->uf_flags & FC_COPY))
1205+
if (force || fp->uf_dfunc_idx == 0 || func_name_refcount(fp->uf_name)
1206+
|| (fp->uf_flags & FC_COPY))
11891207
func_free(fp, force);
11901208
else
11911209
fp->uf_flags |= FC_DEAD;
@@ -1730,20 +1748,6 @@ call_user_func_check(
17301748
return error;
17311749
}
17321750

1733-
/*
1734-
* There are two kinds of function names:
1735-
* 1. ordinary names, function defined with :function
1736-
* 2. numbered functions and lambdas
1737-
* For the first we only count the name stored in func_hashtab as a reference,
1738-
* using function() does not count as a reference, because the function is
1739-
* looked up by name.
1740-
*/
1741-
static int
1742-
func_name_refcount(char_u *name)
1743-
{
1744-
return isdigit(*name) || *name == '<';
1745-
}
1746-
17471751
static funccal_entry_T *funccal_stack = NULL;
17481752

17491753
/*

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
1711,
753755
/**/
754756
1710,
755757
/**/

src/vim9compile.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2593,6 +2593,9 @@ compile_lambda(char_u **arg, cctx_T *cctx)
25932593
// The return type will now be known.
25942594
set_function_type(ufunc);
25952595

2596+
// The function reference count will be 1. When the ISN_FUNCREF
2597+
// instruction is deleted the reference count is decremented and the
2598+
// function is freed.
25962599
return generate_FUNCREF(cctx, ufunc);
25972600
}
25982601

@@ -7424,6 +7427,18 @@ clear_def_function(ufunc_T *ufunc)
74247427
}
74257428
}
74267429

7430+
/*
7431+
* Used when a user function is about to be deleted: remove the pointer to it.
7432+
* The entry in def_functions is then unused.
7433+
*/
7434+
void
7435+
unlink_def_function(ufunc_T *ufunc)
7436+
{
7437+
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
7438+
7439+
dfunc->df_ufunc = NULL;
7440+
}
7441+
74277442
#if defined(EXITFREE) || defined(PROTO)
74287443
/*
74297444
* Free all functions defined with ":def".

src/vim9execute.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,18 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
270270
{
271271
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
272272
+ ectx->ec_dfunc_idx;
273-
int argcount = ufunc_argcount(dfunc->df_ufunc);
274-
int top = ectx->ec_frame_idx - argcount;
273+
int argcount;
274+
int top;
275275
int idx;
276276
typval_T *tv;
277277
int closure_in_use = FALSE;
278278

279+
if (dfunc->df_ufunc == NULL)
280+
// function was freed
281+
return OK;
282+
argcount = ufunc_argcount(dfunc->df_ufunc);
283+
top = ectx->ec_frame_idx - argcount;
284+
279285
// Check if any created closure is still in use.
280286
for (idx = 0; idx < dfunc->df_closure_count; ++idx)
281287
{

0 commit comments

Comments
 (0)