changeset 23689:e7f5931b46ca v8.2.2386

patch 8.2.2386: Vim9: crash when using ":silent! put" Commit: https://github.com/vim/vim/commit/f904133e1a5ea84a124d3ece12b1f0a7392f1ca7 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jan 21 19:41:16 2021 +0100 patch 8.2.2386: Vim9: crash when using ":silent! put" Problem: Vim9: crash when using ":silent! put". Solution: When ignoring an error for ":silent!" rewind the stack and skip ahead to restoring the cmdmod. (closes #7717)
author Bram Moolenaar <Bram@vim.org>
date Thu, 21 Jan 2021 19:45:06 +0100
parents 915625fad609
children 90a28e0d556f
files src/testdir/test_vim9_func.vim src/version.c src/vim9execute.c
diffstat 3 files changed, 37 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -2184,6 +2184,24 @@ def Test_dict_member_with_silent()
   CheckScriptSuccess(lines)
 enddef
 
+def Test_skip_cmds_with_silent()
+  var lines =<< trim END
+      vim9script
+
+      def Func(b: bool)
+        Crash()
+      enddef
+
+      def Crash()
+        sil! :/not found/d _
+        sil! :/not found/put _
+      enddef
+
+      Func(true)
+  END
+  CheckScriptSuccess(lines)
+enddef
+
 def Test_opfunc()
   nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@
   def g:Opfunc(_: any): string
--- 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 */
 /**/
+    2386,
+/**/
     2385,
 /**/
     2384,
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1124,6 +1124,7 @@ call_def_function(
     msglist_T	*private_msg_list = NULL;
     cmdmod_T	save_cmdmod;
     int		restore_cmdmod = FALSE;
+    int		restore_cmdmod_stacklen = 0;
     int		save_emsg_silent_def = emsg_silent_def;
     int		save_did_emsg_def = did_emsg_def;
     int		trylevel_at_start = trylevel;
@@ -3398,6 +3399,7 @@ call_def_function(
 	    case ISN_CMDMOD:
 		save_cmdmod = cmdmod;
 		restore_cmdmod = TRUE;
+		restore_cmdmod_stacklen = ectx.ec_stack.ga_len;
 		cmdmod = *iptr->isn_arg.cmdmod.cf_cmdmod;
 		apply_cmdmod(&cmdmod);
 		break;
@@ -3523,7 +3525,22 @@ on_error:
 	// when calling the function.
 	if (did_emsg_cumul + did_emsg == did_emsg_before
 					   && emsg_silent && did_emsg_def == 0)
+	{
+	    // If a sequence of instructions causes an error while ":silent!"
+	    // was used, restore the stack length and jump ahead to restoring
+	    // the cmdmod.
+	    if (restore_cmdmod)
+	    {
+		while (ectx.ec_stack.ga_len > restore_cmdmod_stacklen)
+		{
+		    --ectx.ec_stack.ga_len;
+		    clear_tv(STACK_TV_BOT(0));
+		}
+		while (ectx.ec_instr[ectx.ec_iidx].isn_type != ISN_CMDMOD_REV)
+		    ++ectx.ec_iidx;
+	    }
 	    continue;
+	}
 on_fatal_error:
 	// Jump here for an error that messes up the stack.
 	// If we are not inside a try-catch started here, abort execution.