1
0
forked from aniani/vim

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 <cb@256bit.org>
This commit is contained in:
Christian Brabandt
2024-08-11 20:09:17 +02:00
parent e20aeb875c
commit fb3f969936
6 changed files with 66 additions and 20 deletions

View File

@@ -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.

Binary file not shown.

View File

@@ -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

View File

@@ -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!

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
671,
/**/
670,
/**/

View File

@@ -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)
{