summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-12-10 21:46:09 +0000
committerBram Moolenaar <Bram@vim.org>2021-12-10 21:46:09 +0000
commit205f29c3e9b895dbaa4f738046da455a93c3812a (patch)
tree8c9dd97ca940b88014f7e890f4aabb75cf93fef1
parent9537e37b1124a0584e5f2af10756baca78bc73a1 (diff)
downloadvim-git-205f29c3e9b895dbaa4f738046da455a93c3812a.tar.gz
patch 8.2.3779: using freed memory when defining a user command recursivelyv8.2.3779
Problem: Using freed memory when defining a user command from a user command. Solution: Do not use the command pointer after executing the command. (closes #9318)
-rw-r--r--src/testdir/test_usercommands.vim19
-rw-r--r--src/usercmd.c11
-rw-r--r--src/version.c2
3 files changed, 30 insertions, 2 deletions
diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim
index d560f4948..b57ed0aa3 100644
--- a/src/testdir/test_usercommands.vim
+++ b/src/testdir/test_usercommands.vim
@@ -704,5 +704,24 @@ def Test_count_with_quotes()
delcommand GetCount
enddef
+func DefCmd(name)
+ if len(a:name) > 30
+ return
+ endif
+ exe 'command ' .. a:name .. ' call DefCmd("' .. a:name .. 'x")'
+ echo a:name
+ exe a:name
+endfunc
+
+func Test_recursive_define()
+ call DefCmd('Command')
+
+ let name = 'Command'
+ while len(name) < 30
+ exe 'delcommand ' .. name
+ let name ..= 'x'
+ endwhile
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/usercmd.c b/src/usercmd.c
index 16fbb0db3..0cc0034f3 100644
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -1670,7 +1670,8 @@ do_ucmd(exarg_T *eap)
size_t split_len = 0;
char_u *split_buf = NULL;
ucmd_T *cmd;
- sctx_T save_current_sctx = current_sctx;
+ sctx_T save_current_sctx;
+ int restore_current_sctx = FALSE;
if (eap->cmdidx == CMD_USER)
cmd = USER_CMD(eap->useridx);
@@ -1771,14 +1772,20 @@ do_ucmd(exarg_T *eap)
if ((cmd->uc_argt & EX_KEEPSCRIPT) == 0)
{
+ restore_current_sctx = TRUE;
+ save_current_sctx = current_sctx;
current_sctx.sc_version = cmd->uc_script_ctx.sc_version;
#ifdef FEAT_EVAL
current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid;
#endif
}
+
(void)do_cmdline(buf, eap->getline, eap->cookie,
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
- if ((cmd->uc_argt & EX_KEEPSCRIPT) == 0)
+
+ // Careful: Do not use "cmd" here, it may have become invalid if a user
+ // command was added.
+ if (restore_current_sctx)
current_sctx = save_current_sctx;
vim_free(buf);
vim_free(split_buf);
diff --git a/src/version.c b/src/version.c
index 265229f12..25669afa1 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3779,
+/**/
3778,
/**/
3777,