mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 8.2.2476: using freed memory when splitting window while closing buffer
Problem: Using freed memory when using an autocommand to split a window while a buffer is being closed. Solution: Disallow splitting when the buffer has b_locked_split set.
This commit is contained in:
10
src/buffer.c
10
src/buffer.c
@@ -595,6 +595,7 @@ close_buffer(
|
|||||||
if (buf->b_nwindows == 1)
|
if (buf->b_nwindows == 1)
|
||||||
{
|
{
|
||||||
++buf->b_locked;
|
++buf->b_locked;
|
||||||
|
++buf->b_locked_split;
|
||||||
if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
|
if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
|
||||||
FALSE, buf)
|
FALSE, buf)
|
||||||
&& !bufref_valid(&bufref))
|
&& !bufref_valid(&bufref))
|
||||||
@@ -605,6 +606,7 @@ aucmd_abort:
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
--buf->b_locked;
|
--buf->b_locked;
|
||||||
|
--buf->b_locked_split;
|
||||||
if (abort_if_last && one_window())
|
if (abort_if_last && one_window())
|
||||||
// Autocommands made this the only window.
|
// Autocommands made this the only window.
|
||||||
goto aucmd_abort;
|
goto aucmd_abort;
|
||||||
@@ -614,12 +616,14 @@ aucmd_abort:
|
|||||||
if (!unload_buf)
|
if (!unload_buf)
|
||||||
{
|
{
|
||||||
++buf->b_locked;
|
++buf->b_locked;
|
||||||
|
++buf->b_locked_split;
|
||||||
if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
|
if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
|
||||||
FALSE, buf)
|
FALSE, buf)
|
||||||
&& !bufref_valid(&bufref))
|
&& !bufref_valid(&bufref))
|
||||||
// Autocommands deleted the buffer.
|
// Autocommands deleted the buffer.
|
||||||
goto aucmd_abort;
|
goto aucmd_abort;
|
||||||
--buf->b_locked;
|
--buf->b_locked;
|
||||||
|
--buf->b_locked_split;
|
||||||
if (abort_if_last && one_window())
|
if (abort_if_last && one_window())
|
||||||
// Autocommands made this the only window.
|
// Autocommands made this the only window.
|
||||||
goto aucmd_abort;
|
goto aucmd_abort;
|
||||||
@@ -800,6 +804,7 @@ buf_freeall(buf_T *buf, int flags)
|
|||||||
|
|
||||||
// Make sure the buffer isn't closed by autocommands.
|
// Make sure the buffer isn't closed by autocommands.
|
||||||
++buf->b_locked;
|
++buf->b_locked;
|
||||||
|
++buf->b_locked_split;
|
||||||
set_bufref(&bufref, buf);
|
set_bufref(&bufref, buf);
|
||||||
if (buf->b_ml.ml_mfp != NULL)
|
if (buf->b_ml.ml_mfp != NULL)
|
||||||
{
|
{
|
||||||
@@ -826,6 +831,7 @@ buf_freeall(buf_T *buf, int flags)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
--buf->b_locked;
|
--buf->b_locked;
|
||||||
|
--buf->b_locked_split;
|
||||||
|
|
||||||
// If the buffer was in curwin and the window has changed, go back to that
|
// If the buffer was in curwin and the window has changed, go back to that
|
||||||
// window, if it still exists. This avoids that ":edit x" triggering a
|
// window, if it still exists. This avoids that ":edit x" triggering a
|
||||||
@@ -1718,8 +1724,8 @@ set_curbuf(buf_T *buf, int action)
|
|||||||
set_bufref(&prevbufref, prevbuf);
|
set_bufref(&prevbufref, prevbuf);
|
||||||
set_bufref(&newbufref, buf);
|
set_bufref(&newbufref, buf);
|
||||||
|
|
||||||
// Autocommands may delete the current buffer and/or the buffer we want to go
|
// Autocommands may delete the current buffer and/or the buffer we want to
|
||||||
// to. In those cases don't close the buffer.
|
// go to. In those cases don't close the buffer.
|
||||||
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
|
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
|
||||||
|| (bufref_valid(&prevbufref)
|
|| (bufref_valid(&prevbufref)
|
||||||
&& bufref_valid(&newbufref)
|
&& bufref_valid(&newbufref)
|
||||||
|
@@ -353,3 +353,5 @@ EXTERN char e_missing_return_type[]
|
|||||||
INIT(= N_("E1157: Missing return type"));
|
INIT(= N_("E1157: Missing return type"));
|
||||||
EXTERN char e_cannot_use_flatten_in_vim9_script[]
|
EXTERN char e_cannot_use_flatten_in_vim9_script[]
|
||||||
INIT(= N_("E1158: Cannot use flatten() in Vim9 script"));
|
INIT(= N_("E1158: Cannot use flatten() in Vim9 script"));
|
||||||
|
EXTERN char e_cannot_split_window_when_closing_buffer[]
|
||||||
|
INIT(= N_("E1159: Cannot split a window when closing the buffer"));
|
||||||
|
@@ -1941,7 +1941,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
|
|||||||
buf->b_p_ul = -1; // no undo
|
buf->b_p_ul = -1; // no undo
|
||||||
buf->b_p_swf = FALSE; // no swap file
|
buf->b_p_swf = FALSE; // no swap file
|
||||||
buf->b_p_bl = FALSE; // unlisted buffer
|
buf->b_p_bl = FALSE; // unlisted buffer
|
||||||
buf->b_locked = TRUE;
|
buf->b_locked = TRUE; // prevent deleting the buffer
|
||||||
|
|
||||||
// Avoid that 'buftype' is reset when this buffer is entered.
|
// Avoid that 'buftype' is reset when this buffer is entered.
|
||||||
buf->b_p_initialized = TRUE;
|
buf->b_p_initialized = TRUE;
|
||||||
|
@@ -2633,6 +2633,8 @@ struct file_buffer
|
|||||||
int b_flags; // various BF_ flags
|
int b_flags; // various BF_ flags
|
||||||
int b_locked; // Buffer is being closed or referenced, don't
|
int b_locked; // Buffer is being closed or referenced, don't
|
||||||
// let autocommands wipe it out.
|
// let autocommands wipe it out.
|
||||||
|
int b_locked_split; // Buffer is being closed, don't allow opening
|
||||||
|
// a new window with it.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* b_ffname has the full path of the file (NULL for no name).
|
* b_ffname has the full path of the file (NULL for no name).
|
||||||
|
@@ -2761,15 +2761,12 @@ endfunc
|
|||||||
|
|
||||||
" Fuzzer found some strange combination that caused a crash.
|
" Fuzzer found some strange combination that caused a crash.
|
||||||
func Test_autocmd_normal_mess()
|
func Test_autocmd_normal_mess()
|
||||||
" TODO: why does this hang on Windows?
|
|
||||||
CheckNotMSWindows
|
|
||||||
|
|
||||||
augroup aucmd_normal_test
|
augroup aucmd_normal_test
|
||||||
au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc
|
au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc
|
||||||
augroup END
|
augroup END
|
||||||
o4
|
call assert_fails('o4', 'E1159')
|
||||||
silent! H
|
silent! H
|
||||||
e xx
|
call assert_fails('e xx', 'E1159')
|
||||||
normal G
|
normal G
|
||||||
|
|
||||||
augroup aucmd_normal_test
|
augroup aucmd_normal_test
|
||||||
@@ -2791,7 +2788,7 @@ func Test_autocmd_vimgrep()
|
|||||||
au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * sb
|
au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * sb
|
||||||
au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * q9 |