summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Brabandt <cb@256bit.org>2024-08-11 20:09:17 +0200
committerChristian Brabandt <cb@256bit.org>2024-08-11 20:09:17 +0200
commitfb3f9699362f8d51c3b48fcaea1eb2ed16c81454 (patch)
treefd915cb29431b76767b109e45909c103063f3583
parente20aeb875c5da145922696823d893de5f61807ae (diff)
Problem: crash with WinNewPre autocommandv9.1.0671
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>
-rw-r--r--runtime/doc/autocmd.txt8
-rw-r--r--src/testdir/crash/nullpointerbin0 -> 315 bytes
-rw-r--r--src/testdir/test_autocmd.vim63
-rw-r--r--src/testdir/test_crash.vim6
-rw-r--r--src/version.c2
-rw-r--r--src/window.c7
6 files changed, 66 insertions, 20 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 0461c0454e..f6d32db398 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 0000000000..c8ff3a4832
--- /dev/null
+++ b/src/testdir/crash/nullpointer
Binary files differ
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 26590ab33b..5a913514b2 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 9aef245026..800f3e5e64 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 03658333ac..ef1ffb0aeb 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 671,
+/**/
670,
/**/
669,
diff --git a/src/window.c b/src/window.c
index 70c72bca75..43a15e0561 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)
{