changeset 6375:27a36d1013a6 v7.4.519

updated for version 7.4.519 Problem: Crash when using syntax highlighting. Solution: When regprog is freed and replaced, store the result.
author Bram Moolenaar <bram@vim.org>
date Wed, 19 Nov 2014 16:38:07 +0100
parents d98edc1ee7be
children 96ae0812c304
files src/buffer.c src/ex_cmds2.c src/fileio.c src/os_unix.c src/proto/fileio.pro src/proto/regexp.pro src/regexp.c src/spell.c src/syntax.c src/version.c
diffstat 10 files changed, 99 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -28,9 +28,9 @@
 #include "vim.h"
 
 #if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL)
-static char_u	*buflist_match __ARGS((regprog_T *prog, buf_T *buf, int ignore_case));
+static char_u	*buflist_match __ARGS((regmatch_T *rmp, buf_T *buf, int ignore_case));
 # define HAVE_BUFLIST_MATCH
-static char_u	*fname_match __ARGS((regprog_T *prog, char_u *name, int ignore_case));
+static char_u	*fname_match __ARGS((regmatch_T *rmp, char_u *name, int ignore_case));
 #endif
 static void	buflist_setfpos __ARGS((buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options));
 static wininfo_T *find_wininfo __ARGS((buf_T *buf, int skip_diff_buffer));
@@ -2220,7 +2220,6 @@ buflist_findpat(pattern, pattern_end, un
     int		curtab_only;	/* find buffers in current tab only */
 {
     buf_T	*buf;
-    regprog_T	*prog;
     int		match = -1;
     int		find_listed;
     char_u	*pat;
@@ -2265,14 +2264,16 @@ buflist_findpat(pattern, pattern_end, un
 	{
 	    for (attempt = 0; attempt <= 3; ++attempt)
 	    {
+		regmatch_T	regmatch;
+
 		/* may add '^' and '$' */
 		if (toggledollar)
 		    *patend = (attempt < 2) ? NUL : '$'; /* add/remove '$' */
 		p = pat;
 		if (*p == '^' && !(attempt & 1))	 /* add/remove '^' */
 		    ++p;
-		prog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
-		if (prog == NULL)
+		regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
+		if (regmatch.regprog == NULL)
 		{
 		    vim_free(pat);
 		    return -1;
@@ -2283,7 +2284,7 @@ buflist_findpat(pattern, pattern_end, un
 #ifdef FEAT_DIFF
 			    && (!diffmode || diff_mode_buf(buf))
 #endif
-			    && buflist_match(prog, buf, FALSE) != NULL)
+			    && buflist_match(&regmatch, buf, FALSE) != NULL)
 		    {
 			if (curtab_only)
 			{
@@ -2310,7 +2311,7 @@ buflist_findpat(pattern, pattern_end, un
 			match = buf->b_fnum;	/* remember first match */
 		    }
 
-		vim_regfree(prog);
+		vim_regfree(regmatch.regprog);
 		if (match >= 0)			/* found one match */
 		    break;
 	    }
@@ -2352,7 +2353,6 @@ ExpandBufnames(pat, num_file, file, opti
     int		round;
     char_u	*p;
     int		attempt;
-    regprog_T	*prog;
     char_u	*patc;
 
     *num_file = 0;		    /* return values in case of FAIL */
@@ -2376,10 +2376,12 @@ ExpandBufnames(pat, num_file, file, opti
      */
     for (attempt = 0; attempt <= 1; ++attempt)
     {
+	regmatch_T	regmatch;
+
 	if (attempt > 0 && patc == pat)
 	    break;	/* there was no anchor, no need to try again */
-	prog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
-	if (prog == NULL)
+	regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
+	if (regmatch.regprog == NULL)
 	{
 	    if (patc != pat)
 		vim_free(patc);
@@ -2397,7 +2399,7 @@ ExpandBufnames(pat, num_file, file, opti
 	    {
 		if (!buf->b_p_bl)	/* skip unlisted buffers */
 		    continue;
-		p = buflist_match(prog, buf, p_wic);
+		p = buflist_match(&regmatch, buf, p_wic);
 		if (p != NULL)
 		{
 		    if (round == 1)
@@ -2419,14 +2421,14 @@ ExpandBufnames(pat, num_file, file, opti
 		*file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
 		if (*file == NULL)
 		{
-		    vim_regfree(prog);
+		    vim_regfree(regmatch.regprog);
 		    if (patc != pat)
 			vim_free(patc);
 		    return FAIL;
 		}
 	    }
 	}
-	vim_regfree(prog);
+	vim_regfree(regmatch.regprog);
 	if (count)		/* match(es) found, break here */
 	    break;
     }
@@ -2445,17 +2447,17 @@ ExpandBufnames(pat, num_file, file, opti
  * Check for a match on the file name for buffer "buf" with regprog "prog".
  */
     static char_u *
-buflist_match(prog, buf, ignore_case)
-    regprog_T	*prog;
+buflist_match(rmp, buf, ignore_case)
+    regmatch_T	*rmp;
     buf_T	*buf;
     int		ignore_case;  /* when TRUE ignore case, when FALSE use 'fic' */
 {
     char_u	*match;
 
     /* First try the short file name, then the long file name. */
-    match = fname_match(prog, buf->b_sfname, ignore_case);
+    match = fname_match(rmp, buf->b_sfname, ignore_case);
     if (match == NULL)
-	match = fname_match(prog, buf->b_ffname, ignore_case);
+	match = fname_match(rmp, buf->b_ffname, ignore_case);
 
     return match;
 }
@@ -2465,27 +2467,25 @@ buflist_match(prog, buf, ignore_case)
  * Return "name" when there is a match, NULL when not.
  */
     static char_u *
-fname_match(prog, name, ignore_case)
-    regprog_T	*prog;
+fname_match(rmp, name, ignore_case)
+    regmatch_T	*rmp;
     char_u	*name;
     int		ignore_case;  /* when TRUE ignore case, when FALSE use 'fic' */
 {
     char_u	*match = NULL;
     char_u	*p;
-    regmatch_T	regmatch;
 
     if (name != NULL)
     {
-	regmatch.regprog = prog;
 	/* Ignore case when 'fileignorecase' or the argument is set. */
-	regmatch.rm_ic = p_fic || ignore_case;
-	if (vim_regexec(&regmatch, name, (colnr_T)0))
+	rmp->rm_ic = p_fic || ignore_case;
+	if (vim_regexec(rmp, name, (colnr_T)0))
 	    match = name;
 	else
 	{
 	    /* Replace $(HOME) with '~' and try matching again. */
 	    p = home_replace_save(NULL, name);
-	    if (p != NULL && vim_regexec(&regmatch, p, (colnr_T)0))
+	    if (p != NULL && vim_regexec(rmp, p, (colnr_T)0))
 		match = name;
 	    vim_free(p);
 	}
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -739,7 +739,6 @@ debuggy_find(file, fname, after, gap, fp
     struct debuggy *bp;
     int		i;
     linenr_T	lnum = 0;
-    regmatch_T	regmatch;
     char_u	*name = fname;
     int		prev_got_int;
 
@@ -771,8 +770,6 @@ debuggy_find(file, fname, after, gap, fp
 #endif
 		(bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
 	{
-	    regmatch.regprog = bp->dbg_prog;
-	    regmatch.rm_ic = FALSE;
 	    /*
 	     * Save the value of got_int and reset it.  We don't want a
 	     * previous interruption cancel matching, only hitting CTRL-C
@@ -780,7 +777,7 @@ debuggy_find(file, fname, after, gap, fp
 	     */
 	    prev_got_int = got_int;
 	    got_int = FALSE;
-	    if (vim_regexec(&regmatch, name, (colnr_T)0))
+	    if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
 	    {
 		lnum = bp->dbg_lnum;
 		if (fp != NULL)
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -7772,6 +7772,9 @@ static int au_get_grouparg __ARGS((char_
 static int do_autocmd_event __ARGS((event_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group));
 static int apply_autocmds_group __ARGS((event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap));
 static void auto_next_pat __ARGS((AutoPatCmd *apc, int stop_at_last));
+#if defined(FEAT_AUTOCMD) || defined(FEAT_WILDIGN)
+static int match_file_pat __ARGS((char_u *pattern, regprog_T **prog, char_u *fname, char_u *sfname, char_u *tail, int allow_dirs));
+#endif
 
 
 static event_T	last_event;
@@ -9640,7 +9643,7 @@ auto_next_pat(apc, stop_at_last)
 	{
 	    /* execution-condition */
 	    if (ap->buflocal_nr == 0
-		    ? (match_file_pat(NULL, ap->reg_prog, apc->fname,
+		    ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
 				      apc->sfname, apc->tail, ap->allow_dirs))
 		    : ap->buflocal_nr == apc->arg_bufnr)
 	    {
@@ -9774,7 +9777,7 @@ has_autocmd(event, sfname, buf)
     for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
 	if (ap->pat != NULL && ap->cmds != NULL
 	      && (ap->buflocal_nr == 0
-		? match_file_pat(NULL, ap->reg_prog,
+		? match_file_pat(NULL, &ap->reg_prog,
 					  fname, sfname, tail, ap->allow_dirs)
 		: buf != NULL && ap->buflocal_nr == buf->b_fnum
 	   ))
@@ -10035,10 +10038,10 @@ aucmd_restbuf(aco)
  * Used for autocommands and 'wildignore'.
  * Returns TRUE if there is a match, FALSE otherwise.
  */
-    int
+    static int
 match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs)
     char_u	*pattern;		/* pattern to match with */
-    regprog_T	*prog;			/* pre-compiled regprog or NULL */
+    regprog_T	**prog;			/* pre-compiled regprog or NULL */
     char_u	*fname;			/* full path of file name */
     char_u	*sfname;		/* short file name or NULL */
     char_u	*tail;			/* tail of path */
@@ -10093,7 +10096,7 @@ match_file_pat(pattern, prog, fname, sfn
 #endif
     {
 	if (prog != NULL)
-	    regmatch.regprog = prog;
+	    regmatch.regprog = *prog;
 	else
 	    regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
     }
@@ -10119,7 +10122,9 @@ match_file_pat(pattern, prog, fname, sfn
 		 || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0)))))
 	result = TRUE;
 
-    if (prog == NULL)
+    if (prog != NULL)
+	*prog = regmatch.regprog;
+    else
 	vim_regfree(regmatch.regprog);
     return result;
 }
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -1610,8 +1610,6 @@ x_IOerror_handler(dpy)
     static int
 x_connect_to_server()
 {
-    regmatch_T	regmatch;
-
 #if defined(FEAT_CLIENTSERVER)
     if (x_force_connect)
 	return TRUE;
@@ -1622,9 +1620,7 @@ x_connect_to_server()
     /* Check for a match with "exclude:" from 'clipboard'. */
     if (clip_exclude_prog != NULL)
     {
-	regmatch.rm_ic = FALSE;		/* Don't ignore case */
-	regmatch.regprog = clip_exclude_prog;
-	if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
+	if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
 	    return FALSE;
     }
     return TRUE;
--- a/src/proto/fileio.pro
+++ b/src/proto/fileio.pro
@@ -59,7 +59,6 @@ char_u *set_context_in_autocmd __ARGS((e
 char_u *get_event_name __ARGS((expand_T *xp, int idx));
 int autocmd_supported __ARGS((char_u *name));
 int au_exists __ARGS((char_u *arg));
-int match_file_pat __ARGS((char_u *pattern, regprog_T *prog, char_u *fname, char_u *sfname, char_u *tail, int allow_dirs));
 int match_file_list __ARGS((char_u *list, char_u *sfname, char_u *ffname));
 char_u *file_pat_to_reg_pat __ARGS((char_u *pat, char_u *pat_end, char *allow_dirs, int no_bslash));
 long read_eintr __ARGS((int fd, void *buf, size_t bufsize));
--- a/src/proto/regexp.pro
+++ b/src/proto/regexp.pro
@@ -13,6 +13,7 @@ char_u *reg_submatch __ARGS((int no));
 list_T *reg_submatch_list __ARGS((int no));
 regprog_T *vim_regcomp __ARGS((char_u *expr_arg, int re_flags));
 void vim_regfree __ARGS((regprog_T *prog));
+int vim_regexec_prog __ARGS((regprog_T **prog, int ignore_case, char_u *line, colnr_T col));
 int vim_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
 int vim_regexec_nl __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
 long vim_regexec_multi __ARGS((regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm));
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -8163,6 +8163,7 @@ static int vim_regexec_both __ARGS((regm
 /*
  * Match a regexp against a string.
  * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Note: "rmp->regprog" may be freed and changed.
  * Uses curbuf for line count and 'iskeyword'.
  * When "nl" is TRUE consider a "\n" in "line" to be a line break.
  *
@@ -8203,6 +8204,29 @@ vim_regexec_both(rmp, line, col, nl)
     return result;
 }
 
+/*
+ * Note: "*prog" may be freed and changed.
+ */
+    int
+vim_regexec_prog(prog, ignore_case, line, col)
+    regprog_T	**prog;
+    int		ignore_case;
+    char_u	*line;
+    colnr_T	col;
+{
+    int r;
+    regmatch_T regmatch;
+
+    regmatch.regprog = *prog;
+    regmatch.rm_ic = ignore_case;
+    r = vim_regexec_both(&regmatch, line, col, FALSE);
+    *prog = regmatch.regprog;
+    return r;
+}
+
+/*
+ * Note: "rmp->regprog" may be freed and changed.
+ */
     int
 vim_regexec(rmp, line, col)
     regmatch_T	*rmp;
@@ -8216,6 +8240,7 @@ vim_regexec(rmp, line, col)
 	|| defined(FIND_REPLACE_DIALOG) || defined(PROTO)
 /*
  * Like vim_regexec(), but consider a "\n" in "line" to be a line break.
+ * Note: "rmp->regprog" may be freed and changed.
  */
     int
 vim_regexec_nl(rmp, line, col)
@@ -8230,6 +8255,7 @@ vim_regexec_nl(rmp, line, col)
 /*
  * Match a regexp against multiple lines.
  * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Note: "rmp->regprog" may be freed and changed.
  * Uses curbuf for line count and 'iskeyword'.
  *
  * Return zero if there is no match.  Return number of lines contained in the
--- a/src/spell.c
+++ b/src/spell.c
@@ -1154,11 +1154,14 @@ spell_check(wp, ptr, attrp, capcol, doco
 	    if (capcol != NULL && wp->w_s->b_cap_prog != NULL)
 	    {
 		regmatch_T	regmatch;
+		int		r;
 
 		/* Check for end of sentence. */
 		regmatch.regprog = wp->w_s->b_cap_prog;
 		regmatch.rm_ic = FALSE;
-		if (vim_regexec(&regmatch, ptr, 0))
+		r = vim_regexec(&regmatch, ptr, 0);
+		wp->w_s->b_cap_prog = regmatch.regprog;
+		if (r)
 		    *capcol = (int)(regmatch.endp[0] - ptr);
 	    }
 
@@ -1786,7 +1789,6 @@ can_compound(slang, word, flags)
     char_u	*word;
     char_u	*flags;
 {
-    regmatch_T	regmatch;
 #ifdef FEAT_MBYTE
     char_u	uflags[MAXWLEN * 2];
     int		i;
@@ -1808,9 +1810,7 @@ can_compound(slang, word, flags)
     else
 #endif
 	p = flags;
-    regmatch.regprog = slang->sl_compprog;
-    regmatch.rm_ic = FALSE;
-    if (!vim_regexec(&regmatch, p, 0))
+    if (!vim_regexec_prog(&slang->sl_compprog, FALSE, p, 0))
 	return FALSE;
 
     /* Count the number of syllables.  This may be slow, do it last.  If there
@@ -1930,8 +1930,7 @@ valid_word_prefix(totprefcnt, arridx, fl
 {
     int		prefcnt;
     int		pidx;
-    regprog_T	*rp;
-    regmatch_T	regmatch;
+    regprog_T	**rp;
     int		prefid;
 
     prefid = (unsigned)flags >> 24;
@@ -1950,12 +1949,10 @@ valid_word_prefix(totprefcnt, arridx, fl
 
 	/* Check the condition, if there is one.  The condition index is
 	 * stored in the two bytes above the prefix ID byte.  */
-	rp = slang->sl_prefprog[((unsigned)pidx >> 8) & 0xffff];
-	if (rp != NULL)
-	{
-	    regmatch.regprog = rp;
-	    regmatch.rm_ic = FALSE;
-	    if (!vim_regexec(&regmatch, word, 0))
+	rp = &slang->sl_prefprog[((unsigned)pidx >> 8) & 0xffff];
+	if (*rp != NULL)
+	{
+	    if (!vim_regexec_prog(rp, FALSE, word, 0))
 		continue;
 	}
 	else if (cond_req)
@@ -6903,7 +6900,6 @@ store_aff_word(spin, word, afflist, affi
     hashitem_T	*hi;
     affheader_T	*ah;
     affentry_T	*ae;
-    regmatch_T	regmatch;
     char_u	newword[MAXWLEN];
     int		retval = OK;
     int		i, j;
@@ -6944,15 +6940,14 @@ store_aff_word(spin, word, afflist, affi
 		     * When a previously added affix had CIRCUMFIX this one
 		     * must have it too, if it had not then this one must not
 		     * have one either. */
-		    regmatch.regprog = ae->ae_prog;
-		    regmatch.rm_ic = FALSE;
 		    if ((xht != NULL || !affile->af_pfxpostpone
 				|| ae->ae_chop != NULL
 				|| ae->ae_flags != NULL)
 			    && (ae->ae_chop == NULL
 				|| STRLEN(ae->ae_chop) < wordlen)
 			    && (ae->ae_prog == NULL
-				|| vim_regexec(&regmatch, word, (colnr_T)0))
+				|| vim_regexec_prog(&ae->ae_prog, FALSE,
+							    word, (colnr_T)0))
 			    && (((condit & CONDIT_CFIX) == 0)
 				== ((condit & CONDIT_AFF) == 0
 				    || ae->ae_flags == NULL
@@ -10478,6 +10473,7 @@ check_need_cap(lnum, col)
 		break;
 	    }
 	}
+	curwin->w_s->b_cap_prog = regmatch.regprog;
     }
 
     vim_free(line_copy);
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -992,13 +992,16 @@ syn_match_linecont(lnum)
     linenr_T	lnum;
 {
     regmmatch_T regmatch;
+    int r;
 
     if (syn_block->b_syn_linecont_prog != NULL)
     {
 	regmatch.rmm_ic = syn_block->b_syn_linecont_ic;
 	regmatch.regprog = syn_block->b_syn_linecont_prog;
-	return syn_regexec(&regmatch, lnum, (colnr_T)0,
+	r = syn_regexec(&regmatch, lnum, (colnr_T)0,
 				IF_SYN_TIME(&syn_block->b_syn_linecont_time));
+	syn_block->b_syn_linecont_prog = regmatch.regprog;
+	return r;
     }
     return FALSE;
 }
@@ -2075,6 +2078,8 @@ syn_current_attr(syncing, displaying, ca
 					    cur_si->si_cont_list, &spp->sp_syn,
 					    spp->sp_flags & HL_CONTAINED))))
 			{
+			    int r;
+
 			    /* If we already tried matching in this line, and
 			     * there isn't a match before next_match_col, skip
 			     * this item. */
@@ -2089,10 +2094,12 @@ syn_current_attr(syncing, displaying, ca
 
 			    regmatch.rmm_ic = spp->sp_ic;
 			    regmatch.regprog = spp->sp_prog;
-			    if (!syn_regexec(&regmatch,
+			    r = syn_regexec(&regmatch,
 					     current_lnum,
 					     (colnr_T)lc_col,
-				             IF_SYN_TIME(&spp->sp_time)))
+				             IF_SYN_TIME(&spp->sp_time));
+			    spp->sp_prog = regmatch.regprog;
+			    if (!r)
 			    {
 				/* no match in this line, try another one */
 				spp->sp_startcol = MAXCOL;
@@ -2963,6 +2970,7 @@ find_endpos(idx, startpos, m_endpos, hl_
 	for (idx = start_idx; idx < syn_block->b_syn_patterns.ga_len; ++idx)
 	{
 	    int lc_col = matchcol;
+	    int r;
 
 	    spp = &(SYN_ITEMS(syn_block)[idx]);
 	    if (spp->sp_type != SPTYPE_END)	/* past last END pattern */
@@ -2973,8 +2981,10 @@ find_endpos(idx, startpos, m_endpos, hl_
 
 	    regmatch.rmm_ic = spp->sp_ic;
 	    regmatch.regprog = spp->sp_prog;
-	    if (syn_regexec(&regmatch, startpos->lnum, lc_col,
-						  IF_SYN_TIME(&spp->sp_time)))
+	    r = syn_regexec(&regmatch, startpos->lnum, lc_col,
+						  IF_SYN_TIME(&spp->sp_time));
+	    spp->sp_prog = regmatch.regprog;
+	    if (r)
 	    {
 		if (best_idx == -1 || regmatch.startpos[0].col
 					      < best_regmatch.startpos[0].col)
@@ -3000,14 +3010,16 @@ find_endpos(idx, startpos, m_endpos, hl_
 	if (spp_skip != NULL)
 	{
 	    int lc_col = matchcol - spp_skip->sp_offsets[SPO_LC_OFF];
+	    int r;
 
 	    if (lc_col < 0)
 		lc_col = 0;
 	    regmatch.rmm_ic = spp_skip->sp_ic;
 	    regmatch.regprog = spp_skip->sp_prog;
-	    if (syn_regexec(&regmatch, startpos->lnum, lc_col,
-					      IF_SYN_TIME(&spp_skip->sp_time))
-		    && regmatch.startpos[0].col
+	    r = syn_regexec(&regmatch, startpos->lnum, lc_col,
+					      IF_SYN_TIME(&spp_skip->sp_time));
+	    spp_skip->sp_prog = regmatch.regprog;
+	    if (r && regmatch.startpos[0].col
 					     <= best_regmatch.startpos[0].col)
 	    {
 		/* Add offset to skip pattern match */
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    519,
+/**/
     518,
 /**/
     517,