diff src/vim9execute.c @ 20257:683c2da4982b v8.2.0684

patch 8.2.0684: Vim9: memory leak when using lambda Commit: https://github.com/vim/vim/commit/f7779c63d4fe531e2483502d4441f24802342768 Author: Bram Moolenaar <Bram@vim.org> Date: Sun May 3 15:38:16 2020 +0200 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.
author Bram Moolenaar <Bram@vim.org>
date Sun, 03 May 2020 15:45:05 +0200
parents aac52c32a91f
children 49b50843e725
line wrap: on
line diff
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -232,10 +232,6 @@ call_dfunc(int cdf_idx, int argcount_arg
     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 @@ handle_closure_in_use(ectx_T *ectx, int 
 	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 @@ handle_closure_in_use(ectx_T *ectx, int 
 	{
 	    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 @@ call_partial(typval_T *tv, int argcount,
 	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 @@ call_def_function(
 
 			// 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 @@ check_not_string(typval_T *tv)
     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