vim-patch:9.0.0550: crash when closing a tabpage and buffer is NULL

Problem:    Crash when closing a tabpage and buffer is NULL.
Solution:   Adjust how autocommands are triggered when closing a window.
            (closes vim/vim#11198, closes vim/vim#11197)
62de54b48d
This commit is contained in:
zeertzjq
2022-09-23 07:14:32 +08:00
parent 0760379b41
commit c28f00b101
3 changed files with 29 additions and 18 deletions

View File

@@ -4696,7 +4696,6 @@ void tabpage_close(int forceit)
void tabpage_close_other(tabpage_T *tp, int forceit) void tabpage_close_other(tabpage_T *tp, int forceit)
{ {
int done = 0; int done = 0;
int h = tabline_height();
char prev_idx[NUMBUFLEN]; char prev_idx[NUMBUFLEN];
// Limit to 1000 windows, autocommands may add a window while we close // Limit to 1000 windows, autocommands may add a window while we close
@@ -4712,11 +4711,6 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
break; break;
} }
} }
redraw_tabline = true;
if (h != tabline_height()) {
win_new_screen_rows();
}
} }
/// ":only". /// ":only".

View File

@@ -447,6 +447,26 @@ func Test_WinClosed_throws_with_tabs()
augroup! test-WinClosed augroup! test-WinClosed
endfunc endfunc
" This used to trigger WinClosed twice for the same window, and the window's
" buffer was NULL in the second autocommand.
func Test_WinClosed_switch_tab()
edit Xa
split Xb
split Xc
tab split
new
augroup test-WinClosed
autocmd WinClosed * tabprev | bwipe!
augroup END
close
" Check that the tabline has been fully removed
call assert_equal([1, 1], win_screenpos(0))
autocmd! test-WinClosed
augroup! test-WinClosed
%bwipe!
endfunc
func s:AddAnAutocmd() func s:AddAnAutocmd()
augroup vimBarTest augroup vimBarTest
au BufReadCmd * echo 'hello' au BufReadCmd * echo 'hello'

View File

@@ -2439,7 +2439,6 @@ void curwin_init(void)
void close_windows(buf_T *buf, bool keep_curwin) void close_windows(buf_T *buf, bool keep_curwin)
{ {
tabpage_T *tp, *nexttp; tabpage_T *tp, *nexttp;
int h = tabline_height();
RedrawingDisabled++; RedrawingDisabled++;
@@ -2480,11 +2479,6 @@ void close_windows(buf_T *buf, bool keep_curwin)
} }
RedrawingDisabled--; RedrawingDisabled--;
redraw_tabline = true;
if (h != tabline_height()) {
win_new_screen_rows();
}
} }
/// Check that the specified window is the last one. /// Check that the specified window is the last one.
@@ -2575,7 +2569,6 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
// Don't trigger autocommands yet, they may use wrong values, so do // Don't trigger autocommands yet, they may use wrong values, so do
// that below. // that below.
goto_tabpage_tp(alt_tabpage(), false, true); goto_tabpage_tp(alt_tabpage(), false, true);
redraw_tabline = true;
// save index for tabclosed event // save index for tabclosed event
char_u prev_idx[NUMBUFLEN]; char_u prev_idx[NUMBUFLEN];
@@ -2584,12 +2577,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
// Safety check: Autocommands may have closed the window when jumping // Safety check: Autocommands may have closed the window when jumping
// to the other tab page. // to the other tab page.
if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win) { if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win) {
int h = tabline_height();
win_close_othertab(win, free_buf, prev_curtab); win_close_othertab(win, free_buf, prev_curtab);
if (h != tabline_height()) {
win_new_screen_rows();
}
} }
entering_window(curwin); entering_window(curwin);
@@ -2793,7 +2781,10 @@ int win_close(win_T *win, bool free_buf, bool force)
if (curtab != prev_curtab && win_valid_any_tab(win) if (curtab != prev_curtab && win_valid_any_tab(win)
&& win->w_buffer == NULL) { && win->w_buffer == NULL) {
// Need to close the window anyway, since the buffer is NULL. // Need to close the window anyway, since the buffer is NULL.
// Don't trigger autocmds with a NULL buffer.
block_autocmds();
win_close_othertab(win, false, prev_curtab); win_close_othertab(win, false, prev_curtab);
unblock_autocmds();
return FAIL; return FAIL;
} }
@@ -2990,6 +2981,8 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
vim_snprintf(prev_idx, NUMBUFLEN, "%i", tabpage_index(tp)); vim_snprintf(prev_idx, NUMBUFLEN, "%i", tabpage_index(tp));
} }
int h = tabline_height();
if (tp == first_tabpage) { if (tp == first_tabpage) {
first_tabpage = tp->tp_next; first_tabpage = tp->tp_next;
} else { } else {
@@ -3004,6 +2997,10 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
ptp->tp_next = tp->tp_next; ptp->tp_next = tp->tp_next;
} }
free_tp = true; free_tp = true;
redraw_tabline = true;
if (h != tabline_height()) {
win_new_screen_rows();
}
if (has_event(EVENT_TABCLOSED)) { if (has_event(EVENT_TABCLOSED)) {
apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, win->w_buffer); apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, win->w_buffer);