summaryrefslogtreecommitdiff
path: root/pp_ctl.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2013-07-16 16:31:04 +0100
committerDavid Mitchell <davem@iabyn.com>2013-07-28 10:33:39 +0100
commitd5e7783a3e8dcf16e8d64aae0d77eed33dc12a5c (patch)
tree90eae92d4e416b5f4abf9a1e7bcd9e4f2ddf2db1 /pp_ctl.c
parentfeb38e3b9dba8f9f75fe6c737d7c4d99ff1aca46 (diff)
downloadperl-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_ctl.c')
-rw-r--r--pp_ctl.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index 87eadd2aeb..ff3d661a70 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -229,7 +229,7 @@ PP(pp_substcont)
if (CxONCE(cx) || s < orig ||
!CALLREGEXEC(rx, s, cx->sb_strend, orig,
(s == m), cx->sb_targ, NULL,
- (REXEC_IGNOREPOS|REXEC_NOT_FIRST)))
+ (REXEC_IGNOREPOS|REXEC_NOT_FIRST|REXEC_FAIL_ON_UNDERFLOW)))
{
SV *targ = cx->sb_targ;