To: vim_dev@googlegroups.com Subject: Patch 8.2.2866 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2866 Problem: Vim9: memory leak when using inline function. Solution: Remember what strings to free. Files: src/userfunc.c, src/structs.h, src/eval.c *** ../vim-8.2.2865/src/userfunc.c 2021-05-18 13:40:30.332459267 +0200 --- src/userfunc.c 2021-05-18 15:01:35.309863928 +0200 *************** *** 976,981 **** --- 976,982 ---- { 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,1032 **** { char_u *p = skipwhite(((char_u **)newlines.ga_data)[idx]); ! if (ga_grow(gap, 1) == FAIL) goto erret; // Going to concatenate the lines after parsing. For an empty or --- 1027,1033 ---- { char_u *p = skipwhite(((char_u **)newlines.ga_data)[idx]); ! 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,1048 **** 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; } ! if (ga_grow(gap, 1) == FAIL) goto erret; if (cmdline != NULL) // more is following after the "}", which was skipped --- 1040,1049 ---- 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; ! ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl; } ! 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,1061 **** 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; } if (cmdline != NULL) --- 1055,1062 ---- 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; ! ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl; } if (cmdline != NULL) *** ../vim-8.2.2865/src/structs.h 2021-05-07 17:55:51.963584417 +0200 --- src/structs.h 2021-05-18 14:56:12.823346503 +0200 *************** *** 1881,1887 **** --- 1881,1889 ---- // 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; *** ../vim-8.2.2865/src/eval.c 2021-05-15 20:06:52.881646140 +0200 --- src/eval.c 2021-05-18 15:00:10.306255151 +0200 *************** *** 416,421 **** --- 416,422 ---- 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,432 **** --- 428,434 ---- // leave room for "start" if (ga_grow(gap, 1) == OK) ++gap->ga_len; + ga_init2(freegap, sizeof(char_u *), 10); } *start = *arg; *************** *** 444,450 **** { if (evalarg->eval_ga.ga_len == 1) { ! // just one line, no need to concatenate ga_clear(gap); gap->ga_itemsize = 0; } --- 446,452 ---- { if (evalarg->eval_ga.ga_len == 1) { ! // just the one line, no need to concatenate ga_clear(gap); gap->ga_itemsize = 0; } *************** *** 471,477 **** --- 473,485 ---- 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,3536 **** /* * nested expression: (expression). ! * lambda: (arg) => expr */ case '(': ret = NOTDONE; if (in_vim9script()) --- 3538,3544 ---- /* * nested expression: (expression). ! * or lambda: (arg) => expr */ case '(': ret = NOTDONE; if (in_vim9script()) *** ../vim-8.2.2865/src/version.c 2021-05-18 13:40:30.332459267 +0200 --- src/version.c 2021-05-18 15:06:41.852451201 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2866, /**/ -- Eight Megabytes And Continually Swapping. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///