summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-05-05 19:46:20 +0200
committerBram Moolenaar <Bram@vim.org>2020-05-05 19:46:20 +0200
commit221fcc741a6660bfc3fd0d64937d0c15bb71f51d (patch)
tree143f707a88e1d10dc7602dcb8278aad0ac325602
parent0e65d3de0aeff00aa42ea899f1afd11f8b22b93e (diff)
patch 8.2.0697: Vim9: memory leak when using nested functionv8.2.0697
Problem: Vim9: memory leak when using nested function. Solution: Unreference function when deleting instructions. Adjust reference count for local variables.
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c9
-rw-r--r--src/vim9execute.c23
3 files changed, 30 insertions, 4 deletions
diff --git a/src/version.c b/src/version.c
index 38755db73f..edbfa9349b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 697,
+/**/
696,
/**/
695,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index de2fb96b51..42fc0749ad 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -6629,6 +6629,14 @@ delete_instr(isn_T *isn)
vim_free(isn->isn_arg.ufunc.cuf_name);
break;
+ case ISN_FUNCREF:
+ {
+ dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ + isn->isn_arg.funcref.fr_func;
+ func_ptr_unref(dfunc->df_ufunc);
+ }
+ break;
+
case ISN_2BOOL:
case ISN_2STRING:
case ISN_ADDBLOB:
@@ -6657,7 +6665,6 @@ delete_instr(isn_T *isn)
case ISN_EXECCONCAT:
case ISN_EXECUTE:
case ISN_FOR:
- case ISN_FUNCREF:
case ISN_INDEX:
case ISN_JUMP:
case ISN_LOAD:
diff --git a/src/vim9execute.c b/src/vim9execute.c
index c74240ff20..386b8491f9 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -264,10 +264,27 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
{
tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
+ dfunc->df_varcount + idx);
- if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1)
+ if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
+ && tv->vval.v_partial->pt_refcount > 1)
{
- closure_in_use = TRUE;
- break;
+ int refcount = tv->vval.v_partial->pt_refcount;
+ int i;
+
+ // A Reference in a local variables doesn't count, its get
+ // unreferenced on return.
+ for (i = 0; i < dfunc->df_varcount; ++i)
+ {
+ typval_T *stv = STACK_TV(ectx->ec_frame_idx
+ + STACK_FRAME_SIZE + i);
+ if (stv->v_type == VAR_PARTIAL
+ && tv->vval.v_partial == stv->vval.v_partial)
+ --refcount;
+ }
+ if (refcount > 1)
+ {
+ closure_in_use = TRUE;
+ break;
+ }
}
}