]> granicus.if.org Git - vim/commitdiff
patch 8.2.2386: Vim9: crash when using ":silent! put" v8.2.2386
authorBram Moolenaar <Bram@vim.org>
Thu, 21 Jan 2021 18:41:16 +0000 (19:41 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 21 Jan 2021 18:41:16 +0000 (19:41 +0100)
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)

src/testdir/test_vim9_func.vim
src/version.c
src/vim9execute.c

index 1ea8ac9fc9ecac1bef40fe93e7c7f13fb7914f59..da0a0e6432a88a7e52f2952eb7688abbf96f3878 100644 (file)
@@ -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
index faa2777434fe38694558c35b1fb0a308a1294f29..a73927045cf1277f7d211dba90f89b9cc2feb511 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2386,
 /**/
     2385,
 /**/
index 59a0982b3f59c4f865390fc92ed59a385c209e88..b533617fc732f80919059b287404e8b651af5bea 100644 (file)
@@ -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.