Patch 7.4.2324
Problem:    Crash when editing a new buffer and BufUnload autocommand wipes
            out the new buffer. (Norio Takagi)
Solution:   Don't allow wiping out this buffer. (partly by Hirohito Higashi)
            Move old style test13 into test_autocmd. Avoid ml_get error when
            editing a file.
Files:      src/structs.h, src/buffer.c, src/ex_cmds.c, src/ex_docmd.c,
            src/window.c, src/testdir/test13.in, src/testdir/test13.ok,
            src/testdir/test_autocmd.vim, src/testdir/Make_all.mak,
            src/Makefile


*** ../vim-7.4.2323/src/structs.h       2016-08-29 22:48:12.169106012 +0200
--- src/structs.h       2016-09-04 17:20:33.023755549 +0200
***************
*** 1845,1852 ****
  
      int               b_flags;        /* various BF_ flags */
  #ifdef FEAT_AUTOCMD
!     int               b_closing;      /* buffer is being closed, don't let
!                                  autocommands close it too. */
  #endif
  
      /*
--- 1845,1852 ----
  
      int               b_flags;        /* various BF_ flags */
  #ifdef FEAT_AUTOCMD
!     int               b_locked;       /* Buffer is being closed or 
referenced, don't
!                                  let autocommands wipe it out. */
  #endif
  
      /*
*** ../vim-7.4.2323/src/buffer.c        2016-09-03 16:29:01.442841209 +0200
--- src/buffer.c        2016-09-04 18:21:06.192908890 +0200
***************
*** 476,481 ****
--- 476,489 ----
        unload_buf = TRUE;
  #endif
  
+     /* Disallow deleting the buffer when it is locked (already being closed or
+      * halfway a command that relies on it). Unloading is allowed. */
+     if (buf->b_locked > 0 && (del_buf || wipe_buf))
+     {
+       EMSG(_("E937: Attempt to delete a buffer that is in use"));
+       return;
+     }
+ 
      if (win != NULL
  #ifdef FEAT_WINDOWS
        && win_valid_any_tab(win) /* in case autocommands closed the window */
***************
*** 499,505 ****
      /* When the buffer is no longer in a window, trigger BufWinLeave */
      if (buf->b_nwindows == 1)
      {
!       buf->b_closing = TRUE;
        if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
                                                                  FALSE, buf)
                && !bufref_valid(&bufref))
--- 507,513 ----
      /* When the buffer is no longer in a window, trigger BufWinLeave */
      if (buf->b_nwindows == 1)
      {
!       ++buf->b_locked;
        if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
                                                                  FALSE, buf)
                && !bufref_valid(&bufref))
***************
*** 509,515 ****
            EMSG(_(e_auabort));
            return;
        }
!       buf->b_closing = FALSE;
        if (abort_if_last && one_window())
            /* Autocommands made this the only window. */
            goto aucmd_abort;
--- 517,523 ----
            EMSG(_(e_auabort));
            return;
        }
!       --buf->b_locked;
        if (abort_if_last && one_window())
            /* Autocommands made this the only window. */
            goto aucmd_abort;
***************
*** 518,530 ****
         * BufHidden */
        if (!unload_buf)
        {
!           buf->b_closing = TRUE;
            if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
                                                                  FALSE, buf)
                    && !bufref_valid(&bufref))
                /* Autocommands deleted the buffer. */
                goto aucmd_abort;
!           buf->b_closing = FALSE;
            if (abort_if_last && one_window())
                /* Autocommands made this the only window. */
                goto aucmd_abort;
--- 526,538 ----
         * BufHidden */
        if (!unload_buf)
        {
!           ++buf->b_locked;
            if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
                                                                  FALSE, buf)
                    && !bufref_valid(&bufref))
                /* Autocommands deleted the buffer. */
                goto aucmd_abort;
!           --buf->b_locked;
            if (abort_if_last && one_window())
                /* Autocommands made this the only window. */
                goto aucmd_abort;
***************
*** 685,691 ****
  # endif
  
      /* Make sure the buffer isn't closed by autocommands. */
!     buf->b_closing = TRUE;
      set_bufref(&bufref, buf);
      if (buf->b_ml.ml_mfp != NULL)
      {
--- 693,699 ----
  # endif
  
      /* Make sure the buffer isn't closed by autocommands. */
!     ++buf->b_locked;
      set_bufref(&bufref, buf);
      if (buf->b_ml.ml_mfp != NULL)
      {
***************
*** 711,717 ****
            /* autocommands deleted the buffer */
            return;
      }
!     buf->b_closing = FALSE;
  
  # ifdef FEAT_WINDOWS
      /* If the buffer was in curwin and the window has changed, go back to that
--- 719,725 ----
            /* autocommands deleted the buffer */
            return;
      }
!     --buf->b_locked;
  
  # ifdef FEAT_WINDOWS
      /* If the buffer was in curwin and the window has changed, go back to that
***************
*** 1369,1375 ****
         */
        while (buf == curbuf
  # ifdef FEAT_AUTOCMD
!                  && !(curwin->w_closing || curwin->w_buffer->b_closing)
  # endif
                   && (firstwin != lastwin || first_tabpage->tp_next != NULL))
        {
--- 1377,1383 ----
         */
        while (buf == curbuf
  # ifdef FEAT_AUTOCMD
!                  && !(curwin->w_closing || curwin->w_buffer->b_locked > 0)
  # endif
                   && (firstwin != lastwin || first_tabpage->tp_next != NULL))
        {
***************
*** 5100,5106 ****
  #endif
                    ) && firstwin != lastwin
  #ifdef FEAT_AUTOCMD
!                   && !(wp->w_closing || wp->w_buffer->b_closing)
  #endif
                    )
            {
--- 5108,5114 ----
  #endif
                    ) && firstwin != lastwin
  #ifdef FEAT_AUTOCMD
!                   && !(wp->w_closing || wp->w_buffer->b_locked > 0)
  #endif
                    )
            {
*** ../vim-7.4.2323/src/ex_cmds.c       2016-09-03 16:29:01.446841174 +0200
--- src/ex_cmds.c       2016-09-04 19:44:37.748006216 +0200
***************
*** 3872,3879 ****
            oldbuf = TRUE;
            set_bufref(&bufref, buf);
            (void)buf_check_timestamp(buf, FALSE);
!           /* Check if autocommands made buffer invalid or changed the current
!            * buffer. */
            if (!bufref_valid(&bufref)
  #ifdef FEAT_AUTOCMD
                    || curbuf != old_curbuf.br_buf
--- 3872,3879 ----
            oldbuf = TRUE;
            set_bufref(&bufref, buf);
            (void)buf_check_timestamp(buf, FALSE);
!           /* Check if autocommands made the buffer invalid or changed the
!            * current buffer. */
            if (!bufref_valid(&bufref)
  #ifdef FEAT_AUTOCMD
                    || curbuf != old_curbuf.br_buf
***************
*** 3938,3945 ****
                win_T       *the_curwin = curwin;
  
                /* Set the w_closing flag to avoid that autocommands close the
!                * window. */
                the_curwin->w_closing = TRUE;
  
                if (curbuf == old_curbuf.br_buf)
  #endif
--- 3938,3946 ----
                win_T       *the_curwin = curwin;
  
                /* Set the w_closing flag to avoid that autocommands close the
!                * window.  And set b_locked for the same reason. */
                the_curwin->w_closing = TRUE;
+               ++buf->b_locked;
  
                if (curbuf == old_curbuf.br_buf)
  #endif
***************
*** 3953,3958 ****
--- 3954,3960 ----
  
  #ifdef FEAT_AUTOCMD
                the_curwin->w_closing = FALSE;
+               --buf->b_locked;
  
  # ifdef FEAT_EVAL
                /* autocmds may abort script processing */
***************
*** 4140,4150 ****
      retval = OK;
  
      /*
-      * Reset cursor position, could be used by autocommands.
-      */
-     check_cursor();
- 
-     /*
       * Check if we are editing the w_arg_idx file in the argument list.
       */
      check_arg_idx(curwin);
--- 4142,4147 ----
*** ../vim-7.4.2323/src/ex_docmd.c      2016-09-03 16:29:01.450841139 +0200
--- src/ex_docmd.c      2016-09-04 17:23:25.074265604 +0200
***************
*** 7201,7207 ****
      /* Refuse to quit when locked or when the buffer in the last window is
       * being closed (can only happen in autocommands). */
      if (curbuf_locked() || (wp->w_buffer->b_nwindows == 1
!                                                 && wp->w_buffer->b_closing))
        return;
  #endif
  
--- 7201,7207 ----
      /* Refuse to quit when locked or when the buffer in the last window is
       * being closed (can only happen in autocommands). */
      if (curbuf_locked() || (wp->w_buffer->b_nwindows == 1
!                                               && wp->w_buffer->b_locked > 0))
        return;
  #endif
  
***************
*** 7283,7289 ****
      apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
      /* Refuse to quit when locked or when the buffer in the last window is
       * being closed (can only happen in autocommands). */
!     if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
        return;
  #endif
  
--- 7283,7289 ----
      apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
      /* Refuse to quit when locked or when the buffer in the last window is
       * being closed (can only happen in autocommands). */
!     if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0))
        return;
  #endif
  
***************
*** 7665,7671 ****
      apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
      /* Refuse to quit when locked or when the buffer in the last window is
       * being closed (can only happen in autocommands). */
!     if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
        return;
  #endif
  
--- 7665,7671 ----
      apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
      /* Refuse to quit when locked or when the buffer in the last window is
       * being closed (can only happen in autocommands). */
!     if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0))
        return;
  #endif
  
*** ../vim-7.4.2323/src/window.c        2016-09-03 16:29:01.450841139 +0200
--- src/window.c        2016-09-04 17:24:16.305822424 +0200
***************
*** 2127,2133 ****
      {
        if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
  #ifdef FEAT_AUTOCMD
!               && !(wp->w_closing || wp->w_buffer->b_closing)
  #endif
                )
        {
--- 2127,2133 ----
      {
        if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
  #ifdef FEAT_AUTOCMD
!               && !(wp->w_closing || wp->w_buffer->b_locked > 0)
  #endif
                )
        {
***************
*** 2148,2154 ****
            for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
                if (wp->w_buffer == buf
  #ifdef FEAT_AUTOCMD
!                   && !(wp->w_closing || wp->w_buffer->b_closing)
  #endif
                    )
                {
--- 2148,2154 ----
            for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
                if (wp->w_buffer == buf
  #ifdef FEAT_AUTOCMD
!                   && !(wp->w_closing || wp->w_buffer->b_locked > 0)
  #endif
                    )
                {
***************
*** 2287,2293 ****
      }
  
  #ifdef FEAT_AUTOCMD
!     if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_closing))
        return FAIL; /* window is already being closed */
      if (win == aucmd_win)
      {
--- 2287,2294 ----
      }
  
  #ifdef FEAT_AUTOCMD
!     if (win->w_closing || (win->w_buffer != NULL
!                                              && win->w_buffer->b_locked > 0))
        return FAIL; /* window is already being closed */
      if (win == aucmd_win)
      {
***************
*** 2503,2509 ****
  #ifdef FEAT_AUTOCMD
      /* Get here with win->w_buffer == NULL when win_close() detects the tab
       * page changed. */
!     if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_closing))
        return; /* window is already being closed */
  #endif
  
--- 2504,2511 ----
  #ifdef FEAT_AUTOCMD
      /* Get here with win->w_buffer == NULL when win_close() detects the tab
       * page changed. */
!     if (win->w_closing || (win->w_buffer != NULL
!                                              && win->w_buffer->b_locked > 0))
        return; /* window is already being closed */
  #endif
  
*** ../vim-7.4.2323/src/testdir/test13.in       2015-06-19 12:43:02.380196210 
+0200
--- src/testdir/test13.in       1970-01-01 01:00:00.000000000 +0100
***************
*** 1,64 ****
- Tests for autocommands on :close command
- 
- Write three files and open them, each in a window.
- Then go to next window, with autocommand that deletes the previous one.
- Do this twice, writing the file.
- 
- Also test deleting the buffer on a Unload event.  If this goes wrong there
- will be the ATTENTION prompt.
- 
- Also test changing buffers in a BufDel autocommand.  If this goes wrong there
- are ml_line errors and/or a Crash.
- 
- STARTTEST
- :so small.vim
- :/^start of testfile/,/^end of testfile/w! Xtestje1
- :/^start of testfile/,/^end of testfile/w! Xtestje2
- :/^start of testfile/,/^end of testfile/w! Xtestje3
- :e Xtestje1
- otestje1 
- :w
- :sp Xtestje2
- otestje2 
- :w
- :sp Xtestje3
- otestje3 
- :w
-   
- :au WinLeave Xtestje2 bwipe
-   
- :w! test.out
- :au WinLeave Xtestje1 bwipe Xtestje3
- :close
- :w >>test.out
- :e Xtestje1
- :bwipe Xtestje2 Xtestje3 test.out
- :au!
- :au! BufUnload Xtestje1 bwipe
- :e Xtestje3
- :w >>test.out
- :e Xtestje2
- :sp Xtestje1
- :e
- :w >>test.out
- :au!
- :only
- :e Xtestje1
- :bwipe Xtestje2 Xtestje3 test.out test13.in
- :au BufWipeout Xtestje1 buf Xtestje1
- :bwipe
- :w >>test.out
- :only
- :help
- :wincmd w
- :1quit
- :$put ='Final line'
- :$w >>test.out
- :qa!
- ENDTEST
- 
- start of testfile
-       contents
-       contents
-       contents
- end of testfile
--- 0 ----
*** ../vim-7.4.2323/src/testdir/test13.ok       2015-06-19 12:43:02.380196210 
+0200
--- src/testdir/test13.ok       1970-01-01 01:00:00.000000000 +0100
***************
*** 1,31 ****
- start of testfile
- testje1
-       contents
-       contents
-       contents
- end of testfile
- start of testfile
- testje1
-       contents
-       contents
-       contents
- end of testfile
- start of testfile
- testje3
-       contents
-       contents
-       contents
- end of testfile
- start of testfile
- testje2
-       contents
-       contents
-       contents
- end of testfile
- start of testfile
- testje1
-       contents
-       contents
-       contents
- end of testfile
- Final line
--- 0 ----
*** ../vim-7.4.2323/src/testdir/test_autocmd.vim        2016-09-03 
16:59:03.043059395 +0200
--- src/testdir/test_autocmd.vim        2016-09-04 18:25:24.522751653 +0200
***************
*** 77,87 ****
--- 77,125 ----
    quit
    call assert_equal(2, tabpagenr('$'))
  
+   autocmd! test_autocmd_bufunload_with_tabnext_group
    augroup! test_autocmd_bufunload_with_tabnext_group
    tablast
    quit
  endfunc
  
+ " SEGV occurs in older versions.  (At least 7.4.2321 or older)
+ function Test_autocmd_bufunload_avoiding_SEGV_01()
+   split aa.txt
+   let lastbuf = bufnr('$')
+ 
+   augroup test_autocmd_bufunload
+     autocmd!
+     exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
+   augroup END
+ 
+   call assert_fails('edit bb.txt', 'E937:')
+ 
+   autocmd! test_autocmd_bufunload
+   augroup! test_autocmd_bufunload
+   bwipe! aa.txt
+   bwipe! bb.txt
+ endfunc
+ 
+ " SEGV occurs in older versions.  (At least 7.4.2321 or older)
+ function Test_autocmd_bufunload_avoiding_SEGV_02()
+   setlocal buftype=nowrite
+   let lastbuf = bufnr('$')
+ 
+   augroup test_autocmd_bufunload
+     autocmd!
+     exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
+   augroup END
+ 
+   normal! i1
+   call assert_fails('edit a.txt', 'E517:')
+   call feedkeys("\<CR>")
+ 
+   autocmd! test_autocmd_bufunload
+   augroup! test_autocmd_bufunload
+   bwipe! a.txt
+ endfunc
+ 
  func Test_win_tab_autocmd()
    let g:record = []
  
***************
*** 196,198 ****
--- 234,296 ----
    au! VimEnter
  endfunc
  
+ " Tests for autocommands on :close command.
+ " This used to be in test13.
+ func Test_three_windows()
+   " Write three files and open them, each in a window.
+   " Then go to next window, with autocommand that deletes the previous one.
+   " Do this twice, writing the file.
+   e! Xtestje1
+   call setline(1, 'testje1')
+   w
+   sp Xtestje2
+   call setline(1, 'testje2')
+   w
+   sp Xtestje3
+   call setline(1, 'testje3')
+   w
+   wincmd w
+   au WinLeave Xtestje2 bwipe
+   wincmd w
+   call assert_equal('Xtestje1', expand('%'))
+ 
+   au WinLeave Xtestje1 bwipe Xtestje3
+   close
+   call assert_equal('Xtestje1', expand('%'))
+ 
+   " Test deleting the buffer on a Unload event.  If this goes wrong there
+   " will be the ATTENTION prompt.
+   e Xtestje1
+   au!
+   au! BufUnload Xtestje1 bwipe
+   call assert_fails('e Xtestje3', 'E937:')
+   call assert_equal('Xtestje3', expand('%'))
+ 
+   e Xtestje2
+   sp Xtestje1
+   call assert_fails('e', 'E937:')
+   call assert_equal('Xtestje2', expand('%'))
+ 
+   " Test changing buffers in a BufWipeout autocommand.  If this goes wrong
+   " there are ml_line errors and/or a Crash.
+   au!
+   only
+   e Xanother
+   e Xtestje1
+   bwipe Xtestje2
+   bwipe Xtestje3
+   au BufWipeout Xtestje1 buf Xtestje1
+   bwipe
+   call assert_equal('Xanother', expand('%'))
+ 
+   only
+   help
+   wincmd w
+   1quit
+   call assert_equal('Xanother', expand('%'))
+ 
+   au!
+   call delete('Xtestje1')
+   call delete('Xtestje2')
+   call delete('Xtestje3')
+ endfunc
*** ../vim-7.4.2323/src/testdir/Make_all.mak    2016-09-03 17:33:39.752215409 
+0200
--- src/testdir/Make_all.mak    2016-09-04 18:02:13.950370486 +0200
***************
*** 111,117 ****
  SCRIPTS_MORE2 = \
        test2.out \
        test12.out \
-       test13.out \
        test25.out \
        test49.out \
        test97.out \
--- 111,116 ----
*** ../vim-7.4.2323/src/Makefile        2016-09-03 17:33:39.752215409 +0200
--- src/Makefile        2016-09-04 18:02:42.130134856 +0200
***************
*** 2042,2048 ****
        test_utf8 \
        test_wordcount \
        test2 test3 test4 test5 test6 test7 test8 test9 \
!       test11 test12 test13 test14 test15 test17 test18 test19 \
        test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
        test30 test31 test32 test33 test34 test36 test37 test38 test39 \
        test40 test41 test42 test43 test44 test45 test48 test49 \
--- 2042,2048 ----
        test_utf8 \
        test_wordcount \
        test2 test3 test4 test5 test6 test7 test8 test9 \
!       test11 test12 test14 test15 test17 test18 test19 \
        test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
        test30 test31 test32 test33 test34 test36 test37 test38 test39 \
        test40 test41 test42 test43 test44 test45 test48 test49 \
*** ../vim-7.4.2323/src/version.c       2016-09-04 15:13:36.621508727 +0200
--- src/version.c       2016-09-04 19:45:34.727544841 +0200
***************
*** 765,766 ****
--- 765,768 ----
  {   /* Add new patch number below this line */
+ /**/
+     2324,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
165. You have a web page burned into your glasses

 /// 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].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui