# HG changeset patch # User Bram Moolenaar # Date 1663933506 -7200 # Node ID d77a900f6094d30738450e749d9fc99de2155779 # Parent 93abb8acf842999b161c1f10913d405b585c1e1f patch 9.0.0554: using freed memory when command follows lambda Commit: https://github.com/vim/vim/commit/f8addf1ca1d8c7801f6dded2341b7084d2b93e5e Author: Bram Moolenaar 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) diff --git a/src/eval.c b/src/eval.c --- 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); } } diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim9expr.c b/src/vim9expr.c --- 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);