From 9b10b4cc6463d901b893ad2d522c629d066607d5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Apr 2022 10:26:33 +0800 Subject: [PATCH 1/9] vim-patch:8.1.1756: autocommand that splits window messes up window layout Problem: Autocommand that splits window messes up window layout. Solution: Disallow splitting a window while closing one. In ":all" give an error when moving a window will not work. https://github.com/vim/vim/commit/1417c766f55e5959b31da488417b7d9b141404af Expected error number was changed to E242 in Vim in patch 8.2.1183, and patch 8.2.2420 (which has already been ported) made the test no longer throw E249 in Vim, so just use E242 in the test. --- src/nvim/buffer.c | 4 ++ src/nvim/testdir/test_window_cmd.vim | 5 ++- src/nvim/window.c | 57 ++++++++++++++++++++++++ test/functional/autocmd/autocmd_spec.lua | 12 ----- 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 4d914acea4..78426568b4 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4855,6 +4855,10 @@ void do_arg_all(int count, int forceit, int keep_tabs) if (keep_tabs) { new_curwin = wp; new_curtab = curtab; + } else if (wp->w_frame->fr_parent != curwin->w_frame->fr_parent) { + emsg(_("E249: window layout changed unexpectedly")); + i = count; + break; } else { win_move_after(wp, curwin); } diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim index ef6dec580f..798122dc5d 100644 --- a/src/nvim/testdir/test_window_cmd.vim +++ b/src/nvim/testdir/test_window_cmd.vim @@ -513,14 +513,15 @@ func Test_window_colon_command() endfunc func Test_access_freed_mem() + call assert_equal(&columns, winwidth(0)) " This was accessing freed memory (but with what events?) au BufEnter,BufLeave,WinEnter,WinLeave 0 vs xxx arg 0 argadd - all - all + call assert_fails("all", "E242:") au! bwipe xxx + call assert_equal(&columns, winwidth(0)) endfunc func Test_visual_cleared_after_window_split() diff --git a/src/nvim/window.c b/src/nvim/window.c index 2ca5128445..d1cc5f245a 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -74,6 +74,35 @@ typedef enum { static char *m_onlyone = N_("Already only one window"); +/// When non-zero splitting a window is forbidden. Used to avoid that nasty +/// autocommands mess up the window structure. +static int split_disallowed = 0; + +// #define WIN_DEBUG +#ifdef WIN_DEBUG +/// Call this method to log the current window layout. +static void log_frame_layout(frame_T *frame) +{ + DLOG("layout %s, wi: %d, he: %d, wwi: %d, whe: %d, id: %d", + frame->fr_layout == FR_LEAF ? "LEAF" : frame->fr_layout == FR_ROW ? "ROW" : "COL", + frame->fr_width, + frame->fr_height, + frame->fr_win == NULL ? -1 : frame->fr_win->w_width, + frame->fr_win == NULL ? -1 : frame->fr_win->w_height, + frame->fr_win == NULL ? -1 : frame->fr_win->w_id); + if (frame->fr_child != NULL) { + DLOG("children"); + log_frame_layout(frame->fr_child); + if (frame->fr_next != NULL) { + DLOG("END of children"); + } + } + if (frame->fr_next != NULL) { + log_frame_layout(frame->fr_next); + } +} +#endif + /// @return the current window, unless in the cmdline window and "prevwin" is /// set, then return "prevwin". win_T *prevwin_curwin(void) @@ -909,6 +938,17 @@ void ui_ext_win_viewport(win_T *wp) } } +/// If "split_disallowed" is set given an error and return FAIL. +/// Otherwise return OK. +static int check_split_disallowed(void) +{ + if (split_disallowed > 0) { + emsg(_("E242: Can't split a window while closing another")); + return FAIL; + } + return OK; +} + /* * split the current window, implements CTRL-W s and :split * @@ -937,6 +977,9 @@ int win_split(int size, int flags) 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. @@ -1886,6 +1929,9 @@ static void win_totop(int size, int flags) if (curwin == aucmd_win) { return; } + if (check_split_disallowed() == FAIL) { + return; + } if (curwin->w_floating) { ui_comp_remove_grid(&curwin->w_grid_alloc); @@ -1929,6 +1975,11 @@ void win_move_after(win_T *win1, win_T *win2) // check if there is something to do if (win2->w_next != win1) { + if (win1->w_frame->fr_parent != win2->w_frame->fr_parent) { + iemsg("INTERNAL: trying to move a window into another frame"); + return; + } + // may need move the status line, horizontal or vertical separator of the last window if (win1 == lastwin) { height = win1->w_prev->w_status_height; @@ -2742,6 +2793,10 @@ int win_close(win_T *win, bool free_buf, bool force) return FAIL; } + // Now we are really going to close the window. Disallow any autocommand + // to split a window to avoid trouble. + split_disallowed++; + // let terminal buffers know that this window dimensions may be ignored win->w_closing = true; @@ -2809,6 +2864,8 @@ int win_close(win_T *win, bool free_buf, bool force) } } + split_disallowed--; + /* * If last window has a status line now and we don't want one, * remove the status line. diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 6111654b5e..b8d2c9ec1d 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -548,18 +548,6 @@ describe('autocmd', function() neq({}, meths.get_autocmds { group = "filetypedetect" }) end) - it('should not access freed mem', function() - source [[ - au BufEnter,BufLeave,WinEnter,WinLeave 0 vs xxx - arg 0 - argadd - all - all - au! - bwipe xxx - ]] - end) - it('should allow comma-separated patterns', function() source [[ augroup TestingPatterns From fa15f2f9380433b4d22387ce313bd4735b960c4e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Apr 2022 09:18:39 +0800 Subject: [PATCH 2/9] vim-patch:8.2.2472: crash when using command line window in an autocommand Problem: Crash when using command line window in an autocommand. (houyunsong) Solution: Save and restore au_new_curbuf. https://github.com/vim/vim/commit/aad5f9d79a2b71e9d2581eace3652be156102b9d Nvim has removed :open, so use :edit in the test instead. --- src/nvim/ex_cmds.c | 8 ++++++-- src/nvim/testdir/test_autocmd.vim | 21 +++++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 61bd9571b5..e16537c192 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2497,16 +2497,19 @@ int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T new if (buf->b_fname != NULL) { new_name = vim_strsave(buf->b_fname); } + const bufref_T save_au_new_curbuf = au_new_curbuf; set_bufref(&au_new_curbuf, buf); apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf); cmdwin_type = save_cmdwin_type; if (!bufref_valid(&au_new_curbuf)) { // New buffer has been deleted. delbuf_msg(new_name); // Frees new_name. + au_new_curbuf = save_au_new_curbuf; goto theend; } if (aborting()) { // autocmds may abort script processing xfree(new_name); + au_new_curbuf = save_au_new_curbuf; goto theend; } if (buf == curbuf) { // already in new buffer @@ -2540,12 +2543,14 @@ int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T new // autocmds may abort script processing if (aborting() && curwin->w_buffer != NULL) { xfree(new_name); + au_new_curbuf = save_au_new_curbuf; goto theend; } // Be careful again, like above. if (!bufref_valid(&au_new_curbuf)) { // New buffer has been deleted. delbuf_msg(new_name); // Frees new_name. + au_new_curbuf = save_au_new_curbuf; goto theend; } if (buf == curbuf) { // already in new buffer @@ -2585,8 +2590,7 @@ int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T new did_get_winopts = true; } xfree(new_name); - au_new_curbuf.br_buf = NULL; - au_new_curbuf.br_buf_free_count = 0; + au_new_curbuf = save_au_new_curbuf; } curwin->w_pcmark.lnum = 1; diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 228145ec4d..7ad3c8c6ad 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2695,9 +2695,9 @@ func Test_autocmd_closes_window() au BufNew,BufWinLeave * e %e file yyy au BufNew,BufWinLeave * ball - call assert_fails('n xxx', 'E143:') + n xxx - bwipe % + %bwipe au! BufNew au! BufWinLeave endfunc @@ -2715,6 +2715,23 @@ func Test_autocmd_quit_psearch() augroup END endfunc +" 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 + " Nvim has removed :open + " o4 + e4 + silent! H + e xx + normal G + + augroup aucmd_normal_test + au! + augroup END +endfunc + func Test_autocmd_closing_cmdwin() au BufWinLeave * nested q call assert_fails("norm 7q?\n", 'E855:') From 69ac382a283c92c54fc40b0017688a60fe89a49c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Apr 2022 09:44:12 +0800 Subject: [PATCH 3/9] vim-patch:8.2.2474: using freed memory when window is closed by autocommand Problem: Using freed memory when window is closed by autocommand. (houyunsong) Solution: Check the window pointer is still valid. https://github.com/vim/vim/commit/2c7080bf1ceef4a7779644fd428b2386a0676794 Add missing comment from Vim patch 8.0.1420. Test fails. --- src/nvim/quickfix.c | 5 ++++- src/nvim/testdir/test_autocmd.vim | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index f8d2d37a91..a12fb70388 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2313,7 +2313,10 @@ static bool qflist_valid(win_T *wp, unsigned int qf_id) qf_info_T *qi = &ql_info; if (wp) { - qi = GET_LOC_LIST(wp); + if (!win_valid(wp)) { + return false; + } + qi = GET_LOC_LIST(wp); // Location list if (!qi) { return false; } diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 7ad3c8c6ad..6cfca21f71 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2741,6 +2741,19 @@ func Test_autocmd_closing_cmdwin() only endfunc +func Test_autocmd_vimgrep() + augroup aucmd_vimgrep + au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * sb + au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * q9 + augroup END + " TODO: if this is executed directly valgrind reports errors + call assert_fails('lv?a?', 'E926:') + + augroup aucmd_vimgrep + au! + augroup END +endfunc + func Test_bufwipeout_changes_window() " This should not crash, but we don't have any expectations about what " happens, changing window in BufWipeout has unpredictable results. From 407be5975db5dd63671397676eef0279662c603d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Apr 2022 10:03:57 +0800 Subject: [PATCH 4/9] vim-patch:8.2.2475: autocommand tests hangs on MS-Windows Problem: Autocommand tests hangs on MS-Windows. Solution: Skip one test. https://github.com/vim/vim/commit/dfc3db76b9de217542cc9258301c1b4818a51cd0 --- src/nvim/testdir/test_autocmd.vim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 6cfca21f71..b80b564470 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2717,6 +2717,9 @@ endfunc " 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 From 1664e3d4bcc122e6a3b064a3fe20fdc163f6ae9d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Apr 2022 10:05:02 +0800 Subject: [PATCH 5/9] vim-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. https://github.com/vim/vim/commit/983d83ff1cd796ff321074335fa53fbe7ac45a46 Put the error message in window.c. Cherry-pick a memory leak fix from Vim patch 8.2.0399. Test still fails. --- src/nvim/buffer.c | 10 ++++++++-- src/nvim/buffer_defs.h | 2 ++ src/nvim/ex_getln.c | 1 + src/nvim/testdir/test_autocmd.vim | 11 ++++------- src/nvim/window.c | 14 +++++++++++--- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 78426568b4..628e398fd4 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -466,6 +466,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i // When the buffer is no longer in a window, trigger BufWinLeave 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)) { // Autocommands deleted the buffer. @@ -473,6 +474,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i return false; } buf->b_locked--; + buf->b_locked_split--; if (abort_if_last && last_nonfloat(win)) { // Autocommands made this the only window. emsg(_(e_auabort)); @@ -483,6 +485,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i // BufHidden 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. @@ -490,6 +493,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i return false; } buf->b_locked--; + buf->b_locked_split--; if (abort_if_last && last_nonfloat(win)) { // Autocommands made this the only window. emsg(_(e_auabort)); @@ -678,6 +682,7 @@ void buf_freeall(buf_T *buf, int flags) // Make sure the buffer isn't closed by autocommands. buf->b_locked++; + buf->b_locked_split++; bufref_T bufref; set_bufref(&bufref, buf); @@ -703,6 +708,7 @@ void buf_freeall(buf_T *buf, int flags) 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 @@ -1466,8 +1472,8 @@ void set_curbuf(buf_T *buf, int action) 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. + // 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) && !aborting())) { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 4917a628ff..baa0d1f102 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -532,6 +532,8 @@ struct file_buffer { 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. int b_ro_locked; // Non-zero when the buffer can't be changed. // Used for FileChangedRO diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 91e93a236a..b7d75855d6 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -6376,6 +6376,7 @@ static int open_cmdwin(void) // Create a window for the command-line buffer. if (win_split((int)p_cwh, WSP_BOT) == FAIL) { beep_flush(); + ga_clear(&winsizes); return K_IGNORE; } cmdwin_type = get_cmdline_type(); diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index b80b564470..7320750cab 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2717,17 +2717,14 @@ endfunc " 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 " Nvim has removed :open - " o4 - e4 + " call assert_fails('o4', 'E1159') + call assert_fails('e4', 'E1159') silent! H - e xx + call assert_fails('e xx', 'E1159') normal G augroup aucmd_normal_test @@ -2749,7 +2746,7 @@ func Test_autocmd_vimgrep() au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * sb au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * q9 augroup END - " TODO: if this is executed directly valgrind reports errors + %bwipe! call assert_fails('lv?a?', 'E926:') augroup aucmd_vimgrep diff --git a/src/nvim/window.c b/src/nvim/window.c index d1cc5f245a..f68cfe4c9c 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -72,6 +72,9 @@ typedef enum { WEE_TRIGGER_LEAVE_AUTOCMDS = 0x10, } wee_flags_T; +static char e_cannot_split_window_when_closing_buffer[] + = N_("E1159: Cannot split a window when closing the buffer"); + static char *m_onlyone = N_("Already only one window"); /// When non-zero splitting a window is forbidden. Used to avoid that nasty @@ -946,6 +949,10 @@ static int check_split_disallowed(void) 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; } @@ -966,6 +973,10 @@ static int check_split_disallowed(void) */ int win_split(int size, int flags) { + 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; @@ -977,9 +988,6 @@ int win_split(int size, int flags) 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. From 69fc23ed9819f2640106ce38613ed6f0962ae926 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Apr 2022 11:09:20 +0800 Subject: [PATCH 6/9] vim-patch:8.2.2477: autocommand tests hang on MS-Windows Problem: Autocommand tests hang on MS-Windows. Solution: Skip a couple of tests. Fix file name. https://github.com/vim/vim/commit/dd07c02232e91ee963b91a4477179d4b9548b862 --- src/nvim/testdir/test_autocmd.vim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 7320750cab..12b6ab26bc 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2717,6 +2717,9 @@ endfunc " Fuzzer found some strange combination that caused a crash. func Test_autocmd_normal_mess() + " For unknown reason this hangs on MS-Windows + CheckNotMSWindows + augroup aucmd_normal_test au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc augroup END @@ -2733,6 +2736,9 @@ func Test_autocmd_normal_mess() endfunc func Test_autocmd_closing_cmdwin() + " For unknown reason this hangs on MS-Windows + CheckNotMSWindows + au BufWinLeave * nested q call assert_fails("norm 7q?\n", 'E855:') @@ -2747,7 +2753,7 @@ func Test_autocmd_vimgrep() au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * q9 augroup END %bwipe! - call assert_fails('lv?a?', 'E926:') + call assert_fails('lv ?a? foo', 'E926:') augroup aucmd_vimgrep au! From f531fb97ff5009d2ac279a83da9b9e911c350c89 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Apr 2022 11:11:39 +0800 Subject: [PATCH 7/9] vim-patch:8.2.4791: events triggered in different order when reusing buffer Problem: Autocmd events triggered in different order when reusing an empty buffer. Solution: Call buff_freeall() earlier. (Charlie Groves, closes vim/vim#10198) https://github.com/vim/vim/commit/fef4485ef58d5937b170c6dc69431359469fc9cd Test failure becomes very strange. --- src/nvim/buffer.c | 21 +++------------------ src/nvim/testdir/test_autocmd.vim | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 628e398fd4..30bd37fe7f 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1748,21 +1748,14 @@ buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum, int fl buf = curbuf; // It's like this buffer is deleted. Watch out for autocommands that // change curbuf! If that happens, allocate a new buffer anyway. - if (curbuf->b_p_bl) { - apply_autocmds(EVENT_BUFDELETE, NULL, NULL, false, curbuf); - } - if (buf == curbuf) { - apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, false, curbuf); + buf_freeall(buf, BFA_WIPE | BFA_DEL); + if (buf != curbuf) { // autocommands deleted the buffer! + return NULL; } if (aborting()) { // autocmds may abort script processing xfree(ffname); return NULL; } - if (buf == curbuf) { - // Make sure 'bufhidden' and 'buftype' are empty - clear_string_option(&buf->b_p_bh); - clear_string_option(&buf->b_p_bt); - } } if (buf != curbuf || curbuf == NULL) { buf = xcalloc(1, sizeof(buf_T)); @@ -1782,14 +1775,6 @@ buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum, int fl buf->b_wininfo = xcalloc(1, sizeof(wininfo_T)); if (buf == curbuf) { - // free all things allocated for this buffer - buf_freeall(buf, 0); - if (buf != curbuf) { // autocommands deleted the buffer! - return NULL; - } - if (aborting()) { // autocmds may abort script processing - return NULL; - } free_buffer_stuff(buf, kBffInitChangedtick); // delete local vars et al. // Init the options. diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 12b6ab26bc..5913032195 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2748,9 +2748,10 @@ func Test_autocmd_closing_cmdwin() endfunc func Test_autocmd_vimgrep() + %bwipe! augroup aucmd_vimgrep - au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * sb - au QuickfixCmdPre,BufNew,BufDelete,BufReadCmd * q9 + au QuickfixCmdPre,BufNew,BufReadCmd * sb + au QuickfixCmdPre,BufNew,BufReadCmd * q9 augroup END %bwipe! call assert_fails('lv ?a? foo', 'E926:') @@ -2795,4 +2796,22 @@ func Test_v_event_readonly() endfunc +func Test_noname_autocmd() + augroup test_noname_autocmd_group + autocmd! + autocmd BufEnter * call add(s:li, ["BufEnter", expand("")]) + autocmd BufDelete * call add(s:li, ["BufDelete", expand("")]) + autocmd BufLeave * call add(s:li, ["BufLeave", expand("")]) + autocmd BufUnload * call add(s:li, ["BufUnload", expand("")]) + autocmd BufWipeout * call add(s:li, ["BufWipeout", expand("")]) + augroup END + + let s:li = [] + edit foo + call assert_equal([['BufUnload', ''], ['BufDelete', ''], ['BufWipeout', ''], ['BufEnter', 'foo']], s:li) + + au! test_noname_autocmd_group + augroup! test_noname_autocmd_group +endfunc + " vim: shiftwidth=2 sts=2 expandtab From e69cb86750d0e4b91d226e827d1eae2a98639777 Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Wed, 23 Mar 2022 15:14:44 -0400 Subject: [PATCH 8/9] test: add a Lua functional test for NoName buffer event order --- test/functional/autocmd/autocmd_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index b8d2c9ec1d..90254b7415 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -60,6 +60,23 @@ describe('autocmd', function() eq(expected, eval('g:evs')) end) + it('first edit causes BufUnload on NoName', function() + local expected = { + {'BufUnload', ''}, + {'BufDelete', ''}, + {'BufWipeout', ''}, + {'BufEnter', 'testfile1'}, + } + command('let g:evs = []') + command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("")])') + command('autocmd BufDelete * :call add(g:evs, ["BufDelete", expand("")])') + command('autocmd BufLeave * :call add(g:evs, ["BufLeave", expand("")])') + command('autocmd BufUnload * :call add(g:evs, ["BufUnload", expand("")])') + command('autocmd BufWipeout * :call add(g:evs, ["BufWipeout", expand("")])') + command('edit testfile1') + eq(expected, eval('g:evs')) + end) + it('WinClosed is non-recursive', function() command('let g:triggered = 0') command('autocmd WinClosed * :let g:triggered+=1 | :bdelete 2') From 5e9afca1c19914cdf6f81685c7950ab180278b1f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 21 Apr 2022 18:28:37 +0800 Subject: [PATCH 9/9] vim-patch:8.2.4802: test is not cleaned up Problem: Test is not cleaned up. Solution: Make test clean up after itself. Avoid NUL. (closes vim/vim#10233) https://github.com/vim/vim/commit/7851c69a120ea6ce8c122dd7198adbe5aec83ea5 Adapt test_autocmd_vimgrep() to Nvim. --- src/nvim/testdir/test_autocmd.vim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 5913032195..13be82a71d 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2713,6 +2713,8 @@ func Test_autocmd_quit_psearch() augroup aucmd_win_test au! augroup END + new + pclose endfunc " Fuzzer found some strange combination that caused a crash. @@ -2748,12 +2750,12 @@ func Test_autocmd_closing_cmdwin() endfunc func Test_autocmd_vimgrep() - %bwipe! augroup aucmd_vimgrep au QuickfixCmdPre,BufNew,BufReadCmd * sb - au QuickfixCmdPre,BufNew,BufReadCmd * q9 + " Nvim makes aucmd_win the last window + " au QuickfixCmdPre,BufNew,BufReadCmd * q9 + au QuickfixCmdPre,BufNew,BufReadCmd * exe 'q' .. (winnr('$') - (win_gettype(winnr('$')) == 'autocmd')) augroup END - %bwipe! call assert_fails('lv ?a? foo', 'E926:') augroup aucmd_vimgrep