]> granicus.if.org Git - vim/commitdiff
patch 8.2.1711: Vim9: leaking memory when using partial v8.2.1711
authorBram Moolenaar <Bram@vim.org>
Sat, 19 Sep 2020 13:16:50 +0000 (15:16 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 19 Sep 2020 13:16:50 +0000 (15:16 +0200)
Problem:    Vim9: leaking memory when using partial.
Solution:   Do delete the function even when it was compiled.

src/proto/vim9compile.pro
src/userfunc.c
src/version.c
src/vim9compile.c
src/vim9execute.c

index 80d0b25a27afe347a81f2f8b5b870750a5ff53b3..1844e1728c00bfe157ffca54a84e09265fbc8db6 100644 (file)
@@ -17,5 +17,6 @@ int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx
 void set_function_type(ufunc_T *ufunc);
 void delete_instr(isn_T *isn);
 void clear_def_function(ufunc_T *ufunc);
+void unlink_def_function(ufunc_T *ufunc);
 void free_def_functions(void);
 /* vim: set ft=c : */
index 017098d0fcfc6822d0738ce411b9774fbaf8a403..d6a7e5d16d4aa6ce1680e830af24827b1871def8 100644 (file)
@@ -1049,6 +1049,21 @@ cleanup_function_call(funccall_T *fc)
        }
     }
 }
+
+/*
+ * There are two kinds of function names:
+ * 1. ordinary names, function defined with :function or :def
+ * 2. numbered functions and lambdas
+ * For the first we only count the name stored in func_hashtab as a reference,
+ * using function() does not count as a reference, because the function is
+ * looked up by name.
+ */
+    static int
+func_name_refcount(char_u *name)
+{
+    return isdigit(*name) || *name == '<';
+}
+
 /*
  * Unreference "fc": decrement the reference count and free it when it
  * becomes zero.  "fp" is detached from "fc".
@@ -1172,6 +1187,8 @@ func_free(ufunc_T *fp, int force)
 
     if ((fp->uf_flags & FC_DEAD) == 0 || force)
     {
+       if (fp->uf_dfunc_idx > 0)
+           unlink_def_function(fp);
        VIM_CLEAR(fp->uf_name_exp);
        vim_free(fp);
     }
@@ -1185,7 +1202,8 @@ func_free(ufunc_T *fp, int force)
 func_clear_free(ufunc_T *fp, int force)
 {
     func_clear(fp, force);
-    if (force || fp->uf_dfunc_idx == 0 || (fp->uf_flags & FC_COPY))
+    if (force || fp->uf_dfunc_idx == 0 || func_name_refcount(fp->uf_name)
+                                                  || (fp->uf_flags & FC_COPY))
        func_free(fp, force);
     else
        fp->uf_flags |= FC_DEAD;
@@ -1730,20 +1748,6 @@ call_user_func_check(
     return error;
 }
 
-/*
- * There are two kinds of function names:
- * 1. ordinary names, function defined with :function
- * 2. numbered functions and lambdas
- * For the first we only count the name stored in func_hashtab as a reference,
- * using function() does not count as a reference, because the function is
- * looked up by name.
- */
-    static int
-func_name_refcount(char_u *name)
-{
-    return isdigit(*name) || *name == '<';
-}
-
 static funccal_entry_T *funccal_stack = NULL;
 
 /*
index 3b1f963bbf8b8778b957650d0b9b3f1cb0fc85e6..aa09b70d242a72afdf796ec3b80fb0d966c39063 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1711,
 /**/
     1710,
 /**/
index a70ed5a44a5e3cd13d1d6aea969667a25bdd9ed6..a6b4ba4098b996aeb85aedb4d3c2e805f58faad3 100644 (file)
@@ -2593,6 +2593,9 @@ compile_lambda(char_u **arg, cctx_T *cctx)
        // The return type will now be known.
        set_function_type(ufunc);
 
+       // The function reference count will be 1.  When the ISN_FUNCREF
+       // instruction is deleted the reference count is decremented and the
+       // function is freed.
        return generate_FUNCREF(cctx, ufunc);
     }
 
@@ -7424,6 +7427,18 @@ clear_def_function(ufunc_T *ufunc)
     }
 }
 
+/*
+ * Used when a user function is about to be deleted: remove the pointer to it.
+ * The entry in def_functions is then unused.
+ */
+    void
+unlink_def_function(ufunc_T *ufunc)
+{
+    dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
+
+    dfunc->df_ufunc = NULL;
+}
+
 #if defined(EXITFREE) || defined(PROTO)
 /*
  * Free all functions defined with ":def".
index e4ccaaa8a11124822425dd70a2ba3ca13c618173..cd6eff56cfaa1b6294a12afe5562174c87309d3b 100644 (file)
@@ -270,12 +270,18 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
 {
     dfunc_T    *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                          + ectx->ec_dfunc_idx;
-    int                argcount = ufunc_argcount(dfunc->df_ufunc);
-    int                top = ectx->ec_frame_idx - argcount;
+    int                argcount;
+    int                top;
     int                idx;
     typval_T   *tv;
     int                closure_in_use = FALSE;
 
+    if (dfunc->df_ufunc == NULL)
+       // function was freed
+       return OK;
+    argcount = ufunc_argcount(dfunc->df_ufunc);
+    top = ectx->ec_frame_idx - argcount;
+
     // Check if any created closure is still in use.
     for (idx = 0; idx < dfunc->df_closure_count; ++idx)
     {