From 34c54eb6cbda5dbc14376c8b1c62ad11d4852793 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 25 Nov 2020 19:15:19 +0100 Subject: [PATCH] patch 8.2.2051: Vim9: crash when aborting a user function call 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 | 23 +++++++++++++++++++++++ src/version.c | 2 ++ src/vim9execute.c | 22 +++++++++++++++++----- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 80d564e3e..8cb6ecf33 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -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 diff --git a/src/version.c b/src/version.c index 216f5c989..4c54fe580 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2051, /**/ 2050, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 323f2926b..ab2cf385f 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -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; -- 2.40.0