Mercurial > vim
changeset 20283:934657e365e5 v8.2.0697
patch 8.2.0697: Vim9: memory leak when using nested function
Commit: https://github.com/vim/vim/commit/221fcc741a6660bfc3fd0d64937d0c15bb71f51d
Author: Bram Moolenaar <Bram@vim.org>
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.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 05 May 2020 20:00:04 +0200 |
parents | a461511dc68f |
children | 7b7c9d3abf7c |
files | src/version.c src/vim9compile.c src/vim9execute.c |
diffstat | 3 files changed, 30 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- 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,
--- 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:
--- 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; + } } }