]> granicus.if.org Git - vim/commitdiff
patch 8.2.2051: Vim9: crash when aborting a user function call v8.2.2051
authorBram Moolenaar <Bram@vim.org>
Wed, 25 Nov 2020 18:15:19 +0000 (19:15 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 25 Nov 2020 18:15:19 +0000 (19:15 +0100)
Problem:    Vim9: crash when aborting a user function call.
Solution:   Do not use the return value when aboring. (closes #7372)

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

index 80d564e3e247429fbc34ccce3519a0e6ae3725bc..8cb6ecf33f6a598ece9cb8a78a5832db71a9f59b 100644 (file)
@@ -1468,6 +1468,29 @@ def Test_nested_closure_fails()
   CheckScriptFailure(lines, 'E1012:')
 enddef
 
+def Test_failure_in_called_function()
+  # this was using the frame index as the return value
+  var lines =<< trim END
+      vim9script
+      au TerminalWinOpen * eval [][0]
+      def PopupTerm(a: any)
+        # make sure typvals on stack are string
+        ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join()
+        FireEvent()
+      enddef
+      def FireEvent()
+          do TerminalWinOpen
+      enddef
+      # use try/catch to make eval fail
+      try
+          call PopupTerm(0)
+      catch
+      endtry
+      au! TerminalWinOpen
+  END
+  CheckScriptSuccess(lines)
+enddef
+
 def Test_nested_lambda()
   var lines =<< trim END
     vim9script
index 216f5c9895f2e1ad354870d4d72716481216b3ce..4c54fe580663da2c621047938ee8c53247dec0f9 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2051,
 /**/
     2050,
 /**/
index 323f2926b50503eec0b548e3c7c80143777f3b01..ab2cf385f98ac34c77e1aeba2b7fe157ecc6076a 100644 (file)
@@ -467,6 +467,7 @@ funcstack_check_refcount(funcstack_T *funcstack)
 func_return(ectx_T *ectx)
 {
     int                idx;
+    int                ret_idx;
     dfunc_T    *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                          + ectx->ec_dfunc_idx;
     int                argcount = ufunc_argcount(dfunc->df_ufunc);
@@ -490,6 +491,12 @@ func_return(ectx_T *ectx)
                                        idx < ectx->ec_stack.ga_len - 1; ++idx)
        clear_tv(STACK_TV(idx));
 
+    // The return value should be on top of the stack.  However, when aborting
+    // it may not be there and ec_frame_idx is the top of the stack.
+    ret_idx = ectx->ec_stack.ga_len - 1;
+    if (ret_idx == ectx->ec_frame_idx + 4)
+       ret_idx = 0;
+
     // Restore the previous frame.
     ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number;
     ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number;
@@ -501,11 +508,16 @@ func_return(ectx_T *ectx)
     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
     ectx->ec_instr = dfunc->df_instr;
 
-    // Reset the stack to the position before the call, move the return value
-    // to the top of the stack.
-    idx = ectx->ec_stack.ga_len - 1;
-    ectx->ec_stack.ga_len = top + 1;
-    *STACK_TV_BOT(-1) = *STACK_TV(idx);
+    if (ret_idx > 0)
+    {
+       // Reset the stack to the position before the call, with a spot for the
+       // return value, moved there from above the frame.
+       ectx->ec_stack.ga_len = top + 1;
+       *STACK_TV_BOT(-1) = *STACK_TV(ret_idx);
+    }
+    else
+       // Reset the stack to the position before the call.
+       ectx->ec_stack.ga_len = top;
 
     funcdepth_decrement();
     return OK;