summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-05-06 22:18:17 +0200
committerBram Moolenaar <Bram@vim.org>2020-05-06 22:18:17 +0200
commitf821ddaa0c27230012a6bffbec6fb0ab2f101171 (patch)
tree3f1ec3abf833b521b235e40415b108353d8973bb
parentb68b346e6db6d3f848e0a89905fcd7777b73c5d8 (diff)
patch 8.2.0704: Vim9: memory leak in disassemble testv8.2.0704
Problem: Vim9: memory leak in disassemble test. Solution: Decrement refcount when creating funccal.
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c28
2 files changed, 29 insertions, 1 deletions
diff --git a/src/version.c b/src/version.c
index b507c89b28..f22b37d4cb 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 */
/**/
+ 704,
+/**/
703,
/**/
702,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 9651f5e9b2..cc677b0013 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -270,7 +270,7 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
int refcount = tv->vval.v_partial->pt_refcount;
int i;
- // A Reference in a local variables doesn't count, its get
+ // A Reference in a local variables doesn't count, it gets
// unreferenced on return.
for (i = 0; i < dfunc->df_varcount; ++i)
{
@@ -323,6 +323,32 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
for (idx = 0; idx < dfunc->df_varcount; ++idx)
{
tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + idx);
+
+ // Do not copy a partial created for a local function.
+ // TODO: this won't work if the closure actually uses it. But when
+ // keeping it it gets complicated: it will create a reference cycle
+ // inside the partial, thus needs special handling for garbage
+ // collection.
+ if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL)
+ {
+ int i;
+ typval_T *ctv;
+
+ for (i = 0; i < dfunc->df_closure_count; ++i)
+ {
+ ctv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
+ + dfunc->df_varcount + i);
+ if (tv->vval.v_partial == ctv->vval.v_partial)
+ break;
+ }
+ if (i < dfunc->df_closure_count)
+ {
+ (stack + argcount + STACK_FRAME_SIZE + idx)->v_type =
+ VAR_UNKNOWN;
+ continue;
+ }
+ }
+
*(stack + argcount + STACK_FRAME_SIZE + idx) = *tv;
tv->v_type = VAR_UNKNOWN;
}