]> granicus.if.org Git - vim/commitdiff
patch 8.2.4739: accessing freed memory after WinScrolled autocmd event v8.2.4739
authorzeertzjq <zeertzjq@outlook.com>
Tue, 12 Apr 2022 10:32:48 +0000 (11:32 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 12 Apr 2022 10:32:48 +0000 (11:32 +0100)
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().

src/edit.c
src/gui.c
src/main.c
src/proto/window.pro
src/testdir/test_autocmd.vim
src/version.c
src/window.c

index fad2a7b1a474024dfbcf76bcc577b59f2f1df392..c28c1f98a377a50480de8818e23887279bdbf3ad 100644 (file)
@@ -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
index 23694d1956b5907522ba708f0474dad8392cacd5..f2f541e79f34e770badbf5d2abdda3f5161f7da7 100644 (file)
--- a/src/gui.c
+++ b/src/gui.c
@@ -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
index fe3571b9266c796a925dea08784b86c3f1f16816..036ab0a1f7aff87e6c623493ee30b60d346f5139 100644 (file)
@@ -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.
index 589dd0931e317714cb94f26d401dadb65035e800..9625942feacac233a0b0b6495e3dfc748d6edcf8 100644 (file)
@@ -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);
index 9af79d8e1ba31ed2dbbff3b379ce8c0e16f4c54c..724d0733fc958f73c93734e6d132b730c2aa55ce 100644 (file)
@@ -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.
index 27de4e52fb3a0f40750bafd4dc2d9f6931dac00a..84c669b181241542391ad6e49a2352f37686bca9 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4739,
 /**/
     4738,
 /**/
index 1eab3dcced462414cce8d880aac8ee11842f1281..c9526a1d660ff5be8bfa98a5154c5de17acc268b 100644 (file)
@@ -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;
+       }
     }
 }