Bram Moolenaar
unread,Feb 7, 2021, 6:13:24 AM2/7/21Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to vim...@googlegroups.com
Patch 8.2.2476
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.
Files: src/buffer.c, src/window.c, src/errors.h, src/structs.h,
src/popupwin.c, src/testdir/test_autocmd.vim
*** ../vim-8.2.2475/src/buffer.c 2021-01-23 15:14:57.308269451 +0100
--- src/buffer.c 2021-02-06 23:21:35.680739843 +0100
***************
*** 595,600 ****
--- 595,601 ----
if (buf->b_nwindows == 1)
{
++buf->b_locked;
+ ++buf->b_locked_split;
if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
FALSE, buf)
&& !bufref_valid(&bufref))
***************
*** 605,610 ****
--- 606,612 ----
return FALSE;
}
--buf->b_locked;
+ --buf->b_locked_split;
if (abort_if_last && one_window())
// Autocommands made this the only window.
goto aucmd_abort;
***************
*** 614,625 ****
--- 616,629 ----
if (!unload_buf)
{
++buf->b_locked;
+ ++buf->b_locked_split;
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;
+ --buf->b_locked_split;
if (abort_if_last && one_window())
// Autocommands made this the only window.
goto aucmd_abort;
***************
*** 800,805 ****
--- 804,810 ----
// Make sure the buffer isn't closed by autocommands.
++buf->b_locked;
+ ++buf->b_locked_split;
set_bufref(&bufref, buf);
if (buf->b_ml.ml_mfp != NULL)
{
***************
*** 826,831 ****
--- 831,837 ----
return;
}
--buf->b_locked;
+ --buf->b_locked_split;
// 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
***************
*** 1718,1725 ****
set_bufref(&prevbufref, prevbuf);
set_bufref(&newbufref, buf);
! // Autocommands may delete the current buffer and/or the buffer we want to go
! // to. In those cases don't close the buffer.
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
|| (bufref_valid(&prevbufref)
&& bufref_valid(&newbufref)
--- 1724,1731 ----
set_bufref(&prevbufref, prevbuf);
set_bufref(&newbufref, buf);
! // Autocommands may delete the current buffer and/or the buffer we want to
! // go to. In those cases don't close the buffer.
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
|| (bufref_valid(&prevbufref)
&& bufref_valid(&newbufref)
*** ../vim-8.2.2475/src/window.c 2020-12-29 12:46:47.662457054 +0100
--- src/window.c 2021-02-06 23:23:10.616459822 +0100
***************
*** 769,774 ****
--- 769,779 ----
emsg(_("E242: Can't split a window while closing another"));
return FAIL;
}
+ if (curwin->w_buffer->b_locked_split)
+ {
+ emsg(_(e_cannot_split_window_when_closing_buffer));
+ return FAIL;
+ }
return OK;
}
***************
*** 793,798 ****
--- 798,806 ----
if (ERROR_IF_ANY_POPUP_WINDOW)
return FAIL;
+ if (check_split_disallowed() == FAIL)
+ return FAIL;
+
// When the ":tab" modifier was used open a new tab page instead.
if (may_open_tabpage() == OK)
return OK;
***************
*** 804,811 ****
emsg(_("E442: Can't split topleft and botright at the same time"));
return FAIL;
}
- if (check_split_disallowed() == FAIL)
- return FAIL;
// When creating the help window make a snapshot of the window layout.
// Otherwise clear the snapshot, it's now invalid.
--- 812,817 ----
*** ../vim-8.2.2475/src/errors.h 2021-02-01 20:14:44.566705066 +0100
--- src/errors.h 2021-02-06 22:41:30.771750526 +0100
***************
*** 353,355 ****
--- 353,357 ----
INIT(= N_("E1157: Missing return type"));
EXTERN char e_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"));
*** ../vim-8.2.2475/src/structs.h 2021-01-31 14:45:56.925141860 +0100
--- src/structs.h 2021-02-06 23:19:56.601032025 +0100
***************
*** 2633,2638 ****
--- 2633,2640 ----
int b_flags; // various BF_ flags
int b_locked; // Buffer is being closed or referenced, don't
// 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).
*** ../vim-8.2.2475/src/popupwin.c 2021-02-06 14:59:21.126120022 +0100
--- src/popupwin.c 2021-02-06 23:22:18.660613080 +0100
***************
*** 1941,1947 ****
buf->b_p_ul = -1; // no undo
buf->b_p_swf = FALSE; // no swap file
buf->b_p_bl = FALSE; // unlisted buffer
! buf->b_locked = TRUE;
// Avoid that 'buftype' is reset when this buffer is entered.
buf->b_p_initialized = TRUE;
--- 1941,1947 ----
buf->b_p_ul = -1; // no undo
buf->b_p_swf = FALSE; // no swap file
buf->b_p_bl = FALSE; // unlisted buffer
! buf->b_locked = TRUE; // prevent deleting the buffer
// Avoid that 'buftype' is reset when this buffer is entered.
buf->b_p_initialized = TRUE;
*** ../vim-8.2.2475/src/testdir/test_autocmd.vim 2021-02-06 19:28:42.108044822 +0100
--- src/testdir/test_autocmd.vim 2021-02-07 12:12:09.845326444 +0100
***************
*** 2761,2775 ****
" Fuzzer found some strange combination that caused a crash.
func Test_autocmd_normal_mess()
- " TODO: why does this hang on Windows?
- CheckNotMSWindows
-
augroup aucmd_normal_test
au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc
augroup END
! o4
silent! H
! e xx
normal G
augroup aucmd_normal_test
--- 2761,2772 ----
" Fuzzer found some strange combination that caused a crash.
func Test_autocmd_normal_mess()
augroup aucmd_normal_test
au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc
augroup END
! call assert_fails('o4', 'E1159')
silent! H
! call assert_fails('e xx', 'E1159')
normal G
augroup aucmd_normal_test
***************
*** 2791,2797 ****
au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * sb
au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * q9