diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-05-05 19:46:20 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-05-05 19:46:20 +0200 |
commit | 221fcc741a6660bfc3fd0d64937d0c15bb71f51d (patch) | |
tree | 143f707a88e1d10dc7602dcb8278aad0ac325602 | |
parent | 0e65d3de0aeff00aa42ea899f1afd11f8b22b93e (diff) |
patch 8.2.0697: Vim9: memory leak when using nested functionv8.2.0697
Problem: Vim9: memory leak when using nested function.
Solution: Unreference function when deleting instructions. Adjust reference
count for local variables.
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9compile.c | 9 | ||||
-rw-r--r-- | src/vim9execute.c | 23 |
3 files changed, 30 insertions, 4 deletions
diff --git a/src/version.c b/src/version.c index 38755db73f..edbfa9349b 100644 --- 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 index de2fb96b51..42fc0749ad 100644 --- 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 index c74240ff20..386b8491f9 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -264,10 +264,27 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments) { 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; + } } } |