]> granicus.if.org Git - vim/commitdiff
patch 8.2.4631: crash when switching window in BufWipeout autocommand v8.2.4631
authorBram Moolenaar <Bram@vim.org>
Sat, 26 Mar 2022 16:28:06 +0000 (16:28 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 26 Mar 2022 16:28:06 +0000 (16:28 +0000)
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
src/testdir/test_autocmd.vim
src/version.c
src/window.c

index 2dac4874c57def7ea42b368707f84d8ef03a3b96..93da5dcc32e6d3e4d88555e1f2f28f6ed9dc909f 100644 (file)
@@ -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
index 688508a856da55757a0a030fa7b513c132295715..39ba9af7dcb42dd0d9b8a9de9992d2c2fa9f0f38 100644 (file)
@@ -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 <buffer> call win_gotoid(g:window_id)
+  tabprevious
+  +tabclose
+
+  unlet g:window_id
+  au! BufWipeout
+  %bwipe!
+endfunc
+
+
 " vim: shiftwidth=2 sts=2 expandtab
index 5eb4eea1e58a274d0c5aadca5ea100eb650d1c02..9d78a0e8f780b45b07edb95e8c5abf3fe43d1535 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4631,
 /**/
     4630,
 /**/
index 5bda6add97e2b72da18a3c1a6c0276b5353c3c4a..66dd099bf6f6929aee999016902ec609ef3ed76b 100644 (file)
@@ -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().