summaryrefslogtreecommitdiff
path: root/regexec.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2012-06-16 13:56:50 +0100
committerDavid Mitchell <davem@iabyn.com>2012-06-16 14:09:41 +0100
commita8d1f4b493af3113b5d10ade9f824f102b7b040b (patch)
treee4b0b9b6fa861981feddc10051da177bef6d026e /regexec.c
parent4109bc0cd01be0ee6d8953b0e2c4f1638369a06e (diff)
downloadperl-a8d1f4b493af3113b5d10ade9f824f102b7b040b.tar.gz
fix paren unwinding with CURLYN, CURLYM
Historically, CURLYN and CURLYM didn't restore lastparen ($+) nor invalidate higher numbered paren slots (reg->offs[n].end = -1) when backtracking. Recent commit f6033a9d6c91e0c29d5aa5049361a529b5d7cdc4 fixed the lastparen issue, but then exposed the offs[n].end issue, which had previously been masked by the too-high lastparen value causing a previous state (such as a branch) to conveniently wipe out the offending parens on further backtracking. Or to put it another way, each backtracker should be expected to clean up his own mess, not hope that someone previous to him will do it for him. Fix this by doing the .end = 1 stuff on CURLYN,M failure as well as BRANCH/TRIE. For consistency, define a new macro to do it.
Diffstat (limited to 'regexec.c')
-rw-r--r--regexec.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/regexec.c b/regexec.c
index 764ea3db93..0bb8d7ed98 100644
--- a/regexec.c
+++ b/regexec.c
@@ -408,6 +408,13 @@ S_regcppush(pTHX_ const regexp *rex, I32 parenfloor)
(IV)(cp), (IV)PL_savestack_ix)); \
regcpblow(cp)
+#define UNWIND_PAREN(lp, lcp) \
+ for (n = rex->lastparen; n > lp; n--) \
+ rex->offs[n].end = -1; \
+ rex->lastparen = n; \
+ rex->lastcloseparen = lcp;
+
+
STATIC void
S_regcppop(pTHX_ regexp *rex)
{
@@ -3497,10 +3504,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
case TRIE_next_fail: /* we failed - try next alternative */
if ( ST.jump) {
REGCP_UNWIND(ST.cp);
- for (n = rex->lastparen; n > ST.lastparen; n--)
- rex->offs[n].end = -1;
- rex->lastparen = n;
- rex->lastcloseparen = ST.lastcloseparen;
+ UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
}
if (!--ST.accepted) {
DEBUG_EXECUTE_r({
@@ -5067,10 +5071,7 @@ NULL
no_final = 0;
}
REGCP_UNWIND(ST.cp);
- for (n = rex->lastparen; n > ST.lastparen; n--)
- rex->offs[n].end = -1;
- rex->lastparen = n;
- rex->lastcloseparen = ST.lastcloseparen;
+ UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
scan = ST.next_branch;
/* no more branches? */
if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) {
@@ -5264,8 +5265,7 @@ NULL
case CURLYM_B_fail: /* just failed to match a B */
REGCP_UNWIND(ST.cp);
- rex->lastparen = ST.lastparen;
- rex->lastcloseparen = ST.lastcloseparen;
+ UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
if (ST.minmod) {
I32 max = ARG2(ST.me);
if (max != REG_INFTY && ST.count == max)
@@ -5462,6 +5462,9 @@ NULL
PL_reginput = locinput; /* Could be reset... */
REGCP_UNWIND(ST.cp);
+ if (ST.paren) {
+ UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+ }
/* Couldn't or didn't -- move forward. */
ST.oldloc = locinput;
if (utf8_target)
@@ -5537,6 +5540,9 @@ NULL
/* failed to find B in a non-greedy match where c1,c2 invalid */
REGCP_UNWIND(ST.cp);
+ if (ST.paren) {
+ UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+ }
/* failed -- move forward one */
PL_reginput = locinput;
if (regrepeat(rex, ST.A, 1, depth)) {
@@ -5582,6 +5588,9 @@ NULL
/* failed to find B in a greedy match */
REGCP_UNWIND(ST.cp);
+ if (ST.paren) {
+ UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+ }
/* back up. */
if (--ST.count < ST.min)
sayNO;