diff options
author | David Mitchell <davem@iabyn.com> | 2013-07-16 16:31:04 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2013-07-28 10:33:39 +0100 |
commit | d5e7783a3e8dcf16e8d64aae0d77eed33dc12a5c (patch) | |
tree | 90eae92d4e416b5f4abf9a1e7bcd9e4f2ddf2db1 /pp_hot.c | |
parent | feb38e3b9dba8f9f75fe6c737d7c4d99ff1aca46 (diff) | |
download | perl-d5e7783a3e8dcf16e8d64aae0d77eed33dc12a5c.tar.gz |
s/.(?=.\G)/X/g: refuse to go backwards
On something like:
$_ = "123456789";
pos = 6;
s/.(?=.\G)/X/g;
each iteration could in theory start with pos one character to the left
of the previous position, and with the substitution replacing bits that
it has already replaced. Since that way madness lies, ban any attempt by
s/// to substitute to the left of a previous position.
To implement this, add a new flag to regexec(), REXEC_FAIL_ON_UNDERFLOW.
This tells regexec() to return failure even if the match itself succeeded,
but where the start of $& is before the passed stringarg point.
This change caused one existing test to fail (which was added about a year
ago):
$_="abcdef";
s/bc|(.)\G(.)/$1 ? "[$1-$2]" : "XX"/ge;
print; # used to print "aXX[c-d][d-e][e-f]"; now prints "aXXdef"
I think that that test relies on ambiguous behaviour, and that my change
makes things saner.
Note that s/// with \G is generally very under-tested.
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 5 |
1 files changed, 3 insertions, 2 deletions
@@ -2233,7 +2233,7 @@ PP(pp_subst) } while (CALLREGEXEC(rx, s, strend, orig, s == m, TARG, NULL, /* don't match same null twice */ - REXEC_NOT_FIRST|REXEC_IGNOREPOS)); + REXEC_NOT_FIRST|REXEC_IGNOREPOS|REXEC_FAIL_ON_UNDERFLOW)); if (s != d) { I32 i = strend - s; SvCUR_set(TARG, d - SvPVX_const(TARG) + i); @@ -2321,7 +2321,8 @@ PP(pp_subst) if (once) break; } while (CALLREGEXEC(rx, s, strend, orig, s == m, - TARG, NULL, REXEC_NOT_FIRST|REXEC_IGNOREPOS)); + TARG, NULL, + REXEC_NOT_FIRST|REXEC_IGNOREPOS|REXEC_FAIL_ON_UNDERFLOW)); sv_catpvn_nomg_maybeutf8(dstr, s, strend - s, DO_UTF8(TARG)); if (rpm->op_pmflags & PMf_NONDESTRUCT) { |