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.