Patch 9.0.0225
Problem:    Using freed memory with multiple line breaks in expression.
Solution:   Free eval_tofree later.
Files:      src/eval.c, src/proto/eval.pro, src/userfunc.c,
            src/testdir/test_vim9_script.vim


*** ../vim-9.0.0224/src/eval.c  2022-08-06 18:12:02.962750601 +0100
--- src/eval.c  2022-08-18 13:12:26.963563448 +0100
***************
*** 354,359 ****
--- 354,416 ----
  }
  
  /*
+  * Initialize "evalarg" for use.
+  */
+     void
+ init_evalarg(evalarg_T *evalarg)
+ {
+     CLEAR_POINTER(evalarg);
+     ga_init2(&evalarg->eval_tofree_ga, sizeof(char_u *), 20);
+ }
+ 
+ /*
+  * If "evalarg->eval_tofree" is not NULL free it later.
+  * Caller is expected to overwrite "evalarg->eval_tofree" next.
+  */
+     static void
+ free_eval_tofree_later(evalarg_T *evalarg)
+ {
+     if (evalarg->eval_tofree != NULL)
+     {
+       if (ga_grow(&evalarg->eval_tofree_ga, 1) == OK)
+           ((char_u **)evalarg->eval_tofree_ga.ga_data)
+               [evalarg->eval_tofree_ga.ga_len++]
+               = evalarg->eval_tofree;
+       else
+           vim_free(evalarg->eval_tofree);
+     }
+ }
+ 
+ /*
+  * After using "evalarg" filled from "eap": free the memory.
+  */
+     void
+ clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
+ {
+     if (evalarg != NULL)
+     {
+       if (evalarg->eval_tofree != NULL)
+       {
+           if (eap != NULL)
+           {
+               // We may need to keep the original command line, e.g. for
+               // ":let" it has the variable names.  But we may also need the
+               // new one, "nextcmd" points into it.  Keep both.
+               vim_free(eap->cmdline_tofree);
+               eap->cmdline_tofree = *eap->cmdlinep;
+               *eap->cmdlinep = evalarg->eval_tofree;
+           }
+           else
+               vim_free(evalarg->eval_tofree);
+           evalarg->eval_tofree = NULL;
+       }
+ 
+       ga_clear_strings(&evalarg->eval_tofree_ga);
+       VIM_CLEAR(evalarg->eval_tofree_lambda);
+     }
+ }
+ 
+ /*
   * Skip over an expression at "*pp".
   * Return FAIL for an error, OK otherwise.
   */
***************
*** 435,442 ****
                // Do not free the first line, the caller can still use it.
                *((char_u **)gap->ga_data) = NULL;
                // Do not free the last line, "arg" points into it, free it
!               // later.
!               vim_free(evalarg->eval_tofree);
                evalarg->eval_tofree =
                                    ((char_u **)gap->ga_data)[gap->ga_len - 1];
                ((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL;
--- 492,499 ----
                // Do not free the first line, the caller can still use it.
                *((char_u **)gap->ga_data) = NULL;
                // Do not free the last line, "arg" points into it, free it
!               // later.  Also free "eval_tofree" later if needed.
!               free_eval_tofree_later(evalarg);
                evalarg->eval_tofree =
                                    ((char_u **)gap->ga_data)[gap->ga_len - 1];
                ((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL;
***************
*** 2274,2280 ****
      }
      else if (evalarg->eval_cookie != NULL)
      {
!       vim_free(evalarg->eval_tofree);
        evalarg->eval_tofree = line;
      }
  
--- 2331,2337 ----
      }
      else if (evalarg->eval_cookie != NULL)
      {
!       free_eval_tofree_later(evalarg);
        evalarg->eval_tofree = line;
      }
  
***************
*** 2302,2346 ****
  }
  
  /*
-  * Initialize "evalarg" for use.
-  */
-     void
- init_evalarg(evalarg_T *evalarg)
- {
-     CLEAR_POINTER(evalarg);
-     ga_init2(&evalarg->eval_tofree_ga, sizeof(char_u *), 20);
- }
- 
- /*
-  * After using "evalarg" filled from "eap": free the memory.
-  */
-     void
- clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
- {
-     if (evalarg != NULL)
-     {
-       if (evalarg->eval_tofree != NULL)
-       {
-           if (eap != NULL)
-           {
-               // We may need to keep the original command line, e.g. for
-               // ":let" it has the variable names.  But we may also need the
-               // new one, "nextcmd" points into it.  Keep both.
-               vim_free(eap->cmdline_tofree);
-               eap->cmdline_tofree = *eap->cmdlinep;
-               *eap->cmdlinep = evalarg->eval_tofree;
-           }
-           else
-               vim_free(evalarg->eval_tofree);
-           evalarg->eval_tofree = NULL;
-       }
- 
-       ga_clear_strings(&evalarg->eval_tofree_ga);
-       VIM_CLEAR(evalarg->eval_tofree_lambda);
-     }
- }
- 
- /*
   * The "evaluate" argument: When FALSE, the argument is only parsed but not
   * executed.  The function may return OK, but the rettv will be of type
   * VAR_UNKNOWN.  The function still returns FAIL for a syntax error.
--- 2359,2364 ----
*** ../vim-9.0.0224/src/proto/eval.pro  2022-06-27 23:15:02.000000000 +0100
--- src/proto/eval.pro  2022-08-18 12:58:31.293122808 +0100
***************
*** 9,14 ****
--- 9,16 ----
  int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T 
*rettv);
  int eval_expr_to_bool(typval_T *expr, int *error);
  char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
+ void init_evalarg(evalarg_T *evalarg);
+ void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
  int skip_expr(char_u **pp, evalarg_T *evalarg);
  int skip_expr_concatenate(char_u **arg, char_u **start, char_u **end, 
evalarg_T *evalarg);
  char_u *typval2string(typval_T *tv, int convert);
***************
*** 34,41 ****
  char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext);
  char_u *eval_next_line(char_u *arg, evalarg_T *evalarg);
  char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg);
- void init_evalarg(evalarg_T *evalarg);
- void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
  int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg);
  int eval0_retarg(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T 
*evalarg, char_u **retarg);
  int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
--- 36,41 ----
*** ../vim-9.0.0224/src/userfunc.c      2022-08-16 16:09:53.599527502 +0100
--- src/userfunc.c      2022-08-18 12:55:47.669699534 +0100
***************
*** 1372,1378 ****
      char_u    *start, *end;
      int               *old_eval_lavars = eval_lavars_used;
      int               eval_lavars = FALSE;
-     char_u    *tofree1 = NULL;
      char_u    *tofree2 = NULL;
      int               equal_arrow = **arg == '(';
      int               white_error = FALSE;
--- 1372,1377 ----
***************
*** 1457,1468 ****
      ret = skip_expr_concatenate(arg, &start, &end, evalarg);
      if (ret == FAIL)
        goto errret;
-     if (evalarg != NULL)
-     {
-       // avoid that the expression gets freed when another line break follows
-       tofree1 = evalarg->eval_tofree;
-       evalarg->eval_tofree = NULL;
-     }
  
      if (!equal_arrow)
      {
--- 1456,1461 ----
***************
*** 1585,1594 ****
  
  theend:
      eval_lavars_used = old_eval_lavars;
-     if (evalarg != NULL && evalarg->eval_tofree == NULL)
-       evalarg->eval_tofree = tofree1;
-     else
-       vim_free(tofree1);
      vim_free(tofree2);
      if (types_optional)
        ga_clear_strings(&argtypes);
--- 1578,1583 ----
***************
*** 1607,1616 ****
      }
      vim_free(fp);
      vim_free(pt);
-     if (evalarg != NULL && evalarg->eval_tofree == NULL)
-       evalarg->eval_tofree = tofree1;
-     else
-       vim_free(tofree1);
      vim_free(tofree2);
      eval_lavars_used = old_eval_lavars;
      return FAIL;
--- 1596,1601 ----
*** ../vim-9.0.0224/src/testdir/test_vim9_script.vim    2022-08-17 
15:55:47.864544955 +0100
--- src/testdir/test_vim9_script.vim    2022-08-18 13:02:29.912353502 +0100
***************
*** 1560,1565 ****
--- 1560,1578 ----
    v9.CheckScriptFailure(lines, 'E1073:')
  enddef
  
+ def Test_lambda_split()
+   # this was using freed memory, because of the split expression
+   var lines =<< trim END
+       vim9script
+       try
+       0
+       0->(0
+         ->a.0(
+         ->u
+   END
+   v9.CheckScriptFailure(lines, 'E1050:')
+ enddef
+ 
  def Test_fixed_size_list()
    # will be allocated as one piece of memory, check that changes work
    var l = [1, 2, 3, 4]
*** ../vim-9.0.0224/src/version.c       2022-08-17 15:55:47.864544955 +0100
--- src/version.c       2022-08-18 12:45:12.312721251 +0100
***************
*** 733,734 ****
--- 733,736 ----
  {   /* Add new patch number below this line */
+ /**/
+     225,
  /**/

-- 
    f y cn rd ths thn y cn hv grt jb n cmptr prgrmmng

 /// Bram Moolenaar -- b...@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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220818122937.C986B1C0B17%40moolenaar.net.

Raspunde prin e-mail lui