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. --- regexp.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'regexp.h') diff --git a/regexp.h b/regexp.h index 5fb85ec684..65c2d38517 100644 --- a/regexp.h +++ b/regexp.h @@ -547,6 +547,9 @@ get_regex_charset_name(const U32 flags, STRLEN* const lenp) * to skip copying ... */ #define REXEC_COPY_SKIP_PRE 0x20 /* ...the $` part of the string, or */ #define REXEC_COPY_SKIP_POST 0x40 /* ...the $' part of the string */ +#define REXEC_FAIL_ON_UNDERFLOW 0x80 /* fail the match if $& would start before + the start pos (so s/.\G// would fail + on second iteration */ #if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) # define ReREFCNT_inc(re) \ -- cgit v1.2.1