From 241b905b1378c5c45d8d284bb191b16807ff2a44 Mon Sep 17 00:00:00 2001 From: Billy Su Date: Thu, 7 Mar 2019 13:08:15 +0800 Subject: vim-patch:8.0.0643: when a pattern search is slow Vim becomes unusable Problem: When 'hlsearch' is set and matching with the last search pattern is very slow, Vim becomes unusable. Cannot quit search by pressing CTRL-C. Solution: When the search times out set a flag and don't try again. Check for timeout and CTRL-C in NFA loop that adds states. https://github.com/vim/vim/commit/fbd0b0af6800f6ff89857863d6a07ea03f09ff6c --- src/nvim/regexp.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'src/nvim/regexp.c') diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index c043d4a173..25fa67c112 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -3297,7 +3297,7 @@ bt_regexec_nl ( rex.reg_icombine = false; rex.reg_maxcol = 0; - long r = bt_regexec_both(line, col, NULL); + long r = bt_regexec_both(line, col, NULL, NULL); assert(r <= INT_MAX); return (int)r; } @@ -3357,7 +3357,8 @@ static inline char_u *cstrchr(const char_u *const s, const int c) /// @return zero if there is no match and number of lines contained in the match /// otherwise. static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, - linenr_T lnum, colnr_T col, proftime_T *tm) + linenr_T lnum, colnr_T col, + proftime_T *tm, int *timed_out) { rex.reg_match = NULL; rex.reg_mmatch = rmp; @@ -3370,7 +3371,7 @@ static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, rex.reg_icombine = false; rex.reg_maxcol = rmp->rmm_maxcol; - return bt_regexec_both(NULL, col, tm); + return bt_regexec_both(NULL, col, tm, timed_out); } /* @@ -3379,8 +3380,10 @@ static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, * Returns 0 for failure, number of lines contained in the match otherwise. */ static long bt_regexec_both(char_u *line, - colnr_T col, /* column to start looking for match */ - proftime_T *tm /* timeout limit or NULL */ + // column to start looking for match + colnr_T col, + proftime_T *tm, // timeout limit or NULL + int *timed_out // flag set on timeout or NULL ) { bt_regprog_T *prog; @@ -3525,8 +3528,12 @@ static long bt_regexec_both(char_u *line, /* Check for timeout once in a twenty times to avoid overhead. */ if (tm != NULL && ++tm_count == 20) { tm_count = 0; - if (profile_passed_limit(*tm)) + if (profile_passed_limit(*tm)) { + if (timed_out != NULL) { + *timed_out = true; + } break; + } } } } @@ -7275,12 +7282,13 @@ int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col) /// Return zero if there is no match. Return number of lines contained in the /// match otherwise. long vim_regexec_multi( - regmmatch_T *rmp, - win_T *win, /* window in which to search or NULL */ - buf_T *buf, /* buffer in which to search */ - linenr_T lnum, /* nr of line to start looking for match */ - colnr_T col, /* column to start looking for match */ - proftime_T *tm /* timeout limit or NULL */ + regmmatch_T *rmp, + win_T *win, // window in which to search or NULL + buf_T *buf, // buffer in which to search + linenr_T lnum, // nr of line to start looking for match + colnr_T col, // column to start looking for match + proftime_T *tm, // timeout limit or NULL + int *timed_out // flag is set when timeout limit reached ) { regexec_T rex_save; @@ -7293,7 +7301,7 @@ long vim_regexec_multi( rex_in_use = true; int result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col, - tm); + tm, timed_out); // NFA engine aborted because it's very slow, use backtracking engine instead. if (rmp->regprog->re_engine == AUTOMATIC_ENGINE @@ -7313,7 +7321,7 @@ long vim_regexec_multi( if (rmp->regprog != NULL) { result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col, - tm); + tm, timed_out); } xfree(pat); -- cgit From fbd8209286373843b7e9b4151a1432fc4555484d Mon Sep 17 00:00:00 2001 From: Billy Su Date: Sat, 2 Mar 2019 12:38:36 +0800 Subject: vim-patch:8.0.0645: no error for illegal back reference in NFA engine Problem: The new regexp engine does not give an error for using a back reference where it is not allowed. (Dominique Pelle) Solution: Check the back reference like the old engine. (closes vim/vim#1774) https://github.com/vim/vim/commit/1ef9bbe215e13a273e74fccaddd8fc5a42c76b6e --- src/nvim/regexp.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'src/nvim/regexp.c') diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 25fa67c112..396b376e39 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -1210,6 +1210,31 @@ char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp) return p; } +/* + * Return TRUE if the back reference is legal. We must have seen the close + * brace. + * TODO: Should also check that we don't refer to something that is repeated + * (+*=): what instance of the repetition should we match? + */ +static int seen_endbrace(int refnum) +{ + if (!had_endbrace[refnum]) { + char_u *p; + + /* Trick: check if "@<=" or "@ Date: Sun, 3 Mar 2019 23:55:44 +0800 Subject: vim-patch:8.0.0646: the hlsearch test fails on fast systems Problem: The hlsearch test fails on fast systems. Solution: Make the search pattern slower. Fix that the old regexp engine doesn't timeout properly. https://github.com/vim/vim/commit/0946326580e6f034fe2c88d041407ea0fde980ab --- src/nvim/regexp.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src/nvim/regexp.c') diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 396b376e39..dc3fbbaeb5 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -3496,7 +3496,7 @@ static long bt_regexec_both(char_u *line, && (utf_fold(prog->regstart) == utf_fold(c) || (c < 255 && prog->regstart < 255 && mb_tolower(prog->regstart) == mb_tolower(c))))) { - retval = regtry(prog, col); + retval = regtry(prog, col, tm, timed_out); } else { retval = 0; } @@ -3520,9 +3520,10 @@ static long bt_regexec_both(char_u *line, break; } - retval = regtry(prog, col); - if (retval > 0) + retval = regtry(prog, col, tm, timed_out); + if (retval > 0) { break; + } /* if not currently on the first line, get it again */ if (reglnum != 0) { @@ -3603,7 +3604,8 @@ void unref_extmatch(reg_extmatch_T *em) * regtry - try match of "prog" with at regline["col"]. * Returns 0 for failure, number of lines contained in the match otherwise. */ -static long regtry(bt_regprog_T *prog, colnr_T col) +static long regtry(bt_regprog_T *prog, colnr_T col, + proftime_T *tm, int *timed_out) { reginput = regline + col; need_clear_subexpr = TRUE; @@ -3611,8 +3613,9 @@ static long regtry(bt_regprog_T *prog, colnr_T col) if (prog->reghasz == REX_SET) need_clear_zsubexpr = TRUE; - if (regmatch(prog->program + 1) == 0) + if (regmatch(prog->program + 1, tm, timed_out) == 0) { return 0; + } cleanup_subexpr(); if (REG_MULTI) { @@ -3768,9 +3771,11 @@ static long bl_maxval; * Returns FALSE when there is no match. Leaves reginput and reglnum in an * undefined state! */ -static int -regmatch ( - char_u *scan /* Current node. */ +static int +regmatch( + char_u *scan, // Current node. + proftime_T *tm, + int *timed_out ) { char_u *next; /* Next node. */ @@ -3779,12 +3784,14 @@ regmatch ( regitem_T *rp; int no; int status; /* one of the RA_ values: */ + int tm_count; /* counter for checking timeout */ #define RA_FAIL 1 /* something failed, abort */ #define RA_CONT 2 /* continue in inner loop */ #define RA_BREAK 3 /* break inner loop */ #define RA_MATCH 4 /* successful match */ #define RA_NOMATCH 5 /* didn't match */ + tm_count = 0; /* Make "regstack" and "backpos" empty. They are allocated and freed in * bt_regexec_both() to reduce malloc()/free() calls. */ regstack.ga_len = 0; @@ -3814,6 +3821,13 @@ regmatch ( status = RA_FAIL; break; } + if (tm != NULL && ++tm_count == 100) { + tm_count = 0; + if (profile_passed_limit(*tm)) { + status = RA_FAIL; + break; + } + } status = RA_CONT; #ifdef REGEXP_DEBUG -- cgit From 96e2c3945f13453070894c70c74e4da29d421dab Mon Sep 17 00:00:00 2001 From: Billy Su Date: Mon, 4 Mar 2019 09:47:13 +0800 Subject: lint: fix coding style --- src/nvim/regexp.c | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'src/nvim/regexp.c') diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index dc3fbbaeb5..55490446e5 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -1210,27 +1210,30 @@ char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp) return p; } -/* - * Return TRUE if the back reference is legal. We must have seen the close - * brace. - * TODO: Should also check that we don't refer to something that is repeated - * (+*=): what instance of the repetition should we match? - */ +/// +/// Return TRUE if the back reference is legal. We must have seen the close +/// brace. +/// TODO(billy4195): Should also check that we don't refer to something that is +/// repeated +/// (+*=): what instance of the repetition should we match? +/// static int seen_endbrace(int refnum) { if (!had_endbrace[refnum]) { char_u *p; - /* Trick: check if "@<=" or "@