# HG changeset patch # User Bram Moolenaar # Date 1416411487 -3600 # Node ID 27a36d1013a6dcf699ea9b2ade80d74329257dbd # Parent d98edc1ee7be0f284316714825c9a5cfcd21e3e6 updated for version 7.4.519 Problem: Crash when using syntax highlighting. Solution: When regprog is freed and replaced, store the result. diff --git a/src/buffer.c b/src/buffer.c --- 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(®match, 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(®match, 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(®match, 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(®match, p, (colnr_T)0)) + if (p != NULL && vim_regexec(rmp, p, (colnr_T)0)) match = name; vim_free(p); } diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c --- 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(®match, name, (colnr_T)0)) + if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0)) { lnum = bp->dbg_lnum; if (fp != NULL) diff --git a/src/fileio.c b/src/fileio.c --- 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(®match, tail, (colnr_T)0))))) result = TRUE; - if (prog == NULL) + if (prog != NULL) + *prog = regmatch.regprog; + else vim_regfree(regmatch.regprog); return result; } diff --git a/src/os_unix.c b/src/os_unix.c --- 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(®match, T_NAME, (colnr_T)0)) + if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0)) return FALSE; } return TRUE; diff --git a/src/proto/fileio.pro b/src/proto/fileio.pro --- 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)); diff --git a/src/proto/regexp.pro b/src/proto/regexp.pro --- 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)); diff --git a/src/regexp.c b/src/regexp.c --- 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(®match, 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 diff --git a/src/spell.c b/src/spell.c --- 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(®match, ptr, 0)) + r = vim_regexec(®match, 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(®match, 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(®match, 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(®match, 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); diff --git a/src/syntax.c b/src/syntax.c --- 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(®match, lnum, (colnr_T)0, + r = syn_regexec(®match, 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(®match, + r = syn_regexec(®match, 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(®match, startpos->lnum, lc_col, - IF_SYN_TIME(&spp->sp_time))) + r = syn_regexec(®match, 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(®match, startpos->lnum, lc_col, - IF_SYN_TIME(&spp_skip->sp_time)) - && regmatch.startpos[0].col + r = syn_regexec(®match, 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 */ diff --git a/src/version.c b/src/version.c --- 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,