mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	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:
		| @@ -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 | 		  VIM REFERENCE MANUAL    by Bram Moolenaar | ||||||
| @@ -1427,8 +1427,10 @@ WinLeave			Before leaving a window.  If the window to be | |||||||
| 							*WinNewPre* | 							*WinNewPre* | ||||||
| WinNewPre			Before creating a new window. Triggered | WinNewPre			Before creating a new window. Triggered | ||||||
| 				before commands that modify window layout by | 				before commands that modify window layout by | ||||||
| 				creating a split or new tab page. Not done for | 				creating a split. | ||||||
| 				the first window, when Vim has just started. | 				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 | 				It is not allowed to modify window layout | ||||||
| 				while executing commands for the WinNewPre | 				while executing commands for the WinNewPre | ||||||
| 				event. | 				event. | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								src/testdir/crash/nullpointer
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/testdir/crash/nullpointer
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -14,6 +14,13 @@ func s:cleanup_buffers() abort | |||||||
|   endfor |   endfor | ||||||
| endfunc | endfunc | ||||||
|  |  | ||||||
|  | func CleanUpTestAuGroup() | ||||||
|  |   augroup testing | ||||||
|  |     au! | ||||||
|  |   augroup END | ||||||
|  |   augroup! testing | ||||||
|  | endfunc | ||||||
|  |  | ||||||
| func Test_vim_did_enter() | func Test_vim_did_enter() | ||||||
|   call assert_false(v:vim_did_enter) |   call assert_false(v:vim_did_enter) | ||||||
|  |  | ||||||
| @@ -269,6 +276,7 @@ endfunc | |||||||
| func Test_win_tab_autocmd() | func Test_win_tab_autocmd() | ||||||
|   let g:record = [] |   let g:record = [] | ||||||
|  |  | ||||||
|  |   defer CleanUpTestAuGroup() | ||||||
|   augroup testing |   augroup testing | ||||||
|     au WinNewPre * call add(g:record, 'WinNewPre') |     au WinNewPre * call add(g:record, 'WinNewPre') | ||||||
|     au WinNew * call add(g:record, 'WinNew') |     au WinNew * call add(g:record, 'WinNew') | ||||||
| @@ -288,7 +296,7 @@ func Test_win_tab_autocmd() | |||||||
|  |  | ||||||
|   call assert_equal([ |   call assert_equal([ | ||||||
| 	\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter', | 	\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter', | ||||||
| 	\ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', | 	\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', | ||||||
| 	\ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter', | 	\ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter', | ||||||
| 	\ 'WinLeave', 'WinClosed', 'WinEnter' | 	\ 'WinLeave', 'WinClosed', 'WinEnter' | ||||||
| 	\ ], g:record) | 	\ ], g:record) | ||||||
| @@ -299,7 +307,7 @@ func Test_win_tab_autocmd() | |||||||
|   bwipe somefile |   bwipe somefile | ||||||
|  |  | ||||||
|   call assert_equal([ |   call assert_equal([ | ||||||
| 	\ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', | 	\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter', | ||||||
| 	\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', | 	\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', | ||||||
| 	\ 'WinClosed', 'TabClosed' | 	\ 'WinClosed', 'TabClosed' | ||||||
| 	\ ], g:record) | 	\ ], g:record) | ||||||
| @@ -316,9 +324,6 @@ func Test_win_tab_autocmd() | |||||||
| 	\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter' | 	\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter' | ||||||
| 	\ ], g:record) | 	\ ], g:record) | ||||||
|  |  | ||||||
|   augroup testing |  | ||||||
|     au! |  | ||||||
|   augroup END |  | ||||||
|   unlet g:record |   unlet g:record | ||||||
| endfunc | endfunc | ||||||
|  |  | ||||||
| @@ -330,17 +335,15 @@ func Test_WinNewPre() | |||||||
|     au WinNewPre * call add(g:layouts_pre, winlayout()) |     au WinNewPre * call add(g:layouts_pre, winlayout()) | ||||||
|     au WinNew * call add(g:layouts_post, winlayout()) |     au WinNew * call add(g:layouts_post, winlayout()) | ||||||
|   augroup END |   augroup END | ||||||
|  |   defer CleanUpTestAuGroup() | ||||||
|   split |   split | ||||||
|   call assert_notequal(g:layouts_pre[0], g:layouts_post[0]) |   call assert_notequal(g:layouts_pre[0], g:layouts_post[0]) | ||||||
|   split |   split | ||||||
|   call assert_equal(g:layouts_pre[1], g:layouts_post[0]) |   call assert_equal(g:layouts_pre[1], g:layouts_post[0]) | ||||||
|   call assert_notequal(g:layouts_pre[1], g:layouts_post[1]) |   call assert_notequal(g:layouts_pre[1], g:layouts_post[1]) | ||||||
|  |   " not triggered for tabnew | ||||||
|   tabnew |   tabnew | ||||||
|   call assert_notequal(g:layouts_pre[2], g:layouts_post[1]) |   call assert_equal(2, len(g:layouts_pre)) | ||||||
|   call assert_notequal(g:layouts_pre[2], g:layouts_post[2]) |  | ||||||
|   augroup testing |  | ||||||
|     au! |  | ||||||
|   augroup END |  | ||||||
|   unlet g:layouts_pre |   unlet g:layouts_pre | ||||||
|   unlet g:layouts_post |   unlet g:layouts_post | ||||||
|  |  | ||||||
| @@ -383,9 +386,6 @@ func Test_WinNewPre() | |||||||
|     let g:caught += 1 |     let g:caught += 1 | ||||||
|   endtry |   endtry | ||||||
|   call assert_equal(4, g:caught) |   call assert_equal(4, g:caught) | ||||||
|   augroup testing |  | ||||||
|     au! |  | ||||||
|   augroup END |  | ||||||
|   unlet g:caught |   unlet g:caught | ||||||
| endfunc | endfunc | ||||||
|  |  | ||||||
| @@ -2807,7 +2807,8 @@ endfunc | |||||||
|  |  | ||||||
| func Test_autocmd_nested() | func Test_autocmd_nested() | ||||||
|   let g:did_nested = 0 |   let g:did_nested = 0 | ||||||
|   augroup Testing |   defer CleanUpTestAuGroup() | ||||||
|  |   augroup testing | ||||||
|     au WinNew * edit somefile |     au WinNew * edit somefile | ||||||
|     au BufNew * let g:did_nested = 1 |     au BufNew * let g:did_nested = 1 | ||||||
|   augroup END |   augroup END | ||||||
| @@ -2817,7 +2818,7 @@ func Test_autocmd_nested() | |||||||
|   bwipe! somefile |   bwipe! somefile | ||||||
|  |  | ||||||
|   " old nested argument still works |   " old nested argument still works | ||||||
|   augroup Testing |   augroup testing | ||||||
|     au! |     au! | ||||||
|     au WinNew * nested edit somefile |     au WinNew * nested edit somefile | ||||||
|     au BufNew * let g:did_nested = 1 |     au BufNew * let g:did_nested = 1 | ||||||
| @@ -4831,4 +4832,36 @@ func Test_KeyInputPre() | |||||||
|   au! KeyInputPre |   au! KeyInputPre | ||||||
| endfunc | 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 | " vim: shiftwidth=2 sts=2 expandtab | ||||||
|   | |||||||
| @@ -202,6 +202,12 @@ func Test_crash1_3() | |||||||
|   call term_sendkeys(buf, args) |   call term_sendkeys(buf, args) | ||||||
|   call TermWait(buf, 150) |   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 |   " clean up | ||||||
|   exe buf .. "bw!" |   exe buf .. "bw!" | ||||||
|   bw! |   bw! | ||||||
|   | |||||||
| @@ -704,6 +704,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     671, | ||||||
| /**/ | /**/ | ||||||
|     670, |     670, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
| @@ -4607,6 +4607,11 @@ free_tabpage(tabpage_T *tp) | |||||||
|  * It will edit the current buffer, like after ":split". |  * It will edit the current buffer, like after ":split". | ||||||
|  * When "after" is 0 put it just after the current Tab page. |  * When "after" is 0 put it just after the current Tab page. | ||||||
|  * Otherwise put it just before tab page "after". |  * 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. |  * Return FAIL or OK. | ||||||
|  */ |  */ | ||||||
|     int |     int | ||||||
| @@ -4640,8 +4645,6 @@ win_new_tabpage(int after) | |||||||
|     newtp->tp_localdir = (tp->tp_localdir == NULL) |     newtp->tp_localdir = (tp->tp_localdir == NULL) | ||||||
| 				    ? NULL : vim_strsave(tp->tp_localdir); | 				    ? NULL : vim_strsave(tp->tp_localdir); | ||||||
|  |  | ||||||
|     trigger_winnewpre(); |  | ||||||
|  |  | ||||||
|     // Create a new empty window. |     // Create a new empty window. | ||||||
|     if (win_alloc_firstwin(tp->tp_curwin) == OK) |     if (win_alloc_firstwin(tp->tp_curwin) == OK) | ||||||
|     { |     { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user