]> granicus.if.org Git - vim/commitdiff
patch 8.2.2866: Vim9: memory leak when using inline function v8.2.2866
authorBram Moolenaar <Bram@vim.org>
Tue, 18 May 2021 13:09:18 +0000 (15:09 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 18 May 2021 13:09:18 +0000 (15:09 +0200)
Problem:    Vim9: memory leak when using inline function.
Solution:   Remember what strings to free.

src/eval.c
src/structs.h
src/userfunc.c
src/version.c

index 97c5f78dffaf50b2f72c2d49f8423f27a79d0b68..b5820b8d3263e0f821555d1a8e8406f924f31ae0 100644 (file)
@@ -416,6 +416,7 @@ skip_expr_concatenate(
     int                res;
     int                vim9script = in_vim9script();
     garray_T    *gap = evalarg == NULL ? NULL : &evalarg->eval_ga;
+    garray_T    *freegap = evalarg == NULL ? NULL : &evalarg->eval_freega;
     int                save_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
     int                evaluate = evalarg == NULL
                               ? FALSE : (evalarg->eval_flags & EVAL_EVALUATE);
@@ -427,6 +428,7 @@ skip_expr_concatenate(
        // leave room for "start"
        if (ga_grow(gap, 1) == OK)
            ++gap->ga_len;
+       ga_init2(freegap, sizeof(char_u *), 10);
     }
     *start = *arg;
 
@@ -444,7 +446,7 @@ skip_expr_concatenate(
     {
        if (evalarg->eval_ga.ga_len == 1)
        {
-           // just one line, no need to concatenate
+           // just the one line, no need to concatenate
            ga_clear(gap);
            gap->ga_itemsize = 0;
        }
@@ -471,7 +473,13 @@ skip_expr_concatenate(
                ga_clear_strings(gap);
            }
            else
+           {
                ga_clear(gap);
+
+               // free lines that were explicitly marked for freeing
+               ga_clear_strings(freegap);
+           }
+
            gap->ga_itemsize = 0;
            if (p == NULL)
                return FAIL;
@@ -3530,7 +3538,7 @@ eval7(
 
     /*
      * nested expression: (expression).
-     * lambda: (arg) => expr
+     * or lambda: (arg) => expr
      */
     case '(':  ret = NOTDONE;
                if (in_vim9script())
index 9861bb601d975b5a6421339ae51f61db35ba9904..3bb641be8454a6b916b03ccfa5ee084d3b5a701d 100644 (file)
@@ -1881,7 +1881,9 @@ typedef struct {
     // Used to collect lines while parsing them, so that they can be
     // concatenated later.  Used when "eval_ga.ga_itemsize" is not zero.
     // "eval_ga.ga_data" is a list of pointers to lines.
+    // "eval_freega" list pointers that need to be freed after concatenating.
     garray_T   eval_ga;
+    garray_T   eval_freega;
 
     // pointer to the last line obtained with getsourceline()
     char_u     *eval_tofree;
index bc7d9238439e049aa7c8d51fa28f0d505756c660..dd6939c9a37779ecf62c8a87b0c24c67896aa265 100644 (file)
@@ -976,6 +976,7 @@ lambda_function_body(
 {
     int                evaluate = (evalarg->eval_flags & EVAL_EVALUATE);
     garray_T   *gap = &evalarg->eval_ga;
+    garray_T   *freegap = &evalarg->eval_freega;
     ufunc_T    *ufunc = NULL;
     exarg_T    eap;
     garray_T   newlines;
@@ -1026,7 +1027,7 @@ lambda_function_body(
        {
            char_u  *p = skipwhite(((char_u **)newlines.ga_data)[idx]);
 
-           if (ga_grow(gap, 1) == FAIL)
+           if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL)
                goto erret;
 
            // Going to concatenate the lines after parsing.  For an empty or
@@ -1039,10 +1040,10 @@ lambda_function_body(
            pnl = vim_strnsave((char_u *)"\n", plen + 1);
            if (pnl != NULL)
                mch_memmove(pnl + 1, p, plen + 1);
-           ((char_u **)gap->ga_data)[gap->ga_len] = pnl;
-           ++gap->ga_len;
+           ((char_u **)gap->ga_data)[gap->ga_len++] = pnl;
+           ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl;
        }
-       if (ga_grow(gap, 1) == FAIL)
+       if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL)
            goto erret;
        if (cmdline != NULL)
            // more is following after the "}", which was skipped
@@ -1054,8 +1055,8 @@ lambda_function_body(
        pnl = vim_strnsave((char_u *)"\n", plen + 1);
        if (pnl != NULL)
            mch_memmove(pnl + 1, last, plen + 1);
-       ((char_u **)gap->ga_data)[gap->ga_len] = pnl;
-       ++gap->ga_len;
+       ((char_u **)gap->ga_data)[gap->ga_len++] = pnl;
+       ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl;
     }
 
     if (cmdline != NULL)
index 5e2a52c1a6c331ff0fcd4b861ba7a82c47547878..88dd5d6d976f5f8a1c120a91aa35be78226a2cf4 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2866,
 /**/
     2865,
 /**/