Commit: patch 9.2.0708: Leaks in do_autocmd in error case

1 view
Skip to first unread message

Christian Brabandt

unread,
4:00 PM (7 hours ago) 4:00 PM
to vim...@googlegroups.com
patch 9.2.0708: Leaks in do_autocmd in error case

Commit: https://github.com/vim/vim/commit/98f5171ef6ba9aa6aea7223e833115e544199bd4
Author: Christian Brabandt <c...@256bit.org>
Date: Tue Jun 23 19:44:48 2026 +0000

patch 9.2.0708: Leaks in do_autocmd in error case

Problem: Leak in do_autocmd in error case (Cheng)
Solution: goto err_exit in the error case and clean up, make the double
++once an actual error

closes: #20606

Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/autocmd.c b/src/autocmd.c
index 2e7f1efd0..98014cf03 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -1025,7 +1025,10 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
{
if (once)
+ {
semsg(_(e_duplicate_argument_str), "++once");
+ goto err_exit;
+ }
once = TRUE;
cmd = skipwhite(cmd + 6);
}
@@ -1036,7 +1039,7 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
if (nested)
{
semsg(_(e_duplicate_argument_str), "++nested");
- return;
+ goto err_exit;
}
nested = TRUE;
cmd = skipwhite(cmd + 8);
@@ -1051,12 +1054,12 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
// be removed and "nested" accepted as the start of the
// command.
emsg(_(e_invalid_command_nested_did_you_mean_plusplus_nested));
- return;
+ goto err_exit;
}
if (nested)
{
semsg(_(e_duplicate_argument_str), "nested");
- return;
+ goto err_exit;
}
nested = TRUE;
cmd = skipwhite(cmd + 6);
@@ -1075,7 +1078,7 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)

cmd = expand_sfile(cmd);
if (cmd == NULL) // some error
- return;
+ goto err_exit;
cmd_need_free = TRUE;
}
}
@@ -1111,6 +1114,7 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
break;
}

+err_exit:
if (cmd_need_free)
vim_free(cmd);
vim_free(tofree);
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 54116a585..4828b3ea9 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -3208,8 +3208,41 @@ func Test_autocmd_once()
close

call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
+ call assert_false(exists('#WinNew'))
endfunc

+func Test_autocmd_dup_arg()
+ " Duplicate ++once / ++nested, or the legacy "nested" used twice, must
+ " error out *and* not create the autocommand. Using an environment
+ " variable in the pattern also exercises the error-exit path that frees
+ " the expanded pattern (checked by the address/leak sanitizers).
+ augroup XdupTest
+ au!
+ augroup END
+ let $XAUTODIR = 'Xfoo'
+
+ " New behavior: duplicate ++once now aborts, the autocmd is not added
+ call assert_fails('au XdupTest WinNew $XAUTODIR/* ++once ++once echo bad', 'E983:')
+ call assert_false(exists('#XdupTest#WinNew'))
+
+ call assert_fails('au XdupTest WinNew $XAUTODIR/* ++nested ++nested echo bad', 'E983:')
+ call assert_false(exists('#XdupTest#WinNew'))
+
+ call assert_fails('au XdupTest WinNew $XAUTODIR/* nested nested echo bad', 'E983:')
+ call assert_false(exists('#XdupTest#WinNew'))
+
+ " "nested" without "++" is rejected in Vim9 script (also frees the pattern)
+ call assert_fails('vim9cmd au XdupTest WinNew $XAUTODIR/* nested echo bad', 'E1078:')
+ call assert_false(exists('#XdupTest#WinNew'))
+
+ augroup XdupTest
+ au!
+ augroup END
+ augroup! XdupTest
+ let $XAUTODIR = ''
+endfunc
+
+
func Test_autocmd_bufreadpre()
new
let b:bufreadpre = 1
diff --git a/src/version.c b/src/version.c
index ff0e68e1c..753a36d2d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -759,6 +759,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 708,
/**/
707,
/**/
Reply all
Reply to author
Forward
0 new messages