patch 8.2.0684: Vim9: memory leak when using lambda
Problem: Vim9: memory leak when using lambda.
Solution: Move the funccal context to the partial. Free the function when
exiting.
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 2404282..c74240f 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -232,10 +232,6 @@
ectx->ec_instr = dfunc->df_instr;
estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
- // used for closures
- ectx->ec_outer_stack = dfunc->df_ectx_stack;
- ectx->ec_outer_frame = dfunc->df_ectx_frame;
-
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argcount, ectx);
@@ -269,7 +265,10 @@
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)
+ {
closure_in_use = TRUE;
+ break;
+ }
}
if (closure_in_use)
@@ -315,15 +314,17 @@
{
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)
{
- dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
- + tv->vval.v_partial->pt_func->uf_dfunc_idx;
- ++funcstack->fs_refcount;
- pt_dfunc->df_funcstack = funcstack;
- pt_dfunc->df_ectx_stack = &funcstack->fs_ga;
- pt_dfunc->df_ectx_frame = ectx->ec_frame_idx - top;
+ partial_T *partial = tv->vval.v_partial;
+
+ if (partial->pt_refcount > 1)
+ {
+ ++funcstack->fs_refcount;
+ partial->pt_funcstack = funcstack;
+ partial->pt_ectx_stack = &funcstack->fs_ga;
+ partial->pt_ectx_frame = ectx->ec_frame_idx - top;
+ }
}
}
}
@@ -515,7 +516,15 @@
partial_T *pt = tv->vval.v_partial;
if (pt->pt_func != NULL)
- return call_ufunc(pt->pt_func, argcount, ectx, NULL);
+ {
+ int ret = call_ufunc(pt->pt_func, argcount, ectx, NULL);
+
+ // closure may need the function context where it was defined
+ ectx->ec_outer_stack = pt->pt_ectx_stack;
+ ectx->ec_outer_frame = pt->pt_ectx_frame;
+
+ return ret;
+ }
name = pt->pt_name;
}
else if (tv->v_type == VAR_FUNC)
@@ -1434,8 +1443,8 @@
// The closure needs to find arguments and local
// variables in the current stack.
- pt_dfunc->df_ectx_stack = &ectx.ec_stack;
- pt_dfunc->df_ectx_frame = ectx.ec_frame_idx;
+ pt->pt_ectx_stack = &ectx.ec_stack;
+ pt->pt_ectx_frame = ectx.ec_frame_idx;
// If this function returns and the closure is still
// used, we need to make a copy of the context
@@ -2676,25 +2685,5 @@
return OK;
}
-/*
- * Mark items in a def function as used.
- */
- int
-set_ref_in_dfunc(ufunc_T *ufunc, int copyID)
-{
- dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
- int abort = FALSE;
-
- if (dfunc->df_funcstack != NULL)
- {
- typval_T *stack = dfunc->df_funcstack->fs_ga.ga_data;
- int idx;
-
- for (idx = 0; idx < dfunc->df_funcstack->fs_ga.ga_len; ++idx)
- abort = abort || set_ref_in_item(stack + idx, copyID, NULL, NULL);
- }
- return abort;
-}
-
#endif // FEAT_EVAL