0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 7.4.2219

Problem:    Recursive call to substitute gets stuck in sandbox. (Nikolai
            Pavlov)
Solution:   Handle the recursive call. (Christian Brabandt, closes #950)
            Add a test.
This commit is contained in:
Bram Moolenaar 2016-08-16 21:04:41 +02:00
parent 13d216d302
commit f5a39447a8
3 changed files with 91 additions and 60 deletions

View File

@ -4747,6 +4747,20 @@ check_secure(void)
static char_u *old_sub = NULL; /* previous substitute pattern */ static char_u *old_sub = NULL; /* previous substitute pattern */
static int global_need_beginline; /* call beginline() after ":g" */ static int global_need_beginline; /* call beginline() after ":g" */
/*
* Flags that are kept between calls to :substitute.
*/
typedef struct {
int do_all; /* do multiple substitutions per line */
int do_ask; /* ask for confirmation */
int do_count; /* count only */
int do_error; /* if false, ignore errors */
int do_print; /* print last line with subs. */
int do_list; /* list last line with subs. */
int do_number; /* list last line with line nr*/
int do_ic; /* ignore case flag */
} subflags_T;
/* do_sub() /* do_sub()
* *
* Perform a substitution from line eap->line1 to line eap->line2 using the * Perform a substitution from line eap->line1 to line eap->line2 using the
@ -4762,14 +4776,11 @@ do_sub(exarg_T *eap)
linenr_T lnum; linenr_T lnum;
long i = 0; long i = 0;
regmmatch_T regmatch; regmmatch_T regmatch;
static int do_all = FALSE; /* do multiple substitutions per line */ static subflags_T subflags = {FALSE, FALSE, FALSE, TRUE, FALSE,
static int do_ask = FALSE; /* ask for confirmation */ FALSE, FALSE, 0};
static int do_count = FALSE; /* count only */ #ifdef FEAT_EVAL
static int do_error = TRUE; /* if false, ignore errors */ subflags_T subflags_save;
static int do_print = FALSE; /* print last line with subs. */ #endif
static int do_list = FALSE; /* list last line with subs. */
static int do_number = FALSE; /* list last line with line nr*/
static int do_ic = 0; /* ignore case flag */
int save_do_all; /* remember user specified 'g' flag */ int save_do_all; /* remember user specified 'g' flag */
int save_do_ask; /* remember user specified 'c' flag */ int save_do_ask; /* remember user specified 'c' flag */
char_u *pat = NULL, *sub = NULL; /* init for GCC */ char_u *pat = NULL, *sub = NULL; /* init for GCC */
@ -4957,16 +4968,16 @@ do_sub(exarg_T *eap)
if (!p_ed) if (!p_ed)
{ {
if (p_gd) /* default is global on */ if (p_gd) /* default is global on */
do_all = TRUE; subflags.do_all = TRUE;
else else
do_all = FALSE; subflags.do_all = FALSE;
do_ask = FALSE; subflags.do_ask = FALSE;
} }
do_error = TRUE; subflags.do_error = TRUE;
do_print = FALSE; subflags.do_print = FALSE;
do_count = FALSE; subflags.do_count = FALSE;
do_number = FALSE; subflags.do_number = FALSE;
do_ic = 0; subflags.do_ic = 0;
} }
while (*cmd) while (*cmd)
{ {
@ -4975,40 +4986,40 @@ do_sub(exarg_T *eap)
* 'r' is never inverted. * 'r' is never inverted.
*/ */
if (*cmd == 'g') if (*cmd == 'g')
do_all = !do_all; subflags.do_all = !subflags.do_all;
else if (*cmd == 'c') else if (*cmd == 'c')
do_ask = !do_ask; subflags.do_ask = !subflags.do_ask;
else if (*cmd == 'n') else if (*cmd == 'n')
do_count = TRUE; subflags.do_count = TRUE;
else if (*cmd == 'e') else if (*cmd == 'e')
do_error = !do_error; subflags.do_error = !subflags.do_error;
else if (*cmd == 'r') /* use last used regexp */ else if (*cmd == 'r') /* use last used regexp */
which_pat = RE_LAST; which_pat = RE_LAST;
else if (*cmd == 'p') else if (*cmd == 'p')
do_print = TRUE; subflags.do_print = TRUE;
else if (*cmd == '#') else if (*cmd == '#')
{ {
do_print = TRUE; subflags.do_print = TRUE;
do_number = TRUE; subflags.do_number = TRUE;
} }
else if (*cmd == 'l') else if (*cmd == 'l')
{ {
do_print = TRUE; subflags.do_print = TRUE;
do_list = TRUE; subflags.do_list = TRUE;
} }
else if (*cmd == 'i') /* ignore case */ else if (*cmd == 'i') /* ignore case */
do_ic = 'i'; subflags.do_ic = 'i';
else if (*cmd == 'I') /* don't ignore case */ else if (*cmd == 'I') /* don't ignore case */
do_ic = 'I'; subflags.do_ic = 'I';
else else
break; break;
++cmd; ++cmd;
} }
if (do_count) if (subflags.do_count)
do_ask = FALSE; subflags.do_ask = FALSE;
save_do_all = do_all; save_do_all = subflags.do_all;
save_do_ask = do_ask; save_do_ask = subflags.do_ask;
/* /*
* check for a trailing count * check for a trailing count
@ -5017,7 +5028,7 @@ do_sub(exarg_T *eap)
if (VIM_ISDIGIT(*cmd)) if (VIM_ISDIGIT(*cmd))
{ {
i = getdigits(&cmd); i = getdigits(&cmd);
if (i <= 0 && !eap->skip && do_error) if (i <= 0 && !eap->skip && subflags.do_error)
{ {
EMSG(_(e_zerocount)); EMSG(_(e_zerocount));
return; return;
@ -5045,7 +5056,7 @@ do_sub(exarg_T *eap)
if (eap->skip) /* not executing commands, only parsing */ if (eap->skip) /* not executing commands, only parsing */
return; return;
if (!do_count && !curbuf->b_p_ma) if (!subflags.do_count && !curbuf->b_p_ma)
{ {
/* Substitution is not allowed in non-'modifiable' buffer */ /* Substitution is not allowed in non-'modifiable' buffer */
EMSG(_(e_modifiable)); EMSG(_(e_modifiable));
@ -5054,15 +5065,15 @@ do_sub(exarg_T *eap)
if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, &regmatch) == FAIL) if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, &regmatch) == FAIL)
{ {
if (do_error) if (subflags.do_error)
EMSG(_(e_invcmd)); EMSG(_(e_invcmd));
return; return;
} }
/* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */ /* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
if (do_ic == 'i') if (subflags.do_ic == 'i')
regmatch.rmm_ic = TRUE; regmatch.rmm_ic = TRUE;
else if (do_ic == 'I') else if (subflags.do_ic == 'I')
regmatch.rmm_ic = FALSE; regmatch.rmm_ic = FALSE;
sub_firstline = NULL; sub_firstline = NULL;
@ -5231,7 +5242,7 @@ do_sub(exarg_T *eap)
* 2. If do_count is set only increase the counter. * 2. If do_count is set only increase the counter.
* If do_ask is set, ask for confirmation. * If do_ask is set, ask for confirmation.
*/ */
if (do_count) if (subflags.do_count)
{ {
/* For a multi-line match, put matchcol at the NUL at /* For a multi-line match, put matchcol at the NUL at
* the end of the line and set nmatch to one, so that * the end of the line and set nmatch to one, so that
@ -5253,7 +5264,7 @@ do_sub(exarg_T *eap)
goto skip; goto skip;
} }
if (do_ask) if (subflags.do_ask)
{ {
int typed = 0; int typed = 0;
@ -5274,19 +5285,20 @@ do_sub(exarg_T *eap)
/* /*
* Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
*/ */
while (do_ask) while (subflags.do_ask)
{ {
if (exmode_active) if (exmode_active)
{ {
char_u *resp; char_u *resp;
colnr_T sc, ec; colnr_T sc, ec;
print_line_no_prefix(lnum, do_number, do_list); print_line_no_prefix(lnum,
subflags.do_number, subflags.do_list);
getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL); getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
curwin->w_cursor.col = regmatch.endpos[0].col - 1; curwin->w_cursor.col = regmatch.endpos[0].col - 1;
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec); getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
if (do_number || curwin->w_p_nu) if (subflags.do_number || curwin->w_p_nu)
{ {
int numw = number_width(curwin) + 1; int numw = number_width(curwin) + 1;
sc += numw; sc += numw;
@ -5420,13 +5432,13 @@ do_sub(exarg_T *eap)
if (typed == 'l') if (typed == 'l')
{ {
/* last: replace and then stop */ /* last: replace and then stop */
do_all = FALSE; subflags.do_all = FALSE;
line2 = lnum; line2 = lnum;
break; break;
} }
if (typed == 'a') if (typed == 'a')
{ {
do_ask = FALSE; subflags.do_ask = FALSE;
break; break;
} }
#ifdef FEAT_INS_EXPAND #ifdef FEAT_INS_EXPAND
@ -5469,22 +5481,28 @@ do_sub(exarg_T *eap)
* 3. substitute the string. * 3. substitute the string.
*/ */
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
if (do_count) if (subflags.do_count)
{ {
/* prevent accidentally changing the buffer by a function */ /* prevent accidentally changing the buffer by a function */
save_ma = curbuf->b_p_ma; save_ma = curbuf->b_p_ma;
curbuf->b_p_ma = FALSE; curbuf->b_p_ma = FALSE;
sandbox++; sandbox++;
} }
/* Save flags for recursion. They can change for e.g.
* :s/^/\=execute("s#^##gn") */
subflags_save = subflags;
#endif #endif
/* get length of substitution part */ /* get length of substitution part */
sublen = vim_regsub_multi(&regmatch, sublen = vim_regsub_multi(&regmatch,
sub_firstlnum - regmatch.startpos[0].lnum, sub_firstlnum - regmatch.startpos[0].lnum,
sub, sub_firstline, FALSE, p_magic, TRUE); sub, sub_firstline, FALSE, p_magic, TRUE);
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
if (do_count) /* Don't keep flags set by a recursive call. */
subflags = subflags_save;
if (subflags.do_count)
{ {
curbuf->b_p_ma = save_ma; curbuf->b_p_ma = save_ma;
if (sandbox > 0)
sandbox--; sandbox--;
goto skip; goto skip;
} }
@ -5578,7 +5596,7 @@ do_sub(exarg_T *eap)
if (sub_firstlnum <= line2) if (sub_firstlnum <= line2)
do_again = TRUE; do_again = TRUE;
else else
do_all = FALSE; subflags.do_all = FALSE;
} }
/* Remember next character to be copied. */ /* Remember next character to be copied. */
@ -5613,7 +5631,7 @@ do_sub(exarg_T *eap)
ml_append(lnum - 1, new_start, ml_append(lnum - 1, new_start,
(colnr_T)(p1 - new_start + 1), FALSE); (colnr_T)(p1 - new_start + 1), FALSE);
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L); mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
if (do_ask) if (subflags.do_ask)
appended_lines(lnum - 1, 1L); appended_lines(lnum - 1, 1L);
else else
{ {
@ -5654,7 +5672,7 @@ skip:
|| got_int || got_int
|| got_quit || got_quit
|| lnum > line2 || lnum > line2
|| !(do_all || do_again) || !(subflags.do_all || do_again)
|| (sub_firstline[matchcol] == NUL && nmatch <= 1 || (sub_firstline[matchcol] == NUL && nmatch <= 1
&& !re_multiline(regmatch.regprog))); && !re_multiline(regmatch.regprog)));
nmatch = -1; nmatch = -1;
@ -5708,7 +5726,7 @@ skip:
ml_delete(lnum, (int)FALSE); ml_delete(lnum, (int)FALSE);
mark_adjust(lnum, lnum + nmatch_tl - 1, mark_adjust(lnum, lnum + nmatch_tl - 1,
(long)MAXLNUM, -nmatch_tl); (long)MAXLNUM, -nmatch_tl);
if (do_ask) if (subflags.do_ask)
deleted_lines(lnum, nmatch_tl); deleted_lines(lnum, nmatch_tl);
--lnum; --lnum;
line2 -= nmatch_tl; /* nr of lines decreases */ line2 -= nmatch_tl; /* nr of lines decreases */
@ -5717,7 +5735,7 @@ skip:
/* When asking, undo is saved each time, must also set /* When asking, undo is saved each time, must also set
* changed flag each time. */ * changed flag each time. */
if (do_ask) if (subflags.do_ask)
changed_bytes(lnum, 0); changed_bytes(lnum, 0);
else else
{ {
@ -5779,7 +5797,7 @@ outofmem:
vim_free(sub_firstline); /* may have to free allocated copy of the line */ vim_free(sub_firstline); /* may have to free allocated copy of the line */
/* ":s/pat//n" doesn't move the cursor */ /* ":s/pat//n" doesn't move the cursor */
if (do_count) if (subflags.do_count)
curwin->w_cursor = old_cursor; curwin->w_cursor = old_cursor;
if (sub_nsubs > start_nsubs) if (sub_nsubs > start_nsubs)
@ -5791,20 +5809,22 @@ outofmem:
if (!global_busy) if (!global_busy)
{ {
if (!do_ask) /* when interactive leave cursor on the match */ /* when interactive leave cursor on the match */
if (!subflags.do_ask)
{ {
if (endcolumn) if (endcolumn)
coladvance((colnr_T)MAXCOL); coladvance((colnr_T)MAXCOL);
else else
beginline(BL_WHITE | BL_FIX); beginline(BL_WHITE | BL_FIX);
} }
if (!do_sub_msg(do_count) && do_ask) if (!do_sub_msg(subflags.do_count) && subflags.do_ask)
MSG(""); MSG("");
} }
else else
global_need_beginline = TRUE; global_need_beginline = TRUE;
if (do_print) if (subflags.do_print)
print_line(curwin->w_cursor.lnum, do_number, do_list); print_line(curwin->w_cursor.lnum,
subflags.do_number, subflags.do_list);
} }
else if (!global_busy) else if (!global_busy)
{ {
@ -5812,12 +5832,12 @@ outofmem:
EMSG(_(e_interr)); EMSG(_(e_interr));
else if (got_match) /* did find something but nothing substituted */ else if (got_match) /* did find something but nothing substituted */
MSG(""); MSG("");
else if (do_error) /* nothing found */ else if (subflags.do_error) /* nothing found */
EMSG2(_(e_patnotf2), get_search_pat()); EMSG2(_(e_patnotf2), get_search_pat());
} }
#ifdef FEAT_FOLDING #ifdef FEAT_FOLDING
if (do_ask && hasAnyFolding(curwin)) if (subflags.do_ask && hasAnyFolding(curwin))
/* Cursor position may require updating */ /* Cursor position may require updating */
changed_window_setting(); changed_window_setting();
#endif #endif
@ -5825,8 +5845,8 @@ outofmem:
vim_regfree(regmatch.regprog); vim_regfree(regmatch.regprog);
/* Restore the flag values, they can be used for ":&&". */ /* Restore the flag values, they can be used for ":&&". */
do_all = save_do_all; subflags.do_all = save_do_all;
do_ask = save_do_ask; subflags.do_ask = save_do_ask;
} }
/* /*

View File

@ -30,3 +30,12 @@ func Test_equivalence_re2()
set re=2 set re=2
call s:equivalence_test() call s:equivalence_test()
endfunc endfunc
func Test_recursive_substitute()
new
s/^/\=execute("s#^##gn")
" check we are now not in the sandbox
call setwinvar(1, 'myvar', 1)
bwipe!
endfunc

View File

@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2219,
/**/ /**/
2218, 2218,
/**/ /**/