commit 4fadc21e3854b9c49c670044b0f84ad8a2f63903
parent 0bef1c88f3621e185b3e35f361a418b8b36ee010
Author: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Date: Tue, 22 Jul 2025 01:28:45 +0100
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.
Diffstat:
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/src/nvim/window.c b/src/nvim/window.c
@@ -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) {
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
@@ -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')