changeset 23644:03acf9c49f07 v8.2.2364

patch 8.2.2364: Vim9: line break in lambda accesses freed memory Commit: https://github.com/vim/vim/commit/f898f7c68dc06def1a5ae02ce82a52a82af37cc4 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jan 16 18:09:52 2021 +0100 patch 8.2.2364: Vim9: line break in lambda accesses freed memory Problem: Vim9: line break in lambda accesses freed memory. Solution: Make a copy of the return type. (closes https://github.com/vim/vim/issues/7664)
author Bram Moolenaar <Bram@vim.org>
date Sat, 16 Jan 2021 18:15:04 +0100
parents df929ddb388b
children 541984a4d2e7
files src/testdir/test_vim9_func.vim src/userfunc.c src/version.c
diffstat 3 files changed, 30 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -1811,6 +1811,18 @@ enddef
 
 def Test_line_continuation_in_lambda()
   Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A'])
+
+  var lines =<< trim END
+      vim9script
+      var res = [{n: 1, m: 2, s: 'xxx'}]
+                ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s',
+                    v.n,
+                    v.m,
+                    substitute(v.s, '.*', 'yyy', '')
+                    ))
+      assert_equal(['1:2:yyy'], res)
+  END
+  CheckScriptSuccess(lines)
 enddef
 
 def Test_list_lambda()
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -539,7 +539,8 @@ get_lambda_tv(
     char_u	*start, *end;
     int		*old_eval_lavars = eval_lavars_used;
     int		eval_lavars = FALSE;
-    char_u	*tofree = NULL;
+    char_u	*tofree1 = NULL;
+    char_u	*tofree2 = NULL;
     int		equal_arrow = **arg == '(';
     int		white_error = FALSE;
 
@@ -582,6 +583,13 @@ get_lambda_tv(
     }
     *arg = s;
 
+    // Skipping over linebreaks may make "ret_type" invalid, make a copy.
+    if (ret_type != NULL)
+    {
+	ret_type = vim_strsave(ret_type);
+	tofree2 = ret_type;
+    }
+
     // Set up a flag for checking local variables and arguments.
     if (evaluate)
 	eval_lavars_used = &eval_lavars;
@@ -605,7 +613,7 @@ get_lambda_tv(
     if (evalarg != NULL)
     {
 	// avoid that the expression gets freed when another line break follows
-	tofree = evalarg->eval_tofree;
+	tofree1 = evalarg->eval_tofree;
 	evalarg->eval_tofree = NULL;
     }
 
@@ -700,9 +708,10 @@ get_lambda_tv(
 
     eval_lavars_used = old_eval_lavars;
     if (evalarg != NULL && evalarg->eval_tofree == NULL)
-	evalarg->eval_tofree = tofree;
+	evalarg->eval_tofree = tofree1;
     else
-	vim_free(tofree);
+	vim_free(tofree1);
+    vim_free(tofree2);
     if (types_optional)
 	ga_clear_strings(&argtypes);
     return OK;
@@ -715,9 +724,10 @@ errret:
     vim_free(fp);
     vim_free(pt);
     if (evalarg != NULL && evalarg->eval_tofree == NULL)
-	evalarg->eval_tofree = tofree;
+	evalarg->eval_tofree = tofree1;
     else
-	vim_free(tofree);
+	vim_free(tofree1);
+    vim_free(tofree2);
     eval_lavars_used = old_eval_lavars;
     return FAIL;
 }
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2364,
+/**/
     2363,
 /**/
     2362,