vim-patch:9.2.0708: Leaks in do_autocmd in error case (#40386)

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: vim/vim#20606

98f5171ef6

Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2026-06-24 08:23:32 +08:00
committed by GitHub
parent c7f83f90ed
commit 19f64a2680
2 changed files with 39 additions and 5 deletions

View File

@@ -763,7 +763,7 @@ void do_autocmd(exarg_T *eap, char *arg_in, int forceit)
char *arg = arg_in;
char *envpat = NULL;
char *cmd;
bool need_free = false;
bool cmd_need_free = false;
bool nested = false;
bool once = false;
int group;
@@ -832,7 +832,7 @@ void do_autocmd(exarg_T *eap, char *arg_in, int forceit)
}
if (invalid_flags) {
return;
goto err_exit;
}
// Find the start of the commands.
@@ -840,9 +840,9 @@ void do_autocmd(exarg_T *eap, char *arg_in, int forceit)
if (*cmd != NUL) {
cmd = expand_sfile(cmd);
if (cmd == NULL) { // some error
return;
goto err_exit;
}
need_free = true;
cmd_need_free = true;
}
}
@@ -879,7 +879,8 @@ void do_autocmd(exarg_T *eap, char *arg_in, int forceit)
}
}
if (need_free) {
err_exit:
if (cmd_need_free) {
xfree(cmd);
}
xfree(envpat);

View File

@@ -3126,8 +3126,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