Patch 8.2.2354
Problem:    Crash with a weird combination of autocommands.
Solution:   Increment b_nwindows when needed. (closes #7674)
Files:      src/ex_cmds.c, src/buffer.c, src/proto/buffer.pro,
            src/testdir/test_autocmd.vim


*** ../vim-8.2.2353/src/ex_cmds.c       2021-01-07 14:45:00.121819781 +0100
--- src/ex_cmds.c       2021-01-15 16:09:52.863124948 +0100
***************
*** 2742,2747 ****
--- 2742,2749 ----
            else
            {
                win_T       *the_curwin = curwin;
+               int         did_decrement;
+               buf_T       *was_curbuf = curbuf;
  
                // Set the w_closing flag to avoid that autocommands close the
                // window.  And set b_locked for the same reason.
***************
*** 2754,2760 ****
                // Close the link to the current buffer. This will set
                // oldwin->w_buffer to NULL.
                u_sync(FALSE);
!               close_buffer(oldwin, curbuf,
                         (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE, FALSE);
  
                the_curwin->w_closing = FALSE;
--- 2756,2762 ----
                // Close the link to the current buffer. This will set
                // oldwin->w_buffer to NULL.
                u_sync(FALSE);
!               did_decrement = close_buffer(oldwin, curbuf,
                         (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE, FALSE);
  
                the_curwin->w_closing = FALSE;
***************
*** 2776,2782 ****
--- 2778,2792 ----
                    goto theend;
                }
                if (buf == curbuf)              // already in new buffer
+               {
+                   // close_buffer() has decremented the window count,
+                   // increment it again here and restore w_buffer.
+                   if (did_decrement && buf_valid(was_curbuf))
+                       ++was_curbuf->b_nwindows;
+                   if (win_valid_any_tab(oldwin) && oldwin->w_buffer == NULL)
+                       oldwin->w_buffer = was_curbuf;
                    auto_buf = TRUE;
+               }
                else
                {
  #ifdef FEAT_SYN_HL
*** ../vim-8.2.2353/src/buffer.c        2020-12-28 18:25:56.796886014 +0100
--- src/buffer.c        2021-01-15 15:04:49.809399903 +0100
***************
*** 492,499 ****
   * supposed to close the window but autocommands close all other windows.
   *
   * When "ignore_abort" is TRUE don't abort even when aborting() returns TRUE.
   */
!     void
  close_buffer(
      win_T     *win,           // if not NULL, set b_last_cursor
      buf_T     *buf,
--- 492,501 ----
   * supposed to close the window but autocommands close all other windows.
   *
   * When "ignore_abort" is TRUE don't abort even when aborting() returns TRUE.
+  *
+  * Return TRUE when we got to the end and b_nwindows was decremented.
   */
!     int
  close_buffer(
      win_T     *win,           // if not NULL, set b_last_cursor
      buf_T     *buf,
***************
*** 540,546 ****
            if (wipe_buf || unload_buf)
            {
                if (!can_unload_buffer(buf))
!                   return;
  
                // Wiping out or unloading a terminal buffer kills the job.
                free_terminal(buf);
--- 542,548 ----
            if (wipe_buf || unload_buf)
            {
                if (!can_unload_buffer(buf))
!                   return FALSE;
  
                // Wiping out or unloading a terminal buffer kills the job.
                free_terminal(buf);
***************
*** 571,577 ****
      // Disallow deleting the buffer when it is locked (already being closed or
      // halfway a command that relies on it). Unloading is allowed.
      if ((del_buf || wipe_buf) && !can_unload_buffer(buf))
!       return;
  
      // check no autocommands closed the window
      if (win != NULL && win_valid_any_tab(win))
--- 573,579 ----
      // Disallow deleting the buffer when it is locked (already being closed or
      // halfway a command that relies on it). Unloading is allowed.
      if ((del_buf || wipe_buf) && !can_unload_buffer(buf))
!       return FALSE;
  
      // check no autocommands closed the window
      if (win != NULL && win_valid_any_tab(win))
***************
*** 600,606 ****
            // Autocommands deleted the buffer.
  aucmd_abort:
            emsg(_(e_auabort));
!           return;
        }
        --buf->b_locked;
        if (abort_if_last && one_window())
--- 602,608 ----
            // Autocommands deleted the buffer.
  aucmd_abort:
            emsg(_(e_auabort));
!           return FALSE;
        }
        --buf->b_locked;
        if (abort_if_last && one_window())
***************
*** 625,631 ****
  #ifdef FEAT_EVAL
        // autocmds may abort script processing
        if (!ignore_abort && aborting())
!           return;
  #endif
      }
  
--- 627,633 ----
  #ifdef FEAT_EVAL
        // autocmds may abort script processing
        if (!ignore_abort && aborting())
!           return FALSE;
  #endif
      }
  
***************
*** 653,659 ****
      // Return when a window is displaying the buffer or when it's not
      // unloaded.
      if (buf->b_nwindows > 0 || !unload_buf)
!       return;
  
      // Always remove the buffer when there is no file name.
      if (buf->b_ffname == NULL)
--- 655,661 ----
      // Return when a window is displaying the buffer or when it's not
      // unloaded.
      if (buf->b_nwindows > 0 || !unload_buf)
!       return FALSE;
  
      // Always remove the buffer when there is no file name.
      if (buf->b_ffname == NULL)
***************
*** 683,693 ****
  
      // Autocommands may have deleted the buffer.
      if (!bufref_valid(&bufref))
!       return;
  #ifdef FEAT_EVAL
      // autocmds may abort script processing
      if (!ignore_abort && aborting())
!       return;
  #endif
  
      /*
--- 685,695 ----
  
      // Autocommands may have deleted the buffer.
      if (!bufref_valid(&bufref))
!       return FALSE;
  #ifdef FEAT_EVAL
      // autocmds may abort script processing
      if (!ignore_abort && aborting())
!       return FALSE;
  #endif
  
      /*
***************
*** 698,704 ****
       * deleted buffer.
       */
      if (buf == curbuf && !is_curbuf)
!       return;
  
      if (win_valid_any_tab(win) && win->w_buffer == buf)
        win->w_buffer = NULL;  // make sure we don't use the buffer now
--- 700,706 ----
       * deleted buffer.
       */
      if (buf == curbuf && !is_curbuf)
!       return FALSE;
  
      if (win_valid_any_tab(win) && win->w_buffer == buf)
        win->w_buffer = NULL;  // make sure we don't use the buffer now
***************
*** 755,760 ****
--- 757,763 ----
            buf->b_p_bl = FALSE;
      }
      // NOTE: at this point "curbuf" may be invalid!
+     return TRUE;
  }
  
  /*
*** ../vim-8.2.2353/src/proto/buffer.pro        2020-11-05 19:36:34.706317028 
+0100
--- src/proto/buffer.pro        2021-01-15 15:05:23.437306054 +0100
***************
*** 5,11 ****
  void set_bufref(bufref_T *bufref, buf_T *buf);
  int bufref_valid(bufref_T *bufref);
  int buf_valid(buf_T *buf);
! void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last, int 
ignore_abort);
  void buf_clear_file(buf_T *buf);
  void buf_freeall(buf_T *buf, int flags);
  void free_wininfo(wininfo_T *wip);
--- 5,11 ----
  void set_bufref(bufref_T *bufref, buf_T *buf);
  int bufref_valid(bufref_T *bufref);
  int buf_valid(buf_T *buf);
! int close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last, int 
ignore_abort);
  void buf_clear_file(buf_T *buf);
  void buf_freeall(buf_T *buf, int flags);
  void free_wininfo(wininfo_T *wip);
*** ../vim-8.2.2353/src/testdir/test_autocmd.vim        2020-12-22 
11:40:40.669481249 +0100
--- src/testdir/test_autocmd.vim        2021-01-15 16:01:14.072446087 +0100
***************
*** 500,505 ****
--- 500,525 ----
    endfor
  endfunc
  
+ " Using :blast and :ball for many events caused a crash, because b_nwindows 
was
+ " not incremented correctly.
+ func Test_autocmd_blast_badd()
+   let content =<< trim [CODE]
+       au 
BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* 
blast
+       edit foo1
+       au 
BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* 
ball
+       edit foo2
+       call writefile(['OK'], 'Xerrors')
+       qall
+   [CODE]
+ 
+   call writefile(content, 'XblastBall')
+   call system(GetVimCommand() .. ' --clean -S XblastBall')
+   call assert_match('OK', readfile('Xerrors')->join())
+ 
+   call delete('XblastBall')
+   call delete('Xerrors')
+ endfunc
+ 
  " SEGV occurs in older versions.
  func Test_autocmd_bufwipe_in_SessLoadPost2()
    tabnew
*** ../vim-8.2.2353/src/version.c       2021-01-15 13:35:26.763953669 +0100
--- src/version.c       2021-01-15 15:02:52.333726768 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2354,
  /**/

-- 
Although the scythe isn't pre-eminent among the weapons of war, anyone who
has been on the wrong end of, say, a peasants' revolt will know that in
skilled hands it is fearsome.
                                        -- (Terry Pratchett, Mort)

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202101151523.10FFNPr71916341%40masaka.moolenaar.net.

Raspunde prin e-mail lui