mirror of
https://github.com/neovim/neovim.git
synced 2026-02-21 09:50:19 +10:00
fix(window): crash closing only non-float if autocmds :tabonly (#37218)
Problem: null pointer member access when closing the only non-float in the
current tab page if autocommands after closing all floats also close all other
tab pages. (making it the last window)
Solution: check last_window again after closing the floats.
Also reduce the scope of "wp"; it would be bugprone to use it before it's later
reassigned to the rv of win_free_mem if freed by Buf/WinLeave.
(cherry picked from commit c14de47f1a)
This commit is contained in:
@@ -98,6 +98,8 @@ typedef enum {
|
||||
WEE_TRIGGER_LEAVE_AUTOCMDS = 0x10,
|
||||
} wee_flags_T;
|
||||
|
||||
static const char e_cannot_close_last_window[]
|
||||
= N_("E444: Cannot close last window");
|
||||
static const char e_cannot_split_window_when_closing_buffer[]
|
||||
= N_("E1159: Cannot split a window when closing the buffer");
|
||||
|
||||
@@ -2683,7 +2685,7 @@ int win_close(win_T *win, bool free_buf, bool force)
|
||||
const bool had_diffmode = win->w_p_diff;
|
||||
|
||||
if (last_window(win)) {
|
||||
emsg(_("E444: Cannot close last window"));
|
||||
emsg(_(e_cannot_close_last_window));
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
@@ -2712,6 +2714,11 @@ int win_close(win_T *win, bool free_buf, bool force)
|
||||
if (!win_valid_any_tab(win)) {
|
||||
return FAIL; // window already closed by autocommands
|
||||
}
|
||||
// Autocommands may have closed all other tabpages; check again.
|
||||
if (last_window(win)) {
|
||||
emsg(_(e_cannot_close_last_window));
|
||||
return FAIL;
|
||||
}
|
||||
} else {
|
||||
emsg(e_floatonly);
|
||||
return FAIL;
|
||||
@@ -2735,7 +2742,6 @@ int win_close(win_T *win, bool free_buf, bool force)
|
||||
clear_snapshot(curtab, SNAP_HELP_IDX);
|
||||
}
|
||||
|
||||
win_T *wp;
|
||||
bool other_buffer = false;
|
||||
|
||||
if (win == curwin) {
|
||||
@@ -2743,7 +2749,8 @@ int win_close(win_T *win, bool free_buf, bool force)
|
||||
|
||||
// Guess which window is going to be the new current window.
|
||||
// This may change because of the autocommands (sigh).
|
||||
wp = win->w_floating ? win_float_find_altwin(win, NULL) : frame2win(win_altframe(win, NULL));
|
||||
win_T *wp = win->w_floating ? win_float_find_altwin(win, NULL)
|
||||
: frame2win(win_altframe(win, NULL));
|
||||
|
||||
// Be careful: If autocommands delete the window or cause this window
|
||||
// to be the last one left, return now.
|
||||
@@ -2838,7 +2845,7 @@ int win_close(win_T *win, bool free_buf, bool force)
|
||||
// Free the memory used for the window and get the window that received
|
||||
// the screen space.
|
||||
int dir;
|
||||
wp = win_free_mem(win, &dir, NULL);
|
||||
win_T *wp = win_free_mem(win, &dir, NULL);
|
||||
|
||||
if (help_window) {
|
||||
// Closing the help window moves the cursor back to the current window
|
||||
|
||||
@@ -710,6 +710,11 @@ describe('float window', function()
|
||||
api.nvim_set_current_win(old_win)
|
||||
eq('Vim:E444: Cannot close last window',
|
||||
pcall_err(api.nvim_win_close, old_win, false))
|
||||
-- Start with many tab pages, but make autocommands from closing floats leave us with just
|
||||
-- one (where we're now the last window).
|
||||
command('tabnew | autocmd WinClosed * ++once tabonly')
|
||||
api.nvim_open_win(0, false, float_opts)
|
||||
eq('Vim:E444: Cannot close last window', pcall_err(api.nvim_win_close, 0, true))
|
||||
end)
|
||||
it('if called from floating window', function()
|
||||
eq('Vim:E444: Cannot close last window',
|
||||
|
||||
Reference in New Issue
Block a user