From 347538fad0c503249ebdedd5884c2081257c9f61 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 26 Mar 2022 16:28:06 +0000 Subject: 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 #10024) --- src/buffer.c | 4 +++ src/testdir/test_autocmd.vim | 17 ++++++++++ src/version.c | 2 ++ src/window.c | 80 +++++++++++++++++++++++++------------------- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index 2dac4874c5..93da5dcc32 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -708,6 +708,10 @@ aucmd_abort: */ if (wipe_buf) { + // Do not wipe out the buffer if it is used in a window. + if (buf->b_nwindows > 0) + return FALSE; + if (action == DOBUF_WIPE_REUSE) { // we can re-use this buffer number, store it diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 688508a856..39ba9af7dc 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -2990,4 +2990,21 @@ func Test_closing_autocmd_window() bwipe Xb.txt 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 call win_gotoid(g:window_id) + tabprevious + +tabclose + + unlet g:window_id + au! BufWipeout + %bwipe! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 5eb4eea1e5..9d78a0e8f7 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4631, /**/ 4630, /**/ diff --git a/src/window.c b/src/window.c index 5bda6add97..66dd099bf6 100644 --- a/src/window.c +++ b/src/window.c @@ -2285,6 +2285,41 @@ entering_window(win_T *win) } #endif + static void +win_init_empty(win_T *wp) +{ + redraw_win_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; +#ifdef FEAT_DIFF + wp->w_topfill = 0; +#endif + wp->w_botline = 2; +#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) + wp->w_s = &wp->w_buffer->b_s; +#endif +#ifdef FEAT_TERMINAL + term_reset_wincolor(wp); +#endif +} + +/* + * Init the current window "curwin". + * Called when a new file is being edited. + */ + void +curwin_init(void) +{ + win_init_empty(curwin); +} + /* * Close all windows for buffer "buf". */ @@ -2786,7 +2821,17 @@ 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; + } // Autocommands may have closed the window already. for (wp = tp->tp_firstwin; wp != NULL && wp != win; wp = wp->w_next) @@ -3685,41 +3730,6 @@ close_others( emsg(_(e_other_window_contains_changes)); } - static void -win_init_empty(win_T *wp) -{ - redraw_win_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; -#ifdef FEAT_DIFF - wp->w_topfill = 0; -#endif - wp->w_botline = 2; -#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) - wp->w_s = &wp->w_buffer->b_s; -#endif -#ifdef FEAT_TERMINAL - term_reset_wincolor(wp); -#endif -} - -/* - * Init the current window "curwin". - * Called when a new file is being edited. - */ - void -curwin_init(void) -{ - win_init_empty(curwin); -} - /* * Allocate the first window and put an empty buffer in it. * Called from main(). -- cgit v1.2.3