diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-04-12 11:32:48 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-04-12 11:32:48 +0100 |
commit | d58862d18f091d3c14fa3647e724ef7eea1ecefa (patch) | |
tree | 0f40cd55732b3a0f0f14ae4e935e5ed93b83b9d8 | |
parent | 11a57dfd16a47f248fe949344bd5db3f12b9bd32 (diff) |
patch 8.2.4739: accessing freed memory after WinScrolled autocmd eventv8.2.4739
Problem: Accessing freed memory after WinScrolled autocmd event.
Solution: Check the window pointer is still valid. (closes #10156)
Remove the argument from may_trigger_winscrolled().
-rw-r--r-- | src/edit.c | 2 | ||||
-rw-r--r-- | src/gui.c | 2 | ||||
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/proto/window.pro | 2 | ||||
-rw-r--r-- | src/testdir/test_autocmd.vim | 46 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/window.c | 18 |
7 files changed, 54 insertions, 20 deletions
diff --git a/src/edit.c b/src/edit.c index fad2a7b1a4..c28c1f98a3 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1528,7 +1528,7 @@ ins_redraw(int ready) // not busy with something } if (ready) - may_trigger_winscrolled(curwin); + may_trigger_winscrolled(); // Trigger SafeState if nothing is pending. may_trigger_safestate(ready @@ -5238,7 +5238,7 @@ gui_update_screen(void) } if (!finish_op) - may_trigger_winscrolled(curwin); + may_trigger_winscrolled(); # ifdef FEAT_CONCEAL if (conceal_update_lines diff --git a/src/main.c b/src/main.c index fe3571b926..036ab0a1f7 100644 --- a/src/main.c +++ b/src/main.c @@ -1342,7 +1342,7 @@ main_loop( validate_cursor(); if (!finish_op) - may_trigger_winscrolled(curwin); + may_trigger_winscrolled(); // If nothing is pending and we are going to wait for the user to // type a character, trigger SafeState. diff --git a/src/proto/window.pro b/src/proto/window.pro index 589dd0931e..9625942fea 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -17,7 +17,7 @@ void curwin_init(void); void close_windows(buf_T *buf, int keep_curwin); int one_window(void); int win_close(win_T *win, int free_buf); -void may_trigger_winscrolled(win_T *wp); +void may_trigger_winscrolled(void); void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp); void win_free_all(void); win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp); diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 9af79d8e1b..724d0733fc 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -314,17 +314,17 @@ func Test_WinScrolled() CheckRunVimInTerminal let lines =<< trim END - set nowrap scrolloff=0 - for ii in range(1, 18) - call setline(ii, repeat(nr2char(96 + ii), ii * 2)) - endfor - let win_id = win_getid() - let g:matched = v:false - execute 'au WinScrolled' win_id 'let g:matched = v:true' - let g:scrolled = 0 - au WinScrolled * let g:scrolled += 1 - au WinScrolled * let g:amatch = str2nr(expand('<amatch>')) - au WinScrolled * let g:afile = str2nr(expand('<afile>')) + set nowrap scrolloff=0 + for ii in range(1, 18) + call setline(ii, repeat(nr2char(96 + ii), ii * 2)) + endfor + let win_id = win_getid() + let g:matched = v:false + execute 'au WinScrolled' win_id 'let g:matched = v:true' + let g:scrolled = 0 + au WinScrolled * let g:scrolled += 1 + au WinScrolled * let g:amatch = str2nr(expand('<amatch>')) + au WinScrolled * let g:afile = str2nr(expand('<afile>')) END call writefile(lines, 'Xtest_winscrolled') let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6}) @@ -364,6 +364,30 @@ func Test_WinScrolled() call delete('Xtest_winscrolled') 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() " Test that the pattern is matched against the closed window's ID, and both " <amatch> and <afile> are set to it. diff --git a/src/version.c b/src/version.c index 27de4e52fb..84c669b181 100644 --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4739, +/**/ 4738, /**/ 4737, diff --git a/src/window.c b/src/window.c index 1eab3dcced..c9526a1d66 100644 --- a/src/window.c +++ b/src/window.c @@ -2784,9 +2784,13 @@ trigger_winclosed(win_T *win) recursive = FALSE; } +/* + * Trigger WinScrolled for "curwin" if needed. + */ void -may_trigger_winscrolled(win_T *wp) +may_trigger_winscrolled(void) { + win_T *wp = curwin; static int recursive = FALSE; char_u winid[NUMBUFLEN]; @@ -2804,10 +2808,14 @@ may_trigger_winscrolled(win_T *wp) apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE, wp->w_buffer); recursive = FALSE; - wp->w_last_topline = wp->w_topline; - wp->w_last_leftcol = wp->w_leftcol; - wp->w_last_width = wp->w_width; - wp->w_last_height = wp->w_height; + // an autocmd may close the window, "wp" may be invalid now + if (win_valid_any_tab(wp)) + { + wp->w_last_topline = wp->w_topline; + wp->w_last_leftcol = wp->w_leftcol; + wp->w_last_width = wp->w_width; + wp->w_last_height = wp->w_height; + } } } |