Last active
August 24, 2016 09:04
-
-
Save h-east/9f2322ec5225f54d61071d040e1351a5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/buffer.c b/src/buffer.c | |
index 75de736..db632fa 100644 | |
--- a/src/buffer.c | |
+++ b/src/buffer.c | |
@@ -499,6 +499,10 @@ close_buffer( | |
/* When the buffer is no longer in a window, trigger BufWinLeave */ | |
if (buf->b_nwindows == 1) | |
{ | |
+# ifdef FEAT_WINDOWS | |
+ tabpage_T *save_curtab = curtab; | |
+# endif | |
+ | |
buf->b_closing = TRUE; | |
if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, | |
FALSE, buf) | |
@@ -533,6 +537,10 @@ aucmd_abort: | |
if (aborting()) /* autocmds may abort script processing */ | |
return; | |
# endif | |
+# ifdef FEAT_WINDOWS | |
+ if (save_curtab != curtab) | |
+ return; | |
+# endif | |
} | |
nwindows = buf->b_nwindows; | |
#endif | |
@@ -561,7 +569,9 @@ aucmd_abort: | |
buf->b_nwindows = nwindows; | |
#endif | |
- buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)); | |
+ if (buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)) | |
+ == FAIL) | |
+ return; | |
#ifdef FEAT_AUTOCMD | |
/* Autocommands may have deleted the buffer. */ | |
@@ -670,13 +680,17 @@ buf_clear_file(buf_T *buf) | |
* BFA_DEL buffer is going to be deleted | |
* BFA_WIPE buffer is going to be wiped out | |
* BFA_KEEP_UNDO do not free undo information | |
+ * Return FAIL for failure, OK otherwise. | |
*/ | |
- void | |
+ int | |
buf_freeall(buf_T *buf, int flags) | |
{ | |
#ifdef FEAT_AUTOCMD | |
int is_curbuf = (buf == curbuf); | |
bufref_T bufref; | |
+# ifdef FEAT_WINDOWS | |
+ tabpage_T *save_curtab = curtab; | |
+# endif | |
buf->b_closing = TRUE; | |
set_bufref(&bufref, buf); | |
@@ -686,7 +700,7 @@ buf_freeall(buf_T *buf, int flags) | |
FALSE, buf) | |
&& !bufref_valid(&bufref)) | |
/* autocommands deleted the buffer */ | |
- return; | |
+ return FAIL; | |
} | |
if ((flags & BFA_DEL) && buf->b_p_bl) | |
{ | |
@@ -694,7 +708,7 @@ buf_freeall(buf_T *buf, int flags) | |
FALSE, buf) | |
&& !bufref_valid(&bufref)) | |
/* autocommands deleted the buffer */ | |
- return; | |
+ return FAIL; | |
} | |
if (flags & BFA_WIPE) | |
{ | |
@@ -702,12 +716,16 @@ buf_freeall(buf_T *buf, int flags) | |
FALSE, buf) | |
&& !bufref_valid(&bufref)) | |
/* autocommands deleted the buffer */ | |
- return; | |
+ return FAIL; | |
} | |
buf->b_closing = FALSE; | |
# ifdef FEAT_EVAL | |
if (aborting()) /* autocmds may abort script processing */ | |
- return; | |
+ return FAIL; | |
+# endif | |
+# ifdef FEAT_WINDOWS | |
+ if (save_curtab != curtab) | |
+ return FAIL; | |
# endif | |
/* | |
@@ -717,7 +735,7 @@ buf_freeall(buf_T *buf, int flags) | |
* Therefore only return if curbuf changed to the deleted buffer. | |
*/ | |
if (buf == curbuf && !is_curbuf) | |
- return; | |
+ return FAIL; | |
#endif | |
#ifdef FEAT_DIFF | |
diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */ | |
@@ -759,6 +777,7 @@ buf_freeall(buf_T *buf, int flags) | |
syntax_clear(&buf->b_s); /* reset syntax info */ | |
#endif | |
buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */ | |
+ return OK; | |
} | |
/* | |
@@ -1940,7 +1959,8 @@ buflist_new( | |
if (buf == curbuf) | |
{ | |
/* free all things allocated for this buffer */ | |
- buf_freeall(buf, 0); | |
+ if (buf_freeall(buf, 0) == FAIL) | |
+ return NULL; | |
if (buf != curbuf) /* autocommands deleted the buffer! */ | |
return NULL; | |
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) | |
diff --git a/src/ex_cmds.c b/src/ex_cmds.c | |
index 9e6a72d..57ff429 100644 | |
--- a/src/ex_cmds.c | |
+++ b/src/ex_cmds.c | |
@@ -4098,7 +4098,13 @@ do_ecmd( | |
goto theend; | |
} | |
u_unchanged(curbuf); | |
- buf_freeall(curbuf, BFA_KEEP_UNDO); | |
+ if (buf_freeall(curbuf, BFA_KEEP_UNDO) == FAIL) | |
+ { | |
+#ifdef FEAT_AUTOCMD | |
+ vim_free(new_name); | |
+#endif | |
+ goto theend; | |
+ } | |
/* tell readfile() not to clear or reload undo info */ | |
readfile_flags = READ_KEEP_UNDO; | |
@@ -4394,6 +4400,11 @@ delbuf_msg(char_u *name) | |
vim_free(name); | |
au_new_curbuf.br_buf = NULL; | |
au_new_curbuf.br_buf_free_count = 0; | |
+ | |
+# ifdef FEAT_WINDOWS | |
+ if (curwin->w_buffer == NULL) | |
+ enter_buffer(curbuf); | |
+# endif | |
} | |
#endif | |
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro | |
index 183f79a..dbe152b 100644 | |
--- a/src/proto/buffer.pro | |
+++ b/src/proto/buffer.pro | |
@@ -5,7 +5,7 @@ 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); | |
void buf_clear_file(buf_T *buf); | |
-void buf_freeall(buf_T *buf, int flags); | |
+int buf_freeall(buf_T *buf, int flags); | |
void goto_buffer(exarg_T *eap, int start, int dir, int count); | |
void handle_swap_exists(bufref_T *old_curbuf); | |
char_u *do_bufdel(int command, char_u *arg, int addr_count, int start_bnr, int end_bnr, int forceit); | |
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim | |
index d856d32..7afa261 100644 | |
--- a/src/testdir/test_autocmd.vim | |
+++ b/src/testdir/test_autocmd.vim | |
@@ -77,11 +77,48 @@ function Test_autocmd_bufunload_with_tabnext() | |
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 version. (At least 7.4.2247 or older) | |
+function Test_autocmd_bufunload_avoiding_SEGV_01() | |
+ edit a.txt | |
+ | |
+ augroup test_autocmd_bufunload | |
+ autocmd! | |
+ autocmd BufUnload <buffer> tabfirst | 2bwipeout! | |
+ augroup END | |
+ | |
+ edit b.txt | |
+ call assert_equal(3, bufnr('$')) | |
+ | |
+ autocmd! test_autocmd_bufunload | |
+ augroup! test_autocmd_bufunload | |
+ only! | |
+endfunc | |
+ | |
+" SEGV occurs in older version. (At least 7.4.2247 or older) | |
+function Test_autocmd_bufunload_avoiding_SEGV_02() | |
+ setlocal buftype=nowrite | |
+ | |
+ augroup test_autocmd_bufunload | |
+ autocmd! | |
+ autocmd BufUnload <buffer> tabfirst | 2bwipeout | |
+ augroup END | |
+ | |
+ normal! i1 | |
+ edit a.txt | |
+ call feedkeys("\<CR>", 'tx') | |
+ call assert_equal(1, bufnr('$')) | |
+ | |
+ autocmd! test_autocmd_bufunload | |
+ augroup! test_autocmd_bufunload | |
+ new | only! | |
+endfunc | |
+ | |
func Test_win_tab_autocmd() | |
let g:record = [] | |
@@ -168,3 +205,5 @@ func Test_augroup_warning() | |
augroup END | |
call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0) | |
endfunc | |
+ | |
+" vim: shiftwidth=2 sts=2 expandtab | |
diff --git a/src/window.c b/src/window.c | |
index b015d1d..71202b8 100644 | |
--- a/src/window.c | |
+++ b/src/window.c | |
@@ -2305,7 +2305,12 @@ win_close(win_T *win, int free_buf) | |
* and then close the window and the tab page to avoid that curwin and | |
* curtab are invalid while we are freeing memory. */ | |
if (close_last_window_tabpage(win, free_buf, prev_curtab)) | |
- return FAIL; | |
+ { | |
+ /* Autocommands have close curwin's buf. Restore curwin->w_buffer */ | |
+ if (win_valid(curwin) && curwin->w_buffer == NULL) | |
+ curwin->w_buffer = curbuf; | |
+ return FAIL; | |
+ } | |
/* When closing the help window, try restoring a snapshot after closing | |
* the window. Otherwise clear the snapshot, it's now invalid. */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment