patch 9.2.0252: Crash when ending Visual mode after curbuf was unloaded

Problem:  if close_buffer() in set_curbuf() unloads curbuf, NULL pointer
          accesses may occur from enter_buffer() calling
          end_visual_mode(), as curbuf is already abandoned and possibly
          unloaded.  Also, selection registers may not contain the
          selection with clipboard+=autoselect(plus).
Solution: Move close_buffer()'s end_visual_mode() call to buf_freeall(), after
          any autocmds that may restart it, but just before freeing anything
          (Sean Dewar)

related: #19728

Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Sean Dewar
2026-03-26 20:05:31 +00:00
committed by Christian Brabandt
parent 68b3585e1d
commit a8fdfd4fcb
3 changed files with 68 additions and 10 deletions
+53
View File
@@ -2970,4 +2970,57 @@ func Test_getregionpos_block_linebreak_matches_getpos()
let &columns = save_columns
bw!
endfunc
func Test_visual_ended_in_wiped_buffer()
edit Xfoo
edit Xbar
setlocal bufhidden=wipe
augroup testing
autocmd BufWipeout * ++once normal! v
augroup END
" Must be the last window.
call assert_equal(1, winnr('$'))
call assert_equal(1, tabpagenr('$'))
" Was a member access on a NULL curbuf from Vim ending Visual mode.
buffer #
call assert_equal(0, bufexists('Xbar'))
call assert_equal('n', mode())
autocmd! testing
%bw!
endfunc
func Test_visual_ended_in_unloaded_buffer()
CheckFeature clipboard
CheckNotGui
set clipboard+=autoselect
edit Xfoo
edit Xbar
call setline(1, 'hi')
setlocal nomodified
let s:fired = 0
augroup testing
autocmd BufUnload Xbar call assert_equal('Xbar', bufname())
\| execute 'normal! V'
\| call assert_equal('V', mode())
" From Vim ending Visual mode. Used to occur too late, after the buffer was
" unloaded, so @* didn't contain the selection. Window also had a NULL
" w_buffer here!
autocmd TextYankPost * ++once let s:fired = 1
\| if has('clipboard_working') | call assert_equal("hi\n", @*) | endif
\| call tabpagebuflist() " was a NULL member access on w_buffer
augroup END
buffer Xfoo
call assert_equal(0, bufloaded('Xbar'))
call assert_equal('n', mode())
call assert_equal(1, s:fired)
autocmd! testing
unlet! s:fired
set clipboard&
%bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab