s/.(?=.\G)/X/g: refuse to go backwards
authorDavid Mitchell <davem@iabyn.com>
Tue, 16 Jul 2013 15:31:04 +0000 (16:31 +0100)
committerDavid Mitchell <davem@iabyn.com>
Sun, 28 Jul 2013 09:33:39 +0000 (10:33 +0100)
commitd5e7783a3e8dcf16e8d64aae0d77eed33dc12a5c
tree90eae92d4e416b5f4abf9a1e7bcd9e4f2ddf2db1
parentfeb38e3b9dba8f9f75fe6c737d7c4d99ff1aca46
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.
pod/perlre.pod
pp_ctl.c
pp_hot.c
regexec.c
regexp.h
t/re/subst.t