fix(window): disallow closing autocmd window in other tabpage

Problem: unlike win_close, win_close_othertab could be used to close the
autocommand window from a different tabpage. This causes aucmd_restbuf to close
the wrong window, potentially causing a crash.

Solution: disallow closing it. Also replace a deprecated use of exc_exec in the
test file.

Fixes #21409.
This commit is contained in:
Sean Dewar
2025-07-22 01:28:45 +01:00
parent 0bef1c88f3
commit 4fadc21e38
2 changed files with 26 additions and 2 deletions

View File

@@ -2992,6 +2992,10 @@ bool win_close_othertab(win_T *win, int free_buf, tabpage_T *tp, bool force)
|| (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) {
return false; // window is already being closed
}
if (is_aucmd_win(win)) {
emsg(_(e_autocmd_close));
return false;
}
// Check if closing this window would leave only floating windows.
if (tp->tp_firstwin == win && win->w_next && win->w_next->w_floating) {

View File

@@ -8,6 +8,7 @@ local dedent = t.dedent
local eq = t.eq
local neq = t.neq
local eval = n.eval
local exec = n.exec
local feed = n.feed
local clear = n.clear
local matches = t.matches
@@ -16,7 +17,6 @@ local pcall_err = t.pcall_err
local fn = n.fn
local expect = n.expect
local command = n.command
local exc_exec = n.exc_exec
local exec_lua = n.exec_lua
local retry = t.retry
local source = n.source
@@ -150,7 +150,10 @@ describe('autocmd', function()
})
command('autocmd BufLeave * bwipeout yy')
eq('Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy', exc_exec('edit yy'))
eq(
'Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy',
pcall_err(command, 'edit yy')
)
expect([[
start of test file xx
@@ -428,6 +431,23 @@ describe('autocmd', function()
)
end)
it('cannot close `aucmd_win` in non-current tabpage', function()
exec([[
file Xa
tabnew Xb
call setline(1, 'foo')
tabfirst
autocmd BufWriteCmd Xb tablast | bwipe! Xa
]])
eq(
'BufWriteCmd Autocommands for "Xb": Vim(bwipeout):E813: Cannot close autocmd window',
pcall_err(command, 'wall')
)
-- Sanity check: :bwipe failing to close all windows into Xa should keep it loaded.
-- (So there's no risk of it being left unloaded inside a window)
eq(1, eval('bufloaded("Xa")'))
end)
describe('closing last non-floating window in tab from `aucmd_win`', function()
before_each(function()
command('edit Xa.txt')