aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Hinz <mh.codebro@gmail.com>2014-04-14 16:47:00 +0200
committerThiago de Arruda <tpadilha84@gmail.com>2014-04-16 09:46:01 -0300
commitcb0adf60de98003564105169dee4bc792c56a559 (patch)
tree92549d91a2d431fafffb2ac841459ac22d94d8c0
parent40970917dcd35c8e986c3dc678bf180a2b2ddf24 (diff)
downloadrneovim-cb0adf60de98003564105169dee4bc792c56a559.tar.gz
rneovim-cb0adf60de98003564105169dee4bc792c56a559.tar.bz2
rneovim-cb0adf60de98003564105169dee4bc792c56a559.zip
vim-patch:7.4.251
Problem: Crash when BufAdd autocommand wipes out the buffer. Solution: Check for buffer to still be valid. Postpone freeing the buffer structure. (Hirohito Higashi) https://code.google.com/p/vim/source/detail?r=29eb4c2a33ac701bfcd4d2e2bed7864eba876e0e
-rw-r--r--src/buffer.c24
-rw-r--r--src/ex_cmds.c5
-rw-r--r--src/fileio.c11
-rw-r--r--src/globals.h5
-rw-r--r--src/version.c2
5 files changed, 39 insertions, 8 deletions
diff --git a/src/buffer.c b/src/buffer.c
index d25ed10ac7..7402c57ec8 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -550,7 +550,14 @@ static void free_buffer(buf_T *buf)
free_buffer_stuff(buf, TRUE);
unref_var_dict(buf->b_vars);
aubuflocal_remove(buf);
- vim_free(buf);
+ if (autocmd_busy) {
+ // Do not free the buffer structure while autocommands are executing,
+ // it's still needed. Free it when autocmd_busy is reset.
+ buf->b_next = au_pending_free_buf;
+ au_pending_free_buf = buf;
+ } else {
+ vim_free(buf);
+ }
}
/*
@@ -1332,8 +1339,12 @@ buflist_new (
buf_copy_options(buf, 0);
if ((flags & BLN_LISTED) && !buf->b_p_bl) {
buf->b_p_bl = TRUE;
- if (!(flags & BLN_DUMMY))
+ if (!(flags & BLN_DUMMY)) {
apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
+ if (!buf_valid(buf)) {
+ return NULL;
+ }
+ }
}
return buf;
}
@@ -1469,8 +1480,15 @@ buflist_new (
buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE; /* init 'buflisted' */
if (!(flags & BLN_DUMMY)) {
apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf);
- if (flags & BLN_LISTED)
+ if (!buf_valid(buf)) {
+ return NULL;
+ }
+ if (flags & BLN_LISTED) {
apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
+ if (!buf_valid(buf)) {
+ return NULL;
+ }
+ }
if (aborting()) /* autocmds may abort script processing */
return NULL;
}
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index e3d02357e1..0779568bc8 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -2774,6 +2774,11 @@ do_ecmd (
}
buf = buflist_new(ffname, sfname, 0L,
BLN_CURBUF | ((flags & ECMD_SET_HELP) ? 0 : BLN_LISTED));
+ // Autocmds may change curwin and curbuf.
+ if (oldwin != NULL) {
+ oldwin = curwin;
+ }
+ old_curbuf = curbuf;
}
if (buf == NULL)
goto theend;
diff --git a/src/fileio.c b/src/fileio.c
index fb9f0e0cea..68b68ef3ed 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -7525,14 +7525,17 @@ apply_autocmds_group (
vim_free(sfname);
--nesting; /* see matching increment above */
- /*
- * When stopping to execute autocommands, restore the search patterns and
- * the redo buffer.
- */
+ // When stopping to execute autocommands, restore the search patterns and
+ // the redo buffer. Free buffers in the au_pending_free_buf list.
if (!autocmd_busy) {
restore_search_patterns();
restoreRedobuff();
did_filetype = FALSE;
+ while (au_pending_free_buf != NULL) {
+ buf_T *b = au_pending_free_buf->b_next;
+ vim_free(au_pending_free_buf);
+ au_pending_free_buf = b;
+ }
}
/*
diff --git a/src/globals.h b/src/globals.h
index 731c99623c..2b39ef5416 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -352,6 +352,11 @@ EXTERN int keep_filetype INIT(= FALSE); /* value for did_filetype when
* 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.
+EXTERN buf_T *au_pending_free_buf INIT(= NULL);
+
/*
* Mouse coordinates, set by check_termcode()
*/
diff --git a/src/version.c b/src/version.c
index 72cc8cf5d4..0f00231659 100644
--- a/src/version.c
+++ b/src/version.c
@@ -209,7 +209,7 @@ static int included_patches[] = {
//254,
//253,
//252,
- //251,
+ 251,
//250,
//249,
//248,