mirror of
https://github.com/neovim/neovim.git
synced 2025-10-12 12:56:04 +00:00
fix(float): crash from nasty :fclose autocmds (#36137)
Problem: :fclose may crash Nvim if autocommands close floats prematurely.
Alternatively, :fclose may call win_close for windows not in curtab if
autocommands change curtab or move windows between tab pages via
nvim_win_set_config (may not crash, but is wrong).
Solution: check win_valid before calling win_close.
(cherry picked from commit 3ccba4cdff
)
Backports #36134.
This commit is contained in:
@@ -290,7 +290,8 @@ void win_float_remove(bool bang, int count)
|
|||||||
qsort(float_win_arr.items, float_win_arr.size, sizeof(win_T *), float_zindex_cmp);
|
qsort(float_win_arr.items, float_win_arr.size, sizeof(win_T *), float_zindex_cmp);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < float_win_arr.size; i++) {
|
for (size_t i = 0; i < float_win_arr.size; i++) {
|
||||||
if (win_close(float_win_arr.items[i], false, false) == FAIL) {
|
win_T *wp = float_win_arr.items[i];
|
||||||
|
if (win_valid(wp) && win_close(wp, false, false) == FAIL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!bang) {
|
if (!bang) {
|
||||||
|
@@ -1122,6 +1122,55 @@ describe('float window', function()
|
|||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it(':fclose does not crash from nasty autocommands', function()
|
||||||
|
local w1 = api.nvim_open_win(0, false, { relative = 'editor', row = 0, col = 0, width = 5, height = 5, zindex = 6 })
|
||||||
|
local w2 = api.nvim_open_win(0, false, { relative = 'editor', row = 0, col = 0, width = 5, height = 5, zindex = 5 })
|
||||||
|
local w3 = api.nvim_open_win(0, false, { relative = 'editor', row = 0, col = 0, width = 5, height = 5, zindex = 4 })
|
||||||
|
local w4 = api.nvim_open_win(0, true, { relative = 'editor', row = 0, col = 0, width = 5, height = 5, zindex = 3 })
|
||||||
|
exec_lua(function()
|
||||||
|
vim.api.nvim_create_autocmd('WinClosed', {
|
||||||
|
once = true,
|
||||||
|
callback = function()
|
||||||
|
vim.api.nvim_win_close(w2, true)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
-- We close just the first three floats with highest zindex, so w4 remains open.
|
||||||
|
-- (despite w2 being closed early by the autocommand rather than directly by :fclose)
|
||||||
|
command('3fclose')
|
||||||
|
eq(false, api.nvim_win_is_valid(w1))
|
||||||
|
eq(false, api.nvim_win_is_valid(w2))
|
||||||
|
eq(false, api.nvim_win_is_valid(w3))
|
||||||
|
eq(true, api.nvim_win_is_valid(w4))
|
||||||
|
|
||||||
|
-- Try switching tab pages and moving windows between tab pages via nvim_win_set_config.
|
||||||
|
-- Simplest if :fclose skips windows in non-current tabpages.
|
||||||
|
local w5 = api.nvim_open_win(0, false, { relative = 'editor', row = 0, col = 0, width = 5, height = 5, zindex = 2 })
|
||||||
|
command('autocmd WinEnter * ++once tabnew')
|
||||||
|
eq(w4, api.nvim_get_current_win())
|
||||||
|
local tp1 = api.nvim_get_current_tabpage()
|
||||||
|
command('fclose!')
|
||||||
|
eq(false, api.nvim_win_is_valid(w4))
|
||||||
|
eq(true, api.nvim_win_is_valid(w5))
|
||||||
|
neq(tp1, api.nvim_get_current_tabpage())
|
||||||
|
|
||||||
|
local w_tp2 = api.nvim_get_current_win()
|
||||||
|
api.nvim_set_current_tabpage(tp1)
|
||||||
|
local w6 = api.nvim_open_win(0, false, { relative = 'editor', row = 0, col = 0, width = 5, height = 5, zindex = 1 })
|
||||||
|
exec_lua(function()
|
||||||
|
vim.api.nvim_create_autocmd('WinClosed', {
|
||||||
|
once = true,
|
||||||
|
callback = function()
|
||||||
|
vim.api.nvim_win_set_config(w6, { win = w_tp2, split = 'below' })
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
command('fclose!')
|
||||||
|
eq(false, api.nvim_win_is_valid(w5))
|
||||||
|
eq(true, api.nvim_win_is_valid(w6))
|
||||||
|
neq(tp1, api.nvim_win_get_tabpage(w6))
|
||||||
|
end)
|
||||||
|
|
||||||
local function with_ext_multigrid(multigrid)
|
local function with_ext_multigrid(multigrid)
|
||||||
local screen, attrs
|
local screen, attrs
|
||||||
before_each(function()
|
before_each(function()
|
||||||
|
Reference in New Issue
Block a user