vim-patch:8.2.4631: crash when switching window in BufWipeout autocommand

Problem:    Crash when switching window in BufWipeout autocommand.
Solution:   Put any buffer in the window to avoid it being NULL.
            (closes vim/vim#10024)
347538fad0

win_init_empty() cannot be made static because it is used in autocmd.c
This commit is contained in:
zeertzjq
2022-03-27 08:57:57 +08:00
parent a490db5ba8
commit f4f18a9833
3 changed files with 52 additions and 27 deletions

View File

@@ -590,6 +590,10 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
// Remove the buffer from the list.
if (wipe_buf) {
// Do not wipe out the buffer if it is used in a window.
if (buf->b_nwindows > 0) {
return false;
}
if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
} else {

View File

@@ -2611,4 +2611,21 @@ func Test_autocmd_closing_cmdwin()
only
endfunc
func Test_bufwipeout_changes_window()
" This should not crash, but we don't have any expectations about what
" happens, changing window in BufWipeout has unpredictable results.
tabedit
let g:window_id = win_getid()
topleft new
setlocal bufhidden=wipe
autocmd BufWipeout <buffer> call win_gotoid(g:window_id)
tabprevious
+tabclose
unlet g:window_id
au! BufWipeout
%bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -2350,6 +2350,30 @@ void entering_window(win_T *const win)
}
}
void win_init_empty(win_T *wp)
{
redraw_later(wp, NOT_VALID);
wp->w_lines_valid = 0;
wp->w_cursor.lnum = 1;
wp->w_curswant = wp->w_cursor.col = 0;
wp->w_cursor.coladd = 0;
wp->w_pcmark.lnum = 1; // pcmark not cleared but set to line 1
wp->w_pcmark.col = 0;
wp->w_prev_pcmark.lnum = 0;
wp->w_prev_pcmark.col = 0;
wp->w_topline = 1;
wp->w_topfill = 0;
wp->w_botline = 2;
wp->w_s = &wp->w_buffer->b_s;
}
/// Init the current window "curwin".
/// Called when a new file is being edited.
void curwin_init(void)
{
win_init_empty(curwin);
}
/// Closes all windows for buffer `buf` unless there is only one non-floating window.
///
/// @param keep_curwin don't close `curwin`
@@ -2867,6 +2891,13 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next) {
}
if (ptp == NULL || tp == curtab) {
// If the buffer was removed from the window we have to give it any
// buffer.
if (win_valid_any_tab(win) && win->w_buffer == NULL) {
win->w_buffer = firstbuf;
firstbuf->b_nwindows++;
win_init_empty(win);
}
return;
}
@@ -3793,33 +3824,6 @@ void close_others(int message, int forceit)
}
}
/*
* Init the current window "curwin".
* Called when a new file is being edited.
*/
void curwin_init(void)
{
win_init_empty(curwin);
}
void win_init_empty(win_T *wp)
{
redraw_later(wp, NOT_VALID);
wp->w_lines_valid = 0;
wp->w_cursor.lnum = 1;
wp->w_curswant = wp->w_cursor.col = 0;
wp->w_cursor.coladd = 0;
wp->w_pcmark.lnum = 1; // pcmark not cleared but set to line 1
wp->w_pcmark.col = 0;
wp->w_prev_pcmark.lnum = 0;
wp->w_prev_pcmark.col = 0;
wp->w_topline = 1;
wp->w_topfill = 0;
wp->w_botline = 2;
wp->w_s = &wp->w_buffer->b_s;
}
/*
* Allocate the first window and put an empty buffer in it.
* Called from main().