mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.2.2354: crash with a weird combination of autocommands
Problem: Crash with a weird combination of autocommands.
Solution: Increment b_nwindows when needed. (closes vim/vim#7674)
797e63b9f2
This commit is contained in:
parent
4338077632
commit
f98433d82a
@ -407,7 +407,8 @@ bool buf_valid(buf_T *buf)
|
|||||||
/// there to be only one window with this buffer. e.g. when
|
/// there to be only one window with this buffer. e.g. when
|
||||||
/// ":quit" is supposed to close the window but autocommands
|
/// ":quit" is supposed to close the window but autocommands
|
||||||
/// close all other windows.
|
/// close all other windows.
|
||||||
void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
/// @returns true when we got to the end and b_nwindows was decremented.
|
||||||
|
bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||||
{
|
{
|
||||||
bool unload_buf = (action != 0);
|
bool unload_buf = (action != 0);
|
||||||
bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
|
bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
|
||||||
@ -444,7 +445,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
|||||||
// halfway a command that relies on it). Unloading is allowed.
|
// halfway a command that relies on it). Unloading is allowed.
|
||||||
if (buf->b_locked > 0 && (del_buf || wipe_buf)) {
|
if (buf->b_locked > 0 && (del_buf || wipe_buf)) {
|
||||||
EMSG(_("E937: Attempt to delete a buffer that is in use"));
|
EMSG(_("E937: Attempt to delete a buffer that is in use"));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (win != NULL // Avoid bogus clang warning.
|
if (win != NULL // Avoid bogus clang warning.
|
||||||
@ -471,13 +472,13 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
|||||||
buf) && !bufref_valid(&bufref)) {
|
buf) && !bufref_valid(&bufref)) {
|
||||||
// Autocommands deleted the buffer.
|
// Autocommands deleted the buffer.
|
||||||
EMSG(_(e_auabort));
|
EMSG(_(e_auabort));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
buf->b_locked--;
|
buf->b_locked--;
|
||||||
if (abort_if_last && last_nonfloat(win)) {
|
if (abort_if_last && last_nonfloat(win)) {
|
||||||
// Autocommands made this the only window.
|
// Autocommands made this the only window.
|
||||||
EMSG(_(e_auabort));
|
EMSG(_(e_auabort));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the buffer becomes hidden, but is not unloaded, trigger
|
// When the buffer becomes hidden, but is not unloaded, trigger
|
||||||
@ -488,17 +489,17 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
|||||||
buf) && !bufref_valid(&bufref)) {
|
buf) && !bufref_valid(&bufref)) {
|
||||||
// Autocommands deleted the buffer.
|
// Autocommands deleted the buffer.
|
||||||
EMSG(_(e_auabort));
|
EMSG(_(e_auabort));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
buf->b_locked--;
|
buf->b_locked--;
|
||||||
if (abort_if_last && last_nonfloat(win)) {
|
if (abort_if_last && last_nonfloat(win)) {
|
||||||
// Autocommands made this the only window.
|
// Autocommands made this the only window.
|
||||||
EMSG(_(e_auabort));
|
EMSG(_(e_auabort));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (aborting()) { // autocmds may abort script processing
|
if (aborting()) { // autocmds may abort script processing
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,7 +526,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
|||||||
/* Return when a window is displaying the buffer or when it's not
|
/* Return when a window is displaying the buffer or when it's not
|
||||||
* unloaded. */
|
* unloaded. */
|
||||||
if (buf->b_nwindows > 0 || !unload_buf) {
|
if (buf->b_nwindows > 0 || !unload_buf) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf->terminal) {
|
if (buf->terminal) {
|
||||||
@ -561,11 +562,11 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
|||||||
|
|
||||||
if (!bufref_valid(&bufref)) {
|
if (!bufref_valid(&bufref)) {
|
||||||
// Autocommands may have deleted the buffer.
|
// Autocommands may have deleted the buffer.
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (aborting()) {
|
if (aborting()) {
|
||||||
// Autocmds may abort script processing.
|
// Autocmds may abort script processing.
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -576,7 +577,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
|||||||
* deleted buffer.
|
* deleted buffer.
|
||||||
*/
|
*/
|
||||||
if (buf == curbuf && !is_curbuf) {
|
if (buf == curbuf && !is_curbuf) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (win != NULL // Avoid bogus clang warning.
|
if (win != NULL // Avoid bogus clang warning.
|
||||||
@ -636,6 +637,8 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
|||||||
buf->b_p_bl = false;
|
buf->b_p_bl = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// NOTE: at this point "curbuf" may be invalid!
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make buffer not contain a file.
|
/// Make buffer not contain a file.
|
||||||
|
@ -2462,6 +2462,7 @@ int do_ecmd(
|
|||||||
auto_buf = true;
|
auto_buf = true;
|
||||||
} else {
|
} else {
|
||||||
win_T *the_curwin = curwin;
|
win_T *the_curwin = curwin;
|
||||||
|
buf_T *was_curbuf = curbuf;
|
||||||
|
|
||||||
// Set w_closing to avoid that autocommands close the window.
|
// Set w_closing to avoid that autocommands close the window.
|
||||||
// Set b_locked for the same reason.
|
// Set b_locked for the same reason.
|
||||||
@ -2475,9 +2476,10 @@ int do_ecmd(
|
|||||||
// Close the link to the current buffer. This will set
|
// Close the link to the current buffer. This will set
|
||||||
// oldwin->w_buffer to NULL.
|
// oldwin->w_buffer to NULL.
|
||||||
u_sync(false);
|
u_sync(false);
|
||||||
close_buffer(oldwin, curbuf,
|
const bool did_decrement = close_buffer(
|
||||||
(flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
|
oldwin, curbuf,
|
||||||
false);
|
(flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
|
||||||
|
false);
|
||||||
|
|
||||||
// Autocommands may have closed the window.
|
// Autocommands may have closed the window.
|
||||||
if (win_valid(the_curwin)) {
|
if (win_valid(the_curwin)) {
|
||||||
@ -2497,6 +2499,14 @@ int do_ecmd(
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
if (buf == curbuf) { // already in new buffer
|
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;
|
auto_buf = true;
|
||||||
} else {
|
} else {
|
||||||
// <VN> We could instead free the synblock
|
// <VN> We could instead free the synblock
|
||||||
|
@ -452,6 +452,27 @@ func Test_autocmd_bufwipe_in_SessLoadPost()
|
|||||||
endfor
|
endfor
|
||||||
endfunc
|
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 assert_match('OK', join(readfile('Xerrors')))
|
||||||
|
|
||||||
|
call delete('XblastBall')
|
||||||
|
call delete('Xerrors')
|
||||||
|
endfunc
|
||||||
|
|
||||||
" SEGV occurs in older versions.
|
" SEGV occurs in older versions.
|
||||||
func Test_autocmd_bufwipe_in_SessLoadPost2()
|
func Test_autocmd_bufwipe_in_SessLoadPost2()
|
||||||
tabnew
|
tabnew
|
||||||
|
Loading…
Reference in New Issue
Block a user