summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2023-04-17 19:23:45 +0100
committerBram Moolenaar <Bram@vim.org>2023-04-17 19:23:45 +0100
commit42994bf678f46dc9ca66e49f512261da8864fff6 (patch)
tree3daa7460a610b439456f8bfabcd72b6b88efe8db
parentfc8a601c3251c0388a88c1235b18c529385f7196 (diff)
downloadvim-git-42994bf678f46dc9ca66e49f512261da8864fff6.tar.gz
patch 9.0.1462: recursively calling :defer function if it does :qav9.0.1462
Problem: Recursively calling :defer function if it does :qa. Solution: Clear the defer entry before calling the function. (closes #12266)
-rw-r--r--src/testdir/test_user_func.vim4
-rw-r--r--src/userfunc.c21
-rw-r--r--src/version.c2
3 files changed, 20 insertions, 7 deletions
diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim
index ade259cff..8715a0b78 100644
--- a/src/testdir/test_user_func.vim
+++ b/src/testdir/test_user_func.vim
@@ -656,6 +656,7 @@ func Test_defer_quitall()
vim9script
func DeferLevelTwo()
call writefile(['text'], 'XQuitallTwo', 'D')
+ call writefile(['quit'], 'XQuitallThree', 'a')
qa!
endfunc
@@ -671,6 +672,9 @@ func Test_defer_quitall()
call assert_equal(0, v:shell_error)
call assert_false(filereadable('XQuitallOne'))
call assert_false(filereadable('XQuitallTwo'))
+ call assert_equal(['quit'], readfile('XQuitallThree'))
+
+ call delete('XQuitallThree')
endfunc
func Test_defer_quitall_in_expr_func()
diff --git a/src/userfunc.c b/src/userfunc.c
index 25f76ecb0..a506d72c8 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -6096,20 +6096,27 @@ handle_defer_one(funccall_T *funccal)
for (idx = funccal->fc_defer.ga_len - 1; idx >= 0; --idx)
{
- funcexe_T funcexe;
- typval_T rettv;
defer_T *dr = ((defer_T *)funccal->fc_defer.ga_data) + idx;
- int i;
+ if (dr->dr_name == NULL)
+ // already being called, can happen if function does ":qa"
+ continue;
+
+ funcexe_T funcexe;
CLEAR_FIELD(funcexe);
funcexe.fe_evaluate = TRUE;
+ typval_T rettv;
rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
- call_func(dr->dr_name, -1, &rettv,
- dr->dr_argcount, dr->dr_argvars, &funcexe);
+
+ char_u *name = dr->dr_name;
+ dr->dr_name = NULL;
+
+ call_func(name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe);
+
clear_tv(&rettv);
- vim_free(dr->dr_name);
- for (i = dr->dr_argcount - 1; i >= 0; --i)
+ vim_free(name);
+ for (int i = dr->dr_argcount - 1; i >= 0; --i)
clear_tv(&dr->dr_argvars[i]);
}
ga_clear(&funccal->fc_defer);
diff --git a/src/version.c b/src/version.c
index 053fe7827..6dc7e3431 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1462,
+/**/
1461,
/**/
1460,