# HG changeset patch # User Bram Moolenaar # Date 1588701604 -7200 # Node ID 934657e365e5ceba1cb330a846293a5454c7cacb # Parent a461511dc68fd9731c2dc4508003278fe8feb18c patch 8.2.0697: Vim9: memory leak when using nested function Commit: https://github.com/vim/vim/commit/221fcc741a6660bfc3fd0d64937d0c15bb71f51d Author: Bram Moolenaar Date: Tue May 5 19:46:20 2020 +0200 patch 8.2.0697: Vim9: memory leak when using nested function Problem: Vim9: memory leak when using nested function. Solution: Unreference function when deleting instructions. Adjust reference count for local variables. diff --git a/src/version.c b/src/version.c --- 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 --- 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 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -264,10 +264,27 @@ 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 && 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; + } } }