]> granicus.if.org Git - vim/commitdiff
patch 9.0.0554: using freed memory when command follows lambda v9.0.0554
authorBram Moolenaar <Bram@vim.org>
Fri, 23 Sep 2022 11:44:25 +0000 (12:44 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 23 Sep 2022 11:44:25 +0000 (12:44 +0100)
Problem:    Using freed memory when command follows lambda.
Solution:   Don't free what is still in use. (closes #11201)

src/eval.c
src/testdir/test_vim9_func.vim
src/version.c
src/vim9expr.c

index 77f0d7fb3cbd35eb65489cdbe3b9366fbe9e2a38..bdf03896a450190053473d250e53a55313fbf460 100644 (file)
@@ -382,23 +382,34 @@ clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
 {
     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);
     }
 }
index 4d5ff14b144b02015481800abecec0cf0a9735f8..dc6b10439fd832c0ce5862815944217adcce91a8 100644 (file)
@@ -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
index 57d8259603a27a9e2cf91c12cdfde13e3def098d..23f822c172f9eecc43ac7433dee5d18ec1811b92 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    554,
 /**/
     553,
 /**/
index 0e44b7652f4ed2b5124461a18ae4acc7e46f3cea..8be8f6b9145c88ebc7ef9ec3e833514def60a110 100644 (file)
@@ -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 *cctx)
 
        *arg = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum]
                                                                         + off;
+       evalarg.eval_using_cmdline = FALSE;
     }
 
     clear_evalarg(&evalarg, NULL);