vim-patch:8.2.4739: accessing freed memory after WinScrolled autocmd event (#18090)

Problem:    Accessing freed memory after WinScrolled autocmd event.
Solution:   Check the window pointer is still valid. (closes vim/vim#10156)
            Remove the argument from may_trigger_winscrolled().
d58862d18f
This commit is contained in:
zeertzjq 2022-04-12 19:16:47 +08:00 committed by GitHub
parent dbd5242d8e
commit 7e1e906738
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 20 deletions

View File

@ -1545,7 +1545,7 @@ static void ins_redraw(bool ready)
if (ready) { if (ready) {
// Trigger Scroll if viewport changed. // Trigger Scroll if viewport changed.
may_trigger_winscrolled(curwin); may_trigger_winscrolled();
} }
// Trigger BufModified if b_changed_invalid is set. // Trigger BufModified if b_changed_invalid is set.

View File

@ -1225,7 +1225,7 @@ static void normal_check_window_scrolled(NormalState *s)
{ {
if (!finish_op) { if (!finish_op) {
// Trigger Scroll if the viewport changed. // Trigger Scroll if the viewport changed.
may_trigger_winscrolled(curwin); may_trigger_winscrolled();
} }
} }

View File

@ -265,17 +265,17 @@ func Test_WinScrolled()
CheckRunVimInTerminal CheckRunVimInTerminal
let lines =<< trim END let lines =<< trim END
set nowrap scrolloff=0 set nowrap scrolloff=0
for ii in range(1, 18) for ii in range(1, 18)
call setline(ii, repeat(nr2char(96 + ii), ii * 2)) call setline(ii, repeat(nr2char(96 + ii), ii * 2))
endfor endfor
let win_id = win_getid() let win_id = win_getid()
let g:matched = v:false let g:matched = v:false
execute 'au WinScrolled' win_id 'let g:matched = v:true' execute 'au WinScrolled' win_id 'let g:matched = v:true'
let g:scrolled = 0 let g:scrolled = 0
au WinScrolled * let g:scrolled += 1 au WinScrolled * let g:scrolled += 1
au WinScrolled * let g:amatch = str2nr(expand('<amatch>')) au WinScrolled * let g:amatch = str2nr(expand('<amatch>'))
au WinScrolled * let g:afile = str2nr(expand('<afile>')) au WinScrolled * let g:afile = str2nr(expand('<afile>'))
END END
call writefile(lines, 'Xtest_winscrolled') call writefile(lines, 'Xtest_winscrolled')
let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6}) let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6})
@ -315,6 +315,30 @@ func Test_WinScrolled()
call delete('Xtest_winscrolled') call delete('Xtest_winscrolled')
endfunc endfunc
func Test_WinScrolled_close_curwin()
CheckRunVimInTerminal
let lines =<< trim END
set nowrap scrolloff=0
call setline(1, ['aaa', 'bbb'])
vsplit
au WinScrolled * close
au VimLeave * call writefile(['123456'], 'Xtestout')
END
call writefile(lines, 'Xtest_winscrolled_close_curwin')
let buf = RunVimInTerminal('-S Xtest_winscrolled_close_curwin', {'rows': 6})
" This was using freed memory
call term_sendkeys(buf, "\<C-E>")
call TermWait(buf)
call StopVimInTerminal(buf)
call assert_equal(['123456'], readfile('Xtestout'))
call delete('Xtest_winscrolled_close_curwin')
call delete('Xtestout')
endfunc
func Test_WinClosed() func Test_WinClosed()
" Test that the pattern is matched against the closed window's ID, and both " Test that the pattern is matched against the closed window's ID, and both
" <amatch> and <afile> are set to it. " <amatch> and <afile> are set to it.

View File

@ -5246,8 +5246,8 @@ void shell_new_columns(void)
win_reconfig_floats(); // The size of floats might change win_reconfig_floats(); // The size of floats might change
} }
/// Trigger WinScrolled autocmd if window has scrolled. /// Trigger WinScrolled for "curwin" if needed.
void may_trigger_winscrolled(win_T *wp) void may_trigger_winscrolled(void)
{ {
static bool recursive = false; static bool recursive = false;
@ -5255,6 +5255,7 @@ void may_trigger_winscrolled(win_T *wp)
return; return;
} }
win_T *wp = curwin;
if (wp->w_last_topline != wp->w_topline if (wp->w_last_topline != wp->w_topline
|| wp->w_last_leftcol != wp->w_leftcol || wp->w_last_leftcol != wp->w_leftcol
|| wp->w_last_width != wp->w_width || wp->w_last_width != wp->w_width
@ -5266,10 +5267,13 @@ void may_trigger_winscrolled(win_T *wp)
apply_autocmds(EVENT_WINSCROLLED, winid, winid, false, wp->w_buffer); apply_autocmds(EVENT_WINSCROLLED, winid, winid, false, wp->w_buffer);
recursive = false; recursive = false;
wp->w_last_topline = wp->w_topline; // an autocmd may close the window, "wp" may be invalid now
wp->w_last_leftcol = wp->w_leftcol; if (win_valid_any_tab(wp)) {
wp->w_last_width = wp->w_width; wp->w_last_topline = wp->w_topline;
wp->w_last_height = wp->w_height; wp->w_last_leftcol = wp->w_leftcol;
wp->w_last_width = wp->w_width;
wp->w_last_height = wp->w_height;
}
} }
} }

View File

@ -6,12 +6,14 @@ local eval = helpers.eval
local command = helpers.command local command = helpers.command
local feed = helpers.feed local feed = helpers.feed
local meths = helpers.meths local meths = helpers.meths
local assert_alive = helpers.assert_alive
before_each(clear)
describe('WinScrolled', function() describe('WinScrolled', function()
local win_id local win_id
before_each(function() before_each(function()
clear()
win_id = meths.get_current_win().id win_id = meths.get_current_win().id
command(string.format('autocmd WinScrolled %d let g:matched = v:true', win_id)) command(string.format('autocmd WinScrolled %d let g:matched = v:true', win_id))
command('let g:scrolled = 0') command('let g:scrolled = 0')
@ -72,3 +74,12 @@ describe('WinScrolled', function()
eq(1, eval('g:scrolled')) eq(1, eval('g:scrolled'))
end) end)
end) end)
it('closing window in WinScrolled does not cause use-after-free #13265', function()
local lines = {'aaa', 'bbb'}
meths.buf_set_lines(0, 0, -1, true, lines)
command('vsplit')
command('autocmd WinScrolled * close')
feed('<C-E>')
assert_alive()
end)