regexec(): use regtry(&s) not regtry(&startpos)
authorDavid Mitchell <davem@iabyn.com>
Fri, 19 Jul 2013 15:37:04 +0000 (16:37 +0100)
committerDavid Mitchell <davem@iabyn.com>
Sun, 28 Jul 2013 09:33:39 +0000 (10:33 +0100)
regexec() has several cases such as anchored, floating etc, and for each
of these it will call regtry() one or more times to match at likely
starting positions. In all cases but one, it calls regtry(&s), where
s is the current start position that moves as we try new positions. In
the one final case it uses startpos instead, which is supposed to be static.
The actual code looks like:

    if (s == startpos && regtry(&startpos))

which might seem harmless, but under things like (*COMMIT), regtry can
update the pointer value (which is why its address is taken). So in this
(obscure) case, the wrong pointer gets updated.

regexec.c
t/re/pat_advanced.t

index 8d2fbfd..00ec190 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -2458,7 +2458,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, char *strend,
     /* Simplest case:  anchored match need be tried only once. */
     /*  [unless only anchor is BOL and multiline is set] */
     if (prog->extflags & (RXf_ANCH & ~RXf_ANCH_GPOS)) {
-       if (s == startpos && regtry(reginfo, &startpos))
+       if (s == startpos && regtry(reginfo, &s))
            goto got_it;
        else if (multiline || (prog->intflags & PREGf_IMPLICIT)
                 || (prog->extflags & RXf_ANCH_MBOL)) /* XXXX SBOL? */
index e6c5f39..52005ef 100644 (file)
@@ -1333,6 +1333,8 @@ sub run_tests {
         1 while /(a+b?)(*COMMIT)(?{$count++; push @res,$1})(*FAIL)/g;
         is($count, 1, "Expect 1 with (*COMMIT)");
         is("@res", "aaab", "Adjacent (*COMMIT) works as expected");
+
+       ok("1\n2a\n" !~ /^\d+(*COMMIT)\w+/m, "COMMIT and anchors");
     }
 
     {