From d5e7783a3e8dcf16e8d64aae0d77eed33dc12a5c Mon Sep 17 00:00:00 2001 From: David Mitchell Date: Tue, 16 Jul 2013 16:31:04 +0100 Subject: 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. --- pp_ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pp_ctl.c') 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; -- cgit v1.2.1