Problem: crash with WinNewPre autocommand Commit: https://github.com/vim/vim/commit/fb3f9699362f8d51c3b48fcaea1eb2ed16c81454 Author: Christian Brabandt <c...@256bit.org> Date: Sun Aug 11 20:09:17 2024 +0200
Problem: crash with WinNewPre autocommand Problem: crash with WinNewPre autocommand, because window structures are not yet safe to use Solution: Don't trigger WinNewPre on :tabnew Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 0461c0454..f6d32db39 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -1,4 +1,4 @@ -*autocmd.txt* For Vim version 9.1. Last change: 2024 Jul 17 +*autocmd.txt* For Vim version 9.1. Last change: 2024 Aug 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1427,8 +1427,10 @@ WinLeave Before leaving a window. If the window to be *WinNewPre* WinNewPre Before creating a new window. Triggered before commands that modify window layout by - creating a split or new tab page. Not done for - the first window, when Vim has just started. + creating a split. + Not done for creating tabs or for the first + window, as the window structure is not + initialized yet and so is generally not safe. It is not allowed to modify window layout while executing commands for the WinNewPre event. diff --git a/src/testdir/crash/nullpointer b/src/testdir/crash/nullpointer new file mode 100644 index 0000000000000000000000000000000000000000..c8ff3a4832f3c9ff253315c61e9b9bf997c11038 GIT binary patch literal 315 zcmZ3;Ra9g(nJYCeEu~e*FjbrZ2pnU$?Cov2bhuLaxk?Ng>N88*Wf@fR@{4k%Z3S4> zV-4-??UT54z#@_=Dk_Cmg@uJyK#*8kq5uROJP=YqKtKnGLBOdrEhsfHg;R@DK>%cs zqz#%jcAz$hQUONZ{L%tn1CXU37`T!QxqyI?Aum5UCpB@h3W%2<7gKGhV+aHWwVg3Q z5C_CED*qFcQn^YJlQ>g~{&5N#E#xY)ss*Zk#mU8`2-3z~5A+<DXh{axmq0(FdBYOw d4Uku?tR`|5rKV@*LpWubxt4|yCXj^q695*hO)3BY literal 0 HcmV?d00001 diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 26590ab33..5a913514b 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -14,6 +14,13 @@ func s:cleanup_buffers() abort endfor endfunc +func CleanUpTestAuGroup() + augroup testing + au! + augroup END + augroup! testing +endfunc + func Test_vim_did_enter() call assert_false(v:vim_did_enter) @@ -269,6 +276,7 @@ endfunc func Test_win_tab_autocmd() let g:record = [] + defer CleanUpTestAuGroup() augroup testing au WinNewPre * call add(g:record, 'WinNewPre') au WinNew * call add(g:record, 'WinNew') @@ -288,7 +296,7 @@ func Test_win_tab_autocmd() call assert_equal([ \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter', - \ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', + \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter', \ 'WinLeave', 'WinClosed', 'WinEnter' \ ], g:record) @@ -299,7 +307,7 @@ func Test_win_tab_autocmd() bwipe somefile call assert_equal([ - \ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', + \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', \ 'WinClosed', 'TabClosed' \ ], g:record) @@ -316,9 +324,6 @@ func Test_win_tab_autocmd() \ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter' \ ], g:record) - augroup testing - au! - augroup END unlet g:record endfunc @@ -330,17 +335,15 @@ func Test_WinNewPre() au WinNewPre * call add(g:layouts_pre, winlayout()) au WinNew * call add(g:layouts_post, winlayout()) augroup END + defer CleanUpTestAuGroup() split call assert_notequal(g:layouts_pre[0], g:layouts_post[0]) split call assert_equal(g:layouts_pre[1], g:layouts_post[0]) call assert_notequal(g:layouts_pre[1], g:layouts_post[1]) + " not triggered for tabnew tabnew - call assert_notequal(g:layouts_pre[2], g:layouts_post[1]) - call assert_notequal(g:layouts_pre[2], g:layouts_post[2]) - augroup testing - au! - augroup END + call assert_equal(2, len(g:layouts_pre)) unlet g:layouts_pre unlet g:layouts_post @@ -383,9 +386,6 @@ func Test_WinNewPre() let g:caught += 1 endtry call assert_equal(4, g:caught) - augroup testing - au! - augroup END unlet g:caught endfunc @@ -2807,7 +2807,8 @@ endfunc func Test_autocmd_nested() let g:did_nested = 0 - augroup Testing + defer CleanUpTestAuGroup() + augroup testing au WinNew * edit somefile au BufNew * let g:did_nested = 1 augroup END @@ -2817,7 +2818,7 @@ func Test_autocmd_nested() bwipe! somefile " old nested argument still works - augroup Testing + augroup testing au! au WinNew * nested edit somefile au BufNew * let g:did_nested = 1 @@ -4831,4 +4832,36 @@ func Test_KeyInputPre() au! KeyInputPre endfunc +" those commands caused null pointer access, see #15464 +func Test_WinNewPre_crash() + defer CleanUpTestAuGroup() + let _cmdheight=&cmdheight + augroup testing + au! + autocmd WinNewPre * redraw + augroup END + tabnew + tabclose + augroup testing + au! + autocmd WinNewPre * wincmd t + augroup END + tabnew + tabclose + augroup testing + au! + autocmd WinNewPre * wincmd b + augroup END + tabnew + tabclose + augroup testing + au! + autocmd WinNewPre * set cmdheight+=1 + augroup END + tabnew + tabclose + let &cmdheight=_cmdheight +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_crash.vim b/src/testdir/test_crash.vim index 9aef24502..800f3e5e6 100644 --- a/src/testdir/test_crash.vim +++ b/src/testdir/test_crash.vim @@ -202,6 +202,12 @@ func Test_crash1_3() call term_sendkeys(buf, args) call TermWait(buf, 150) + let file = 'crash/nullpointer' + let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>" + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args) + call TermWait(buf, 50) + " clean up exe buf .. "bw!" bw! diff --git a/src/version.c b/src/version.c index 03658333a..ef1ffb0ae 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 671, /**/ 670, /**/ diff --git a/src/window.c b/src/window.c index 70c72bca7..43a15e056 100644 --- a/src/window.c +++ b/src/window.c @@ -4607,6 +4607,11 @@ free_tabpage(tabpage_T *tp) * It will edit the current buffer, like after ":split". * When "after" is 0 put it just after the current Tab page. * Otherwise put it just before tab page "after". + * + * Does not trigger WinNewPre, since the window structures + * are not completly setup yet and could cause dereferencing + * NULL pointers + * * Return FAIL or OK. */ int @@ -4640,8 +4645,6 @@ win_new_tabpage(int after) newtp->tp_localdir = (tp->tp_localdir == NULL) ? NULL : vim_strsave(tp->tp_localdir); - trigger_winnewpre(); - // Create a new empty window. if (win_alloc_firstwin(tp->tp_curwin) == OK) { -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/vim_dev/E1sdD5t-00CWwA-SY%40256bit.org.