Patch 8.2.3560
Problem:    Using freed memory with lambda.
Solution:   Do not free lines early, keep them until the expression is
            finished.
Files:      src/eval.c, src/proto/eval.pro, src/userfunc.c, src/vim9compile.c,
            src/structs.h, src/globals.h, src/testdir/test_vim9_func.vim


*** ../vim-8.2.3559/src/eval.c  2021-09-09 11:11:58.875602021 +0100
--- src/eval.c  2021-10-23 13:17:23.263893881 +0100
***************
*** 143,149 ****
      void
  fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip)
  {
!     CLEAR_FIELD(*evalarg);
      evalarg->eval_flags = skip ? 0 : EVAL_EVALUATE;
      if (eap != NULL)
      {
--- 143,149 ----
      void
  fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip)
  {
!     init_evalarg(evalarg);
      evalarg->eval_flags = skip ? 0 : EVAL_EVALUATE;
      if (eap != NULL)
      {
***************
*** 2137,2144 ****
  
      // Advanced to the next line, "arg" no longer points into the previous
      // line.
!     VIM_CLEAR(evalarg->eval_tofree_cmdline);
! 
      return skipwhite(line);
  }
  
--- 2137,2143 ----
  
      // Advanced to the next line, "arg" no longer points into the previous
      // line.
!     evalarg->eval_using_cmdline = FALSE;
      return skipwhite(line);
  }
  
***************
*** 2160,2165 ****
--- 2159,2174 ----
  }
  
  /*
+  * 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
***************
*** 2183,2189 ****
            evalarg->eval_tofree = NULL;
        }
  
!       VIM_CLEAR(evalarg->eval_tofree_cmdline);
        VIM_CLEAR(evalarg->eval_tofree_lambda);
      }
  }
--- 2192,2198 ----
            evalarg->eval_tofree = NULL;
        }
  
!       ga_clear_strings(&evalarg->eval_tofree_ga);
        VIM_CLEAR(evalarg->eval_tofree_lambda);
      }
  }
***************
*** 2298,2304 ****
  
        if (evalarg == NULL)
        {
!           CLEAR_FIELD(local_evalarg);
            evalarg_used = &local_evalarg;
        }
        orig_flags = evalarg_used->eval_flags;
--- 2307,2313 ----
  
        if (evalarg == NULL)
        {
!           init_evalarg(&local_evalarg);
            evalarg_used = &local_evalarg;
        }
        orig_flags = evalarg_used->eval_flags;
***************
*** 2455,2461 ****
  
        if (evalarg == NULL)
        {
!           CLEAR_FIELD(local_evalarg);
            evalarg_used = &local_evalarg;
        }
        orig_flags = evalarg_used->eval_flags;
--- 2464,2470 ----
  
        if (evalarg == NULL)
        {
!           init_evalarg(&local_evalarg);
            evalarg_used = &local_evalarg;
        }
        orig_flags = evalarg_used->eval_flags;
***************
*** 2581,2587 ****
  
        if (evalarg == NULL)
        {
!           CLEAR_FIELD(local_evalarg);
            evalarg_used = &local_evalarg;
        }
        orig_flags = evalarg_used->eval_flags;
--- 2590,2596 ----
  
        if (evalarg == NULL)
        {
!           init_evalarg(&local_evalarg);
            evalarg_used = &local_evalarg;
        }
        orig_flags = evalarg_used->eval_flags;
*** ../vim-8.2.3559/src/proto/eval.pro  2021-08-11 20:49:19.626869328 +0100
--- src/proto/eval.pro  2021-10-23 12:54:35.361834638 +0100
***************
*** 34,39 ****
--- 34,40 ----
  void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
  int pattern_match(char_u *pat, char_u *text, int ic);
  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 eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
*** ../vim-8.2.3559/src/userfunc.c      2021-10-22 22:17:49.142382407 +0100
--- src/userfunc.c      2021-10-23 13:19:06.697410154 +0100
***************
*** 1177,1188 ****
  
      if (cmdline != NULL)
      {
        // Something comes after the "}".
        *arg = eap.nextcmd;
  
        // "arg" points into cmdline, need to keep the line and free it later.
!       vim_free(evalarg->eval_tofree_cmdline);
!       evalarg->eval_tofree_cmdline = cmdline;
      }
      else
        *arg = (char_u *)"";
--- 1177,1193 ----
  
      if (cmdline != NULL)
      {
+       garray_T *tfgap = &evalarg->eval_tofree_ga;
+ 
        // Something comes after the "}".
        *arg = eap.nextcmd;
  
        // "arg" points into cmdline, need to keep the line and free it later.
!       if (ga_grow(tfgap, 1) == OK)
!       {
!           ((char_u **)(tfgap->ga_data))[tfgap->ga_len++] = cmdline;
!           evalarg->eval_using_cmdline = TRUE;
!       }
      }
      else
        *arg = (char_u *)"";
***************
*** 4867,4873 ****
        return;
      }
  
!     CLEAR_FIELD(evalarg);
      evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
  
      if (eap->skip)
--- 4872,4878 ----
        return;
      }
  
!     init_evalarg(&evalarg);
      evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
  
      if (eap->skip)
*** ../vim-8.2.3559/src/vim9compile.c   2021-10-13 15:28:22.759581625 +0100
--- src/vim9compile.c   2021-10-23 13:19:42.153928462 +0100
***************
*** 3702,3708 ****
      ufunc_T   *ufunc;
      evalarg_T evalarg;
  
!     CLEAR_FIELD(evalarg);
      evalarg.eval_flags = EVAL_EVALUATE;
      evalarg.eval_cctx = cctx;
  
--- 3702,3708 ----
      ufunc_T   *ufunc;
      evalarg_T evalarg;
  
!     init_evalarg(&evalarg);
      evalarg.eval_flags = EVAL_EVALUATE;
      evalarg.eval_cctx = cctx;
  
***************
*** 3733,3743 ****
        compile_def_function(ufunc, FALSE, CT_NONE, cctx);
  #endif
  
!     // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg"
!     // points into it.  Point to the original line to avoid a dangling 
pointer.
!     if (evalarg.eval_tofree_cmdline != NULL)
      {
!       size_t  off = *arg - evalarg.eval_tofree_cmdline;
  
        *arg = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum]
                                                                         + off;
--- 3733,3745 ----
        compile_def_function(ufunc, FALSE, CT_NONE, cctx);
  #endif
  
!     // The last entry in evalarg.eval_tofree_ga is a copy of the last line and
!     // "*arg" may point into it.  Point into the original line to avoid a
!     // dangling pointer.
!     if (evalarg.eval_using_cmdline)
      {
!       garray_T    *gap = &evalarg.eval_tofree_ga;
!       size_t      off = *arg - ((char_u **)gap->ga_data)[gap->ga_len - 1];
  
        *arg = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum]
                                                                         + off;
***************
*** 4201,4209 ****
  {
      evalarg_T evalarg;
  
!     CLEAR_FIELD(evalarg);
      evalarg.eval_cctx = cctx;
      skip_expr(arg, &evalarg);
  }
  
  /*
--- 4203,4212 ----
  {
      evalarg_T evalarg;
  
!     init_evalarg(&evalarg);
      evalarg.eval_cctx = cctx;
      skip_expr(arg, &evalarg);
+     clear_evalarg(&evalarg, NULL);
  }
  
  /*
*** ../vim-8.2.3559/src/structs.h       2021-10-17 14:13:04.832665843 +0100
--- src/structs.h       2021-10-23 13:20:22.318514796 +0100
***************
*** 1906,1913 ****
      // pointer to the last line obtained with getsourceline()
      char_u    *eval_tofree;
  
!     // pointer to the last line of an inline function
!     char_u    *eval_tofree_cmdline;
  
      // pointer to the lines concatenated for a lambda.
      char_u    *eval_tofree_lambda;
--- 1906,1916 ----
      // pointer to the last line obtained with getsourceline()
      char_u    *eval_tofree;
  
!     // array with lines of an inline function
!     garray_T  eval_tofree_ga;
! 
!     // set when "arg" points into the last entry of "eval_tofree_ga"
!     int               eval_using_cmdline;
  
      // pointer to the lines concatenated for a lambda.
      char_u    *eval_tofree_lambda;
*** ../vim-8.2.3559/src/globals.h       2021-09-17 19:45:26.066836056 +0100
--- src/globals.h       2021-10-23 13:31:16.835131030 +0100
***************
*** 1867,1874 ****
  // Passed to an eval() function to enable evaluation.
  EXTERN evalarg_T EVALARG_EVALUATE
  # ifdef DO_INIT
!       = {EVAL_EVALUATE, 0, NULL, NULL, NULL, NULL, {0, 0, 0, 0, NULL},
!                                         {0, 0, 0, 0, NULL}, NULL, NULL, NULL}
  # endif
        ;
  #endif
--- 1867,1874 ----
  // Passed to an eval() function to enable evaluation.
  EXTERN evalarg_T EVALARG_EVALUATE
  # ifdef DO_INIT
!       = {EVAL_EVALUATE, 0, NULL, NULL, NULL, NULL, GA_EMPTY, GA_EMPTY, NULL,
!                        {0, 0, (int)sizeof(char_u *), 20, NULL}, 0, NULL}
  # endif
        ;
  #endif
*** ../vim-8.2.3559/src/testdir/test_vim9_func.vim      2021-09-13 
17:25:50.456525311 +0100
--- src/testdir/test_vim9_func.vim      2021-10-23 13:25:58.451395993 +0100
***************
*** 1133,1138 ****
--- 1133,1158 ----
    CheckScriptSuccess(lines)
  enddef
  
+ def Test_lambda_in_reduce_line_break()
+   # this was using freed memory
+   var lines =<< trim END
+       vim9script
+       const result: dict<number> =
+           ['Bob', 'Sam', 'Cat', 'Bob', 'Cat', 'Cat']
+           ->reduce((acc, val) => {
+               if has_key(acc, val)
+                   acc[val] += 1
+                   return acc
+               else
+                   acc[val] = 1
+                   return acc
+               endif
+           }, {})
+       assert_equal({Bob: 2, Sam: 1, Cat: 3}, result)
+   END
+   CheckScriptSuccess(lines)
+ enddef
+ 
  " Default arg and varargs
  def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
    var res = one .. ',' .. two
*** ../vim-8.2.3559/src/version.c       2021-10-23 12:34:18.413019131 +0100
--- src/version.c       2021-10-23 13:25:36.539078901 +0100
***************
*** 759,760 ****
--- 759,762 ----
  {   /* Add new patch number below this line */
+ /**/
+     3560,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
231. You sprinkle Carpet Fresh on the rugs and put your vacuum cleaner
     in the front doorway permanently so it always looks like you are
     actually attempting to do something about that mess that has amassed
     since you discovered the Internet.

 /// Bram Moolenaar -- [email protected] -- 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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20211023123305.BC530C80053%40moolenaar.net.

Raspunde prin e-mail lui