Mercurial > vim
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