changeset 30437:d77a900f6094 v9.0.0554

patch 9.0.0554: using freed memory when command follows lambda Commit: https://github.com/vim/vim/commit/f8addf1ca1d8c7801f6dded2341b7084d2b93e5e Author: Bram Moolenaar <Bram@vim.org> Date: Fri Sep 23 12:44:25 2022 +0100 patch 9.0.0554: using freed memory when command follows lambda Problem: Using freed memory when command follows lambda. Solution: Don't free what is still in use. (closes https://github.com/vim/vim/issues/11201)
author Bram Moolenaar <Bram@vim.org>
date Fri, 23 Sep 2022 13:45:06 +0200
parents 93abb8acf842
children 69be14b8733c
files src/eval.c src/testdir/test_vim9_func.vim src/version.c src/vim9expr.c
diffstat 4 files changed, 37 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -382,23 +382,34 @@ clear_evalarg(evalarg_T *evalarg, exarg_
 {
     if (evalarg != NULL)
     {
-	if (evalarg->eval_tofree != NULL)
+	garray_T *etga = &evalarg->eval_tofree_ga;
+
+	if (evalarg->eval_tofree != NULL || evalarg->eval_using_cmdline)
 	{
 	    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.
+		// ":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;
+
+		if (evalarg->eval_using_cmdline && etga->ga_len > 0)
+		{
+		    // "nextcmd" points into the last line in eval_tofree_ga,
+		    // need to keep it around.
+		    --etga->ga_len;
+		    *eap->cmdlinep = ((char_u **)etga->ga_data)[etga->ga_len];
+		}
+		else
+		    *eap->cmdlinep = evalarg->eval_tofree;
 	    }
 	    else
 		vim_free(evalarg->eval_tofree);
 	    evalarg->eval_tofree = NULL;
 	}
 
-	ga_clear_strings(&evalarg->eval_tofree_ga);
+	ga_clear_strings(etga);
 	VIM_CLEAR(evalarg->eval_tofree_lambda);
     }
 }
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -1515,6 +1515,20 @@ def Test_lambda_invalid_block()
   v9.CheckDefAndScriptFailure(lines, 'E488: Trailing characters: | echo')
 enddef
 
+def Test_lambda_with_following_cmd()
+  var lines =<< trim END
+      set ts=2
+      var Lambda = () => {
+          set ts=4
+        } | set ts=3
+      assert_equal(3, &ts)
+      Lambda()
+      assert_equal(4, &ts)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+  set ts=8
+enddef
+
 def Test_pass_legacy_lambda_to_def_func()
   var lines =<< trim END
       vim9script
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    554,
+/**/
     553,
 /**/
     552,
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -522,10 +522,12 @@ compile_load(
 	    {
 		type = lvar.lv_type;
 		idx = lvar.lv_idx;
-		outer_loop_depth = lvar.lv_loop_depth;
-		outer_loop_idx = lvar.lv_loop_idx;
 		if (lvar.lv_from_outer != 0)
+		{
 		    gen_load_outer = lvar.lv_from_outer;
+		    outer_loop_depth = lvar.lv_loop_depth;
+		    outer_loop_idx = lvar.lv_loop_idx;
+		}
 		else
 		    gen_load = TRUE;
 	    }
@@ -1096,6 +1098,7 @@ compile_lambda(char_u **arg, cctx_T *cct
 
 	*arg = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum]
 									 + off;
+	evalarg.eval_using_cmdline = FALSE;
     }
 
     clear_evalarg(&evalarg, NULL);