Patch 8.2.1161
Problem:    Vim9: using freed memory.
Solution:   Put pointer back in evalarg instead of freeing it.
Files:      src/userfunc.c, src/vim9compile.c, src/eval.c, src/proto/eval.pro,
            src/structs.h


*** ../vim-8.2.1160/src/userfunc.c      2020-07-08 19:35:17.767686401 +0200
--- src/userfunc.c      2020-07-08 21:33:04.828727980 +0200
***************
*** 389,396 ****
      partial_T   *pt = NULL;
      int               varargs;
      int               ret;
!     char_u    *start;
!     char_u    *s, *e;
      int               *old_eval_lavars = eval_lavars_used;
      int               eval_lavars = FALSE;
      char_u    *tofree = NULL;
--- 389,396 ----
      partial_T   *pt = NULL;
      int               varargs;
      int               ret;
!     char_u    *s;
!     char_u    *start, *end;
      int               *old_eval_lavars = eval_lavars_used;
      int               eval_lavars = FALSE;
      char_u    *tofree = NULL;
***************
*** 399,408 ****
      ga_init(&newlines);
  
      // First, check if this is a lambda expression. "->" must exist.
!     start = skipwhite(*arg + 1);
!     ret = get_function_args(&start, '-', NULL, NULL, NULL, NULL, TRUE,
                                                                   NULL, NULL);
!     if (ret == FAIL || *start != '>')
        return NOTDONE;
  
      // Parse the arguments again.
--- 399,408 ----
      ga_init(&newlines);
  
      // First, check if this is a lambda expression. "->" must exist.
!     s = skipwhite(*arg + 1);
!     ret = get_function_args(&s, '-', NULL, NULL, NULL, NULL, TRUE,
                                                                   NULL, NULL);
!     if (ret == FAIL || *s != '>')
        return NOTDONE;
  
      // Parse the arguments again.
***************
*** 423,430 ****
  
      // Get the start and the end of the expression.
      *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
!     s = *arg;
!     ret = skip_expr_concatenate(&s, arg, evalarg);
      if (ret == FAIL)
        goto errret;
      if (evalarg != NULL)
--- 423,430 ----
  
      // Get the start and the end of the expression.
      *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
!     start = *arg;
!     ret = skip_expr_concatenate(arg, &start, &end, evalarg);
      if (ret == FAIL)
        goto errret;
      if (evalarg != NULL)
***************
*** 434,440 ****
        evalarg->eval_tofree = NULL;
      }
  
-     e = *arg;
      *arg = skipwhite_and_linebreak(*arg, evalarg);
      if (**arg != '}')
      {
--- 434,439 ----
***************
*** 463,475 ****
            goto errret;
  
        // Add "return " before the expression.
!       len = 7 + (int)(e - s) + 1;
        p = alloc(len);
        if (p == NULL)
            goto errret;
        ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
        STRCPY(p, "return ");
!       vim_strncpy(p + 7, s, e - s);
        if (strstr((char *)p + 7, "a:") == NULL)
            // No a: variables are used for sure.
            flags |= FC_NOARGS;
--- 462,474 ----
            goto errret;
  
        // Add "return " before the expression.
!       len = 7 + (int)(end - start) + 1;
        p = alloc(len);
        if (p == NULL)
            goto errret;
        ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
        STRCPY(p, "return ");
!       vim_strncpy(p + 7, start, end - start);
        if (strstr((char *)p + 7, "a:") == NULL)
            // No a: variables are used for sure.
            flags |= FC_NOARGS;
***************
*** 509,515 ****
      }
  
      eval_lavars_used = old_eval_lavars;
!     vim_free(tofree);
      return OK;
  
  errret:
--- 508,517 ----
      }
  
      eval_lavars_used = old_eval_lavars;
!     if (evalarg->eval_tofree == NULL)
!       evalarg->eval_tofree = tofree;
!     else
!       vim_free(tofree);
      return OK;
  
  errret:
***************
*** 517,523 ****
      ga_clear_strings(&newlines);
      vim_free(fp);
      vim_free(pt);
!     vim_free(tofree);
      eval_lavars_used = old_eval_lavars;
      return FAIL;
  }
--- 519,528 ----
      ga_clear_strings(&newlines);
      vim_free(fp);
      vim_free(pt);
!     if (evalarg->eval_tofree == NULL)
!       evalarg->eval_tofree = tofree;
!     else
!       vim_free(tofree);
      eval_lavars_used = old_eval_lavars;
      return FAIL;
  }
*** ../vim-8.2.1160/src/vim9compile.c   2020-07-08 19:35:17.767686401 +0200
--- src/vim9compile.c   2020-07-08 21:08:44.792351587 +0200
***************
*** 3113,3118 ****
--- 3113,3120 ----
      // Compile it into instructions.
      compile_def_function(ufunc, TRUE, cctx);
  
+     clear_evalarg(&evalarg, NULL);
+ 
      if (ufunc->uf_def_status == UF_COMPILED)
        return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
      return FAIL;
*** ../vim-8.2.1160/src/eval.c  2020-07-08 17:36:17.738105000 +0200
--- src/eval.c  2020-07-08 21:55:37.633123734 +0200
***************
*** 379,388 ****
   * Skip over an expression at "*pp".
   * If in Vim9 script and line breaks are encountered, the lines are
   * concatenated.  "evalarg->eval_tofree" will be set accordingly.
   * Return FAIL for an error, OK otherwise.
   */
      int
! skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
  {
      typval_T  rettv;
      int               res;
--- 379,395 ----
   * Skip over an expression at "*pp".
   * If in Vim9 script and line breaks are encountered, the lines are
   * concatenated.  "evalarg->eval_tofree" will be set accordingly.
+  * "arg" is advanced to just after the expression.
+  * "start" is set to the start of the expression, "end" to just after the end.
+  * Also when the expression is copied to allocated memory.
   * Return FAIL for an error, OK otherwise.
   */
      int
! skip_expr_concatenate(
!       char_u      **arg,
!       char_u      **start,
!       char_u      **end,
!       evalarg_T   *evalarg)
  {
      typval_T  rettv;
      int               res;
***************
*** 398,409 ****
        if (ga_grow(gap, 1) == OK)
            ++gap->ga_len;
      }
  
      // Don't evaluate the expression.
      if (evalarg != NULL)
        evalarg->eval_flags &= ~EVAL_EVALUATE;
!     *end = skipwhite(*end);
!     res = eval1(end, &rettv, evalarg);
      if (evalarg != NULL)
        evalarg->eval_flags = save_flags;
  
--- 405,418 ----
        if (ga_grow(gap, 1) == OK)
            ++gap->ga_len;
      }
+     *start = *arg;
  
      // Don't evaluate the expression.
      if (evalarg != NULL)
        evalarg->eval_flags &= ~EVAL_EVALUATE;
!     *arg = skipwhite(*arg);
!     res = eval1(arg, &rettv, evalarg);
!     *end = *arg;
      if (evalarg != NULL)
        evalarg->eval_flags = save_flags;
  
***************
*** 419,425 ****
        else
        {
            char_u          *p;
!           size_t          endoff = STRLEN(*end);
  
            // Line breaks encountered, concatenate all the lines.
            *((char_u **)gap->ga_data) = *start;
--- 428,434 ----
        else
        {
            char_u          *p;
!           size_t          endoff = STRLEN(*arg);
  
            // Line breaks encountered, concatenate all the lines.
            *((char_u **)gap->ga_data) = *start;
***************
*** 428,434 ****
--- 437,450 ----
            // free the lines only when using getsourceline()
            if (evalarg->eval_cookie != NULL)
            {
+               // 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;
                ga_clear_strings(gap);
            }
            else
***************
*** 437,444 ****
            if (p == NULL)
                return FAIL;
            *start = p;
!           vim_free(evalarg->eval_tofree);
!           evalarg->eval_tofree = p;
            // Compute "end" relative to the end.
            *end = *start + STRLEN(*start) - endoff;
        }
--- 453,460 ----
            if (p == NULL)
                return FAIL;
            *start = p;
!           vim_free(evalarg->eval_tofree_lambda);
!           evalarg->eval_tofree_lambda = p;
            // Compute "end" relative to the end.
            *end = *start + STRLEN(*start) - endoff;
        }
***************
*** 1936,1942 ****
        ((char_u **)gap->ga_data)[gap->ga_len] = line;
        ++gap->ga_len;
      }
!     else
      {
        vim_free(evalarg->eval_tofree);
        evalarg->eval_tofree = line;
--- 1952,1958 ----
        ((char_u **)gap->ga_data)[gap->ga_len] = line;
        ++gap->ga_len;
      }
!     else if (evalarg->eval_cookie != NULL)
      {
        vim_free(evalarg->eval_tofree);
        evalarg->eval_tofree = line;
***************
*** 1962,1986 ****
  }
  
  /*
!  * After using "evalarg" filled from "eap" free the memory.
   */
      void
  clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
  {
!     if (evalarg != NULL && 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;
      }
  }
  
--- 1978,2008 ----
  }
  
  /*
!  * 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;
        }
! 
!       vim_free(evalarg->eval_tofree_lambda);
!       evalarg->eval_tofree_lambda = NULL;
      }
  }
  
*** ../vim-8.2.1160/src/proto/eval.pro  2020-07-04 14:14:55.633073475 +0200
--- src/proto/eval.pro  2020-07-08 21:35:36.700364651 +0200
***************
*** 10,16 ****
  int eval_expr_to_bool(typval_T *expr, int *error);
  char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
  int skip_expr(char_u **pp);
! int skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg);
  char_u *eval_to_string(char_u *arg, int convert);
  char_u *eval_to_string_safe(char_u *arg, int use_sandbox);
  varnumber_T eval_to_number(char_u *expr);
--- 10,16 ----
  int eval_expr_to_bool(typval_T *expr, int *error);
  char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
  int skip_expr(char_u **pp);
! int skip_expr_concatenate(char_u **arg, char_u **start, char_u **end, 
evalarg_T *evalarg);
  char_u *eval_to_string(char_u *arg, int convert);
  char_u *eval_to_string_safe(char_u *arg, int use_sandbox);
  varnumber_T eval_to_number(char_u *expr);
*** ../vim-8.2.1160/src/structs.h       2020-07-08 17:36:17.734105013 +0200
--- src/structs.h       2020-07-08 21:54:48.377262186 +0200
***************
*** 1773,1780 ****
      // "eval_ga.ga_data" is a list of pointers to lines.
      garray_T  eval_ga;
  
!     // pointer to the line obtained with getsourceline()
      char_u    *eval_tofree;
  } evalarg_T;
  
  // Flags for expression evaluation.
--- 1773,1783 ----
      // "eval_ga.ga_data" is a list of pointers to lines.
      garray_T  eval_ga;
  
!     // pointer to the last line obtained with getsourceline()
      char_u    *eval_tofree;
+ 
+     // pointer to the lines concatenated for a lambda.
+     char_u    *eval_tofree_lambda;
  } evalarg_T;
  
  // Flags for expression evaluation.
*** ../vim-8.2.1160/src/version.c       2020-07-08 19:35:17.767686401 +0200
--- src/version.c       2020-07-08 21:07:20.828519290 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1161,
  /**/

-- 
Normal people believe that if it ain't broke, don't fix it.  Engineers believe
that if it ain't broke, it doesn't have enough features yet.
                                (Scott Adams - The Dilbert principle)

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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/202007082002.068K2J8I1434848%40masaka.moolenaar.net.

Raspunde prin e-mail lui