changeset 5958:f7bc601823e5 v7.4.320

updated for version 7.4.320 Problem: Possible crash when an BufLeave autocommand deletes the buffer. Solution: Check for the window pointer being valid. Postpone freeing the window until autocommands are done. (Yasuhiro Matsumoto)
author Bram Moolenaar <bram@vim.org>
date Thu, 12 Jun 2014 14:01:31 +0200
parents c4d8afa9f89c
children 6f9cadddc06a
files src/buffer.c src/fileio.c src/globals.h src/version.c src/window.c
diffstat 5 files changed, 27 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -371,7 +371,11 @@ close_buffer(win, buf, action, abort_if_
 	unload_buf = TRUE;
 #endif
 
-    if (win != NULL)
+    if (win != NULL
+#ifdef FEAT_WINDOWS
+	&& win_valid(win)	/* in case autocommands closed the window */
+#endif
+	    )
     {
 	/* Set b_last_cursor when closing the last window for the buffer.
 	 * Remember the last cursor position and window options of the buffer.
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -9549,7 +9549,8 @@ apply_autocmds_group(event, fname, fname
 
     /*
      * When stopping to execute autocommands, restore the search patterns and
-     * the redo buffer.  Free buffers in the au_pending_free_buf list.
+     * the redo buffer.  Free any buffers in the au_pending_free_buf list and
+     * free any windows in the au_pending_free_win list.
      */
     if (!autocmd_busy)
     {
@@ -9562,6 +9563,12 @@ apply_autocmds_group(event, fname, fname
 	    vim_free(au_pending_free_buf);
 	    au_pending_free_buf = b;
 	}
+	while (au_pending_free_win != NULL)
+	{
+	    win_T *w = au_pending_free_win->w_next;
+	    vim_free(au_pending_free_win);
+	    au_pending_free_win = w;
+	}
     }
 
     /*
--- a/src/globals.h
+++ b/src/globals.h
@@ -387,10 +387,12 @@ EXTERN int	keep_filetype INIT(= FALSE);	
  * which one is preferred, au_new_curbuf is set to it */
 EXTERN buf_T	*au_new_curbuf INIT(= NULL);
 
-/* When deleting the buffer and autocmd_busy is TRUE, do not free the buffer
- * but link it in the list starting with au_pending_free_buf, using b_next.
- * Free the buffer when autocmd_busy is set to FALSE. */
+/* When deleting a buffer/window and autocmd_busy is TRUE, do not free the
+ * buffer/window. but link it in the list starting with
+ * au_pending_free_buf/ap_pending_free_win, using b_next/w_next.
+ * Free the buffer/window when autocmd_busy is being set to FALSE. */
 EXTERN buf_T	*au_pending_free_buf INIT(= NULL);
+EXTERN win_T	*au_pending_free_win INIT(= NULL);
 #endif
 
 #ifdef FEAT_MOUSE
--- a/src/version.c
+++ b/src/version.c
@@ -735,6 +735,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    320,
+/**/
     319,
 /**/
     318,
--- a/src/window.c
+++ b/src/window.c
@@ -4597,7 +4597,13 @@ win_free(wp, tp)
     if (wp != aucmd_win)
 #endif
 	win_remove(wp, tp);
-    vim_free(wp);
+    if (autocmd_busy)
+    {
+	wp->w_next = au_pending_free_win;
+	au_pending_free_win = wp;
+    }
+    else
+	vim_free(wp);
 
 #ifdef FEAT_AUTOCMD
     unblock_autocmds();