From: Christian Brabandt Date: Tue, 23 Jun 2026 19:44:48 +0000 (+0000) Subject: patch 9.2.0708: Leaks in do_autocmd in error case X-Git-Tag: v9.2.0708^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=98f5171ef6ba9aa6aea7223e833115e544199bd4;p=thirdparty%2Fvim.git 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 --- diff --git a/src/autocmd.c b/src/autocmd.c index 2e7f1efd01..98014cf037 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 54116a5857..4828b3ea9e 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 ff0e68e1c7..753a36d2de 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, /**/