changeset 11587:439835c4b7aa v8.0.0676

patch 8.0.0676: crash when closing quickfix window in autocmd commit https://github.com/vim/vim/commit/182a17b1e80b92826204d967808df0d30eb2ef27 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jun 25 20:57:18 2017 +0200 patch 8.0.0676: crash when closing quickfix window in autocmd Problem: Crash when closing the quickfix window in a FileType autocommand that triggers when the quickfix window is opened. Solution: Save the new value before triggering the OptionSet autocommand. Add the "starting" flag to test_override() to make the text work.
author Christian Brabandt <cb@256bit.org>
date Sun, 25 Jun 2017 21:00:03 +0200
parents c742c05d083c
children 9ea6a69996fe
files runtime/doc/eval.txt src/evalfunc.c src/option.c src/version.c
diffstat 4 files changed, 81 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt*	For Vim version 8.0.  Last change: 2017 Jun 24
+*eval.txt*	For Vim version 8.0.  Last change: 2017 Jun 25
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -7942,8 +7942,19 @@ test_override({name}, {val})				*test_ov
 		name	     effect when {val} is non-zero ~
 		redraw       disable the redrawing() function
 		char_avail   disable the char_avail() function
+		starting     reset the "starting" variable, see below
 		ALL	     clear all overrides ({val} is not used)
 
+		"starting" is to be used when a test should behave like
+		startup was done.  Since the tests are run by sourcing a
+		script the "starting" variable is non-zero. This is usually a
+		good thing (tests run faster), but sometimes changes behavior
+		in a way that the test doesn't work properly.
+		When using: >
+			call test_override('starting', 1)
+< 		The value of "starting" is saved.  It is restored by: >
+			call test_override('starting', 0)
+
 test_settime({expr})					*test_settime()*
 		Set the time Vim uses internally.  Currently only used for
 		timestamps in the history, as they are used in viminfo, and
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -12398,6 +12398,7 @@ f_test_override(typval_T *argvars, typva
 {
     char_u *name = (char_u *)"";
     int     val;
+    static int save_starting = -1;
 
     if (argvars[0].v_type != VAR_STRING
 	    || (argvars[1].v_type) != VAR_NUMBER)
@@ -12411,10 +12412,29 @@ f_test_override(typval_T *argvars, typva
 	    disable_redraw_for_testing = val;
 	else if (STRCMP(name, (char_u *)"char_avail") == 0)
 	    disable_char_avail_for_testing = val;
+	else if (STRCMP(name, (char_u *)"starting") == 0)
+	{
+	    if (val)
+	    {
+		if (save_starting < 0)
+		    save_starting = starting;
+		starting = 0;
+	    }
+	    else
+	    {
+		starting = save_starting;
+		save_starting = -1;
+	    }
+	}
 	else if (STRCMP(name, (char_u *)"ALL") == 0)
 	{
 	    disable_char_avail_for_testing = FALSE;
 	    disable_redraw_for_testing = FALSE;
+	    if (save_starting >= 0)
+	    {
+		starting = save_starting;
+		save_starting = -1;
+	    }
 	}
 	else
 	    EMSG2(_(e_invarg2), name);
--- a/src/option.c
+++ b/src/option.c
@@ -4294,6 +4294,32 @@ set_title_defaults(void)
 }
 #endif
 
+#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+    static void
+trigger_optionsset_string(
+	int	opt_idx,
+	int	opt_flags,
+	char_u *oldval,
+	char_u *newval)
+{
+    if (oldval != NULL && newval != NULL)
+    {
+	char_u buf_type[7];
+
+	sprintf((char *)buf_type, "%s",
+	    (opt_flags & OPT_LOCAL) ? "local" : "global");
+	set_vim_var_string(VV_OPTION_OLD, oldval, -1);
+	set_vim_var_string(VV_OPTION_NEW, newval, -1);
+	set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+	apply_autocmds(EVENT_OPTIONSET,
+		       (char_u *)options[opt_idx].fullname, NULL, FALSE, NULL);
+	reset_v_option_vars();
+    }
+    vim_free(oldval);
+    vim_free(newval);
+}
+#endif
+
 /*
  * Parse 'arg' for option settings.
  *
@@ -4763,6 +4789,7 @@ do_set(
 			char_u	    *origval = NULL;
 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
 			char_u	    *saved_origval = NULL;
+			char_u	    *saved_newval = NULL;
 #endif
 			unsigned    newlen;
 			int	    comma;
@@ -5114,14 +5141,21 @@ do_set(
 # ifdef FEAT_CRYPT
 				&& options[opt_idx].indir != PV_KEY
 # endif
-							   && origval != NULL)
+					  && origval != NULL && newval != NULL)
+			{
 			    /* origval may be freed by
 			     * did_set_string_option(), make a copy. */
 			    saved_origval = vim_strsave(origval);
+			    /* newval (and varp) may become invalid if the
+			     * buffer is closed by autocommands. */
+			    saved_newval = vim_strsave(newval);
+			}
 #endif
 
 			/* Handle side effects, and set the global value for
-			 * ":set" on local options. */
+			 * ":set" on local options. Note: when setting 'syntax'
+			 * or 'filetype' autocommands may be triggered that can
+			 * cause havoc. */
 			errmsg = did_set_string_option(opt_idx, (char_u **)varp,
 				new_value_alloced, oldval, errbuf, opt_flags);
 
@@ -5130,28 +5164,14 @@ do_set(
 			{
 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
 			    vim_free(saved_origval);
+			    vim_free(saved_newval);
 #endif
 			    goto skip;
 			}
 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
-			if (saved_origval != NULL)
-			{
-			    char_u buf_type[7];
-
-			    sprintf((char *)buf_type, "%s",
-				(opt_flags & OPT_LOCAL) ? "local" : "global");
-			    set_vim_var_string(VV_OPTION_NEW,
-							*(char_u **)varp, -1);
-			    set_vim_var_string(VV_OPTION_OLD, saved_origval, -1);
-			    set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
-			    apply_autocmds(EVENT_OPTIONSET,
-					  (char_u *)options[opt_idx].fullname,
-				NULL, FALSE, NULL);
-			    reset_v_option_vars();
-			    vim_free(saved_origval);
-			}
-#endif
-
+			trigger_optionsset_string(opt_idx, opt_flags,
+						  saved_origval, saved_newval);
+#endif
 		    }
 		    else	    /* key code option */
 		    {
@@ -5922,6 +5942,7 @@ set_string_option(
     char_u	*oldval;
 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
     char_u	*saved_oldval = NULL;
+    char_u	*saved_newval = NULL;
 #endif
     char_u	*r = NULL;
 
@@ -5945,26 +5966,19 @@ set_string_option(
 		&& options[opt_idx].indir != PV_KEY
 # endif
 		)
+	{
 	    saved_oldval = vim_strsave(oldval);
+	    saved_newval = vim_strsave(s);
+	}
 #endif
 	if ((r = did_set_string_option(opt_idx, varp, TRUE, oldval, NULL,
 							   opt_flags)) == NULL)
 	    did_set_option(opt_idx, opt_flags, TRUE);
 
+#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
 	/* call autocommand after handling side effects */
-#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
-	if (saved_oldval != NULL)
-	{
-	    char_u buf_type[7];
-	    sprintf((char *)buf_type, "%s",
-		(opt_flags & OPT_LOCAL) ? "local" : "global");
-	    set_vim_var_string(VV_OPTION_NEW, *varp, -1);
-	    set_vim_var_string(VV_OPTION_OLD, saved_oldval, -1);
-	    set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
-	    apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, FALSE, NULL);
-	    reset_v_option_vars();
-	    vim_free(saved_oldval);
-	}
+	trigger_optionsset_string(opt_idx, opt_flags,
+						   saved_oldval, saved_newval);
 #endif
     }
     return r;
--- a/src/version.c
+++ b/src/version.c
@@ -765,6 +765,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    676,
+/**/
     675,
 /**/
     674,