Revision: 642
http://vcs.pcre.org/viewvc?view=rev&revision=642
Author: ph10
Date: 2011-07-28 19:59:40 +0100 (Thu, 28 Jul 2011)
Log Message:
-----------
Avoid false positive for infinite recursion by not checking conditionals at
compile time, but add tests at runtime that also catch infinite mutual
recursion.
Modified Paths:
--------------
code/trunk/ChangeLog
code/trunk/doc/pcreapi.3
code/trunk/pcre.h.in
code/trunk/pcre_compile.c
code/trunk/pcre_dfa_exec.c
code/trunk/pcre_exec.c
code/trunk/pcre_internal.h
code/trunk/pcretest.c
code/trunk/testdata/testinput11
code/trunk/testdata/testinput2
code/trunk/testdata/testinput7
code/trunk/testdata/testoutput11
code/trunk/testdata/testoutput2
code/trunk/testdata/testoutput7
Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/ChangeLog 2011-07-28 18:59:40 UTC (rev 642)
@@ -195,7 +195,21 @@
38. Add minix to OS list not supporting the -S option in pcretest.
+39. PCRE tries to detect cases of infinite recursion at compile time, but it
+ cannot analyze patterns in sufficient detail to catch mutual recursions
+ such as ((?1))((?2)). There is now a runtime test that gives an error if a
+ subgroup is called recursively as a subpattern for a second time at the
+ same position in the subject string. In previous releases this might have
+ been caught by the recursion limit, or it might have run out of stack.
+
+40. A pattern such as /(?(R)a+|(?R)b)/ is quite safe, as the recursion can
+ happen only once. PCRE was, however incorrectly giving a compile time error
+ "recursive call could loop indefinitely" because it cannot analyze the
+ pattern in sufficient detail. The compile time test no longer happens when
+ PCRE is compiling a conditional subpattern, but actual runaway loops are
+ now caught at runtime (see 39 above).
+
Version 8.12 15-Jan-2011
------------------------
Modified: code/trunk/doc/pcreapi.3
===================================================================
--- code/trunk/doc/pcreapi.3 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/doc/pcreapi.3 2011-07-28 18:59:40 UTC (rev 642)
@@ -1862,6 +1862,16 @@
fact sufficient to detect this case, but this special error code for
PCRE_PARTIAL_HARD precedes the implementation of returned information; it is
retained for backwards compatibility.
+.sp
+ PCRE_ERROR_RECURSELOOP (-26)
+.sp
+This error is returned when \fBpcre_exec()\fP detects a recursion loop within
+the pattern. Specifically, it means that either the whole pattern or a
+subpattern has been called recursively for the second time at the same position
+in the subject string. Some simple patterns that might do this are detected and
+faulted at compile time, but more complicated cases, in particular mutual
+recursions between two different subpatterns, cannot be detected until run
+time.
.P
Error numbers -16 to -20 and -22 are not used by \fBpcre_exec()\fP.
.
@@ -2369,6 +2379,6 @@
.rs
.sp
.nf
-Last updated: 07 May 2011
+Last updated: 28 July 2011
Copyright (c) 1997-2011 University of Cambridge.
.fi
Modified: code/trunk/pcre.h.in
===================================================================
--- code/trunk/pcre.h.in 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/pcre.h.in 2011-07-28 18:59:40 UTC (rev 642)
@@ -163,6 +163,7 @@
#define PCRE_ERROR_BADNEWLINE (-23)
#define PCRE_ERROR_BADOFFSET (-24)
#define PCRE_ERROR_SHORTUTF8 (-25)
+#define PCRE_ERROR_RECURSELOOP (-26)
/* Specific error codes for UTF-8 validity checks */
Modified: code/trunk/pcre_compile.c
===================================================================
--- code/trunk/pcre_compile.c 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/pcre_compile.c 2011-07-28 18:59:40 UTC (rev 642)
@@ -546,8 +546,8 @@
/* Definition to allow mutual recursion */
static BOOL
- compile_regex(int, uschar **, const uschar **, int *, BOOL, BOOL, int, int *,
- int *, branch_chain *, compile_data *, int *);
+ compile_regex(int, uschar **, const uschar **, int *, BOOL, BOOL, int, int,
+ int *, int *, branch_chain *, compile_data *, int *);
@@ -3035,6 +3035,7 @@
firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)
reqbyteptr set to the last literal character required, else < 0
bcptr points to current branch chain
+ cond_depth conditional nesting depth
cd contains pointers to tables etc.
lengthptr NULL during the real compile phase
points to length accumulator during pre-compile phase
@@ -3046,7 +3047,7 @@
static BOOL
compile_branch(int *optionsptr, uschar **codeptr, const uschar **ptrptr,
int *errorcodeptr, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr,
- compile_data *cd, int *lengthptr)
+ int cond_depth, compile_data *cd, int *lengthptr)
{
int repeat_type, op_type;
int repeat_min = 0, repeat_max = 0; /* To please picky compilers */
@@ -5759,9 +5760,14 @@
/* If not a forward reference, and the subpattern is still open,
this is a recursive call. We check to see if this is a left
- recursion that could loop for ever, and diagnose that case. */
+ recursion that could loop for ever, and diagnose that case. We
+ must not, however, do this check if we are in a conditional
+ subpattern because the condition might be testing for recursion in
+ a pattern such as /(?(R)a+|(?R)b)/, which is perfectly valid.
+ Forever loops are also detected at runtime, so those that occur in
+ conditional subpatterns will be picked up then. */
- else if (GET(called, 1) == 0 &&
+ else if (GET(called, 1) == 0 && cond_depth <= 0 &&
could_be_empty(called, code, bcptr, utf8, cd))
{
*errorcodeptr = ERR40;
@@ -5893,27 +5899,29 @@
repeated. We copy code into a non-register variable (tempcode) in order to
be able to pass its address because some compilers complain otherwise. */
- previous = code; /* For handling repetition */
- *code = bravalue;
- tempcode = code;
- tempreqvary = cd->req_varyopt; /* Save value before bracket */
- length_prevgroup = 0; /* Initialize for pre-compile phase */
-
- if (!compile_regex(
- newoptions, /* The complete new option state */
- &tempcode, /* Where to put code (updated) */
- &ptr, /* Input pointer (updated) */
- errorcodeptr, /* Where to put an error message */
+ previous = code; /* For handling repetition */
+ *code = bravalue;
+ tempcode = code;
+ tempreqvary = cd->req_varyopt; /* Save value before bracket */
+ length_prevgroup = 0; /* Initialize for pre-compile phase */
+
+ if (!compile_regex(
+ newoptions, /* The complete new option state */
+ &tempcode, /* Where to put code (updated) */
+ &ptr, /* Input pointer (updated) */
+ errorcodeptr, /* Where to put an error message */
(bravalue == OP_ASSERTBACK ||
bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
- reset_bracount, /* True if (?| group */
- skipbytes, /* Skip over bracket number */
- &subfirstbyte, /* For possible first char */
- &subreqbyte, /* For possible last char */
- bcptr, /* Current branch chain */
- cd, /* Tables block */
- (lengthptr == NULL)? NULL : /* Actual compile phase */
- &length_prevgroup /* Pre-compile phase */
+ reset_bracount, /* True if (?| group */
+ skipbytes, /* Skip over bracket number */
+ cond_depth +
+ ((bravalue == OP_COND)?1:0), /* Depth of condition subpatterns */
+ &subfirstbyte, /* For possible first char */
+ &subreqbyte, /* For possible last char */
+ bcptr, /* Current branch chain */
+ cd, /* Tables block */
+ (lengthptr == NULL)? NULL : /* Actual compile phase */
+ &length_prevgroup /* Pre-compile phase */
))
goto FAILED;
@@ -6371,6 +6379,7 @@
lookbehind TRUE if this is a lookbehind assertion
reset_bracount TRUE to reset the count for each branch
skipbytes skip this many bytes at start (for brackets and OP_COND)
+ cond_depth depth of nesting for conditional subpatterns
firstbyteptr place to put the first required character, or a negative number
reqbyteptr place to put the last required character, or a negative number
bcptr pointer to the chain of currently open branches
@@ -6384,8 +6393,8 @@
static BOOL
compile_regex(int options, uschar **codeptr, const uschar **ptrptr,
int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes,
- int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd,
- int *lengthptr)
+ int cond_depth, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr,
+ compile_data *cd, int *lengthptr)
{
const uschar *ptr = *ptrptr;
uschar *code = *codeptr;
@@ -6464,7 +6473,8 @@
into the length. */
if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstbyte,
- &branchreqbyte, &bc, cd, (lengthptr == NULL)? NULL : &length))
+ &branchreqbyte, &bc, cond_depth, cd,
+ (lengthptr == NULL)? NULL : &length))
{
*ptrptr = ptr;
return FALSE;
@@ -7190,7 +7200,7 @@
code = cworkspace;
*code = OP_BRA;
(void)compile_regex(cd->external_options, &code, &ptr, &errorcode, FALSE,
- FALSE, 0, &firstbyte, &reqbyte, NULL, cd, &length);
+ FALSE, 0, 0, &firstbyte, &reqbyte, NULL, cd, &length);
if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;
DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,
@@ -7263,7 +7273,7 @@
ptr = (const uschar *)pattern + skipatstart;
code = (uschar *)codestart;
*code = OP_BRA;
-(void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0,
+(void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 0,
&firstbyte, &reqbyte, NULL, cd, NULL);
re->top_bracket = cd->bracount;
re->top_backref = cd->top_backref;
Modified: code/trunk/pcre_dfa_exec.c
===================================================================
--- code/trunk/pcre_dfa_exec.c 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/pcre_dfa_exec.c 2011-07-28 18:59:40 UTC (rev 642)
@@ -328,7 +328,6 @@
workspace vector of workspace
wscount size of same
rlevel function call recursion level
- recursing regex recursive call level
Returns: > 0 => number of match offset pairs placed in offsets
= 0 => offsets overflowed; longest matches are present
@@ -392,8 +391,7 @@
int offsetcount,
int *workspace,
int wscount,
- int rlevel,
- int recursing)
+ int rlevel)
{
stateblock *active_states, *new_states, *temp_states;
stateblock *next_active_state, *next_new_state;
@@ -402,6 +400,8 @@
const uschar *ptr;
const uschar *end_code, *first_op;
+dfa_recursion_info new_recursive;
+
int active_count, new_count, match_count;
/* Some fields in the md block are frequently referenced, so we load them into
@@ -425,8 +425,8 @@
(2 * INTS_PER_STATEBLOCK);
DPRINTF(("\n%.*s---------------------\n"
- "%.*sCall to internal_dfa_exec f=%d r=%d\n",
- rlevel*2-2, SP, rlevel*2-2, SP, rlevel, recursing));
+ "%.*sCall to internal_dfa_exec f=%d\n",
+ rlevel*2-2, SP, rlevel*2-2, SP, rlevel));
ctypes = md->tables + ctypes_offset;
lcc = md->tables + lcc_offset;
@@ -2521,8 +2521,7 @@
sizeof(local_offsets)/sizeof(int), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
- rlevel, /* function recursion level */
- recursing); /* pass on regex recursion */
+ rlevel); /* function recursion level */
if (rc == PCRE_ERROR_DFA_UITEM) return rc;
if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK))
@@ -2587,7 +2586,7 @@
{
int value = GET2(code, LINK_SIZE+2);
if (value != RREF_ANY) return PCRE_ERROR_DFA_UCOND;
- if (recursing > 0)
+ if (md->recursive != NULL)
{ ADD_ACTIVE(state_offset + LINK_SIZE + 4, 0); }
else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
}
@@ -2611,8 +2610,7 @@
sizeof(local_offsets)/sizeof(int), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
- rlevel, /* function recursion level */
- recursing); /* pass on regex recursion */
+ rlevel); /* function recursion level */
if (rc == PCRE_ERROR_DFA_UITEM) return rc;
if ((rc >= 0) ==
@@ -2627,28 +2625,48 @@
/*-----------------------------------------------------------------*/
case OP_RECURSE:
{
+ dfa_recursion_info *ri;
int local_offsets[1000];
int local_workspace[1000];
+ const uschar *callpat = start_code + GET(code, 1);
+ int recno = (callpat == md->start_code)? 0 :
+ GET2(callpat, 1 + LINK_SIZE);
int rc;
- DPRINTF(("%.*sStarting regex recursion %d\n", rlevel*2-2, SP,
- recursing + 1));
+ DPRINTF(("%.*sStarting regex recursion\n", rlevel*2-2, SP));
+
+ /* Check for repeating a recursion without advancing the subject
+ pointer. This should catch convoluted mutual recursions. (Some simple
+ cases are caught at compile time.) */
+
+ for (ri = md->recursive; ri != NULL; ri = ri->prevrec)
+ if (recno == ri->group_num && ptr == ri->subject_position)
+ return PCRE_ERROR_RECURSELOOP;
+ /* Remember this recursion and where we started it so as to
+ catch infinite loops. */
+
+ new_recursive.group_num = recno;
+ new_recursive.subject_position = ptr;
+ new_recursive.prevrec = md->recursive;
+ md->recursive = &new_recursive;
+
rc = internal_dfa_exec(
md, /* fixed match data */
- start_code + GET(code, 1), /* this subexpression's code */
+ callpat, /* this subexpression's code */
ptr, /* where we currently are */
(int)(ptr - start_subject), /* start offset */
local_offsets, /* offset vector */
sizeof(local_offsets)/sizeof(int), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
- rlevel, /* function recursion level */
- recursing + 1); /* regex recurse level */
+ rlevel); /* function recursion level */
- DPRINTF(("%.*sReturn from regex recursion %d: rc=%d\n", rlevel*2-2, SP,
- recursing + 1, rc));
+ md->recursive = new_recursive.prevrec; /* Done this recursion */
+ DPRINTF(("%.*sReturn from regex recursion: rc=%d\n", rlevel*2-2, SP,
+ rc));
+
/* Ran out of internal offsets */
if (rc == 0) return PCRE_ERROR_DFA_RECURSE;
@@ -2714,8 +2732,7 @@
sizeof(local_offsets)/sizeof(int), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
- rlevel, /* function recursion level */
- recursing); /* pass on regex recursion */
+ rlevel); /* function recursion level */
/* Failed to match */
@@ -2784,8 +2801,7 @@
sizeof(local_offsets)/sizeof(int), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
- rlevel, /* function recursion level */
- recursing); /* pass on regex recursion */
+ rlevel); /* function recursion level */
if (rc >= 0)
{
@@ -3377,6 +3393,7 @@
/* OK, now we can do the business */
md->start_used_ptr = current_subject;
+ md->recursive = NULL;
rc = internal_dfa_exec(
md, /* fixed match data */
@@ -3387,8 +3404,7 @@
offsetcount, /* size of same */
workspace, /* workspace vector */
wscount, /* size of same */
- 0, /* function recurse level */
- 0); /* regex recurse level */
+ 0); /* function recurse level */
/* Anything other than "no match" means we are done, always; otherwise, carry
on only if not anchored. */
Modified: code/trunk/pcre_exec.c
===================================================================
--- code/trunk/pcre_exec.c 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/pcre_exec.c 2011-07-28 18:59:40 UTC (rev 642)
@@ -1501,12 +1501,25 @@
case OP_RECURSE:
{
+ recursion_info *ri;
+ int recno;
+
callpat = md->start_code + GET(ecode, 1);
- new_recursive.group_num = (callpat == md->start_code)? 0 :
- GET2(callpat, 1 + LINK_SIZE);
+ recno = (callpat == md->start_code)? 0 :
+ GET2(callpat, 1 + LINK_SIZE);
+
+ /* Check for repeating a recursion without advancing the subject pointer.
+ This should catch convoluted mutual recursions. (Some simple cases are
+ caught at compile time.) */
+
+ for (ri = md->recursive; ri != NULL; ri = ri->prevrec)
+ if (recno == ri->group_num && eptr == ri->subject_position)
+ RRETURN(PCRE_ERROR_RECURSELOOP);
/* Add to "recursing stack" */
+ new_recursive.group_num = recno;
+ new_recursive.subject_position = eptr;
new_recursive.prevrec = md->recursive;
md->recursive = &new_recursive;
Modified: code/trunk/pcre_internal.h
===================================================================
--- code/trunk/pcre_internal.h 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/pcre_internal.h 2011-07-28 18:59:40 UTC (rev 642)
@@ -7,7 +7,7 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2010 University of Cambridge
+ Copyright (c) 1997-2011 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -1753,7 +1753,7 @@
} compile_data;
/* Structure for maintaining a chain of pointers to the currently incomplete
-branches, for testing for left recursion. */
+branches, for testing for left recursion while compiling. */
typedef struct branch_chain {
struct branch_chain *outer;
@@ -1761,18 +1761,28 @@
} branch_chain;
/* Structure for items in a linked list that represents an explicit recursive
-call within the pattern. */
+call within the pattern; used by pcre_exec(). */
typedef struct recursion_info {
struct recursion_info *prevrec; /* Previous recursion record (or NULL) */
int group_num; /* Number of group that was called */
int *offset_save; /* Pointer to start of saved offsets */
int saved_max; /* Number of saved offsets */
+ USPTR subject_position; /* Position at start of recursion */
} recursion_info;
+/* A similar structure for pcre_dfa_exec(). */
+
+typedef struct dfa_recursion_info {
+ struct dfa_recursion_info *prevrec;
+ int group_num;
+ USPTR subject_position;
+} dfa_recursion_info;
+
/* Structure for building a chain of data for holding the values of the subject
pointer at the start of each subpattern, so as to detect when an empty string
-has been matched by a subpattern - to break infinite loops. */
+has been matched by a subpattern - to break infinite loops; used by
+pcre_exec(). */
typedef struct eptrblock {
struct eptrblock *epb_prev;
@@ -1832,18 +1842,19 @@
functions. */
typedef struct dfa_match_data {
- const uschar *start_code; /* Start of the compiled pattern */
- const uschar *start_subject; /* Start of the subject string */
- const uschar *end_subject; /* End of subject string */
- const uschar *start_used_ptr; /* Earliest consulted character */
- const uschar *tables; /* Character tables */
- int start_offset; /* The start offset value */
- int moptions; /* Match options */
- int poptions; /* Pattern options */
- int nltype; /* Newline type */
- int nllen; /* Newline string length */
- uschar nl[4]; /* Newline string when fixed */
- void *callout_data; /* To pass back to callouts */
+ const uschar *start_code; /* Start of the compiled pattern */
+ const uschar *start_subject; /* Start of the subject string */
+ const uschar *end_subject; /* End of subject string */
+ const uschar *start_used_ptr; /* Earliest consulted character */
+ const uschar *tables; /* Character tables */
+ int start_offset; /* The start offset value */
+ int moptions; /* Match options */
+ int poptions; /* Pattern options */
+ int nltype; /* Newline type */
+ int nllen; /* Newline string length */
+ uschar nl[4]; /* Newline string when fixed */
+ void *callout_data; /* To pass back to callouts */
+ dfa_recursion_info *recursive; /* Linked list of recursion data */
} dfa_match_data;
/* Bit definitions for entries in the pcre_ctypes table. */
Modified: code/trunk/pcretest.c
===================================================================
--- code/trunk/pcretest.c 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/pcretest.c 2011-07-28 18:59:40 UTC (rev 642)
@@ -225,7 +225,8 @@
"not used - internal error",
"invalid combination of newline options",
"bad offset value",
- NULL /* SHORTUTF8 is handled specially */
+ NULL, /* SHORTUTF8 is handled specially */
+ "nested recursion at the same subject position"
};
Modified: code/trunk/testdata/testinput11
===================================================================
--- code/trunk/testdata/testinput11 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/testdata/testinput11 2011-07-28 18:59:40 UTC (rev 642)
@@ -654,4 +654,16 @@
/^\N{1,}/
abc\ndef
+/(?(R)a+|(?R)b)/
+ aaaabcde
+
+/(?(R)a+|((?R))b)/
+ aaaabcde
+
+/((?(R)a+|(?1)b))/
+ aaaabcde
+
+/((?(R1)a+|(?1)b))/
+ aaaabcde
+
/-- End of testinput11 --/
Modified: code/trunk/testdata/testinput2
===================================================================
--- code/trunk/testdata/testinput2 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/testdata/testinput2 2011-07-28 18:59:40 UTC (rev 642)
@@ -3818,4 +3818,15 @@
/[:a[:abc]b:]/
+/((?2))((?1))/
+ abc
+
+/((?(R2)a+|(?1)b))/
+ aaaabcde
+
+/(?(R)a*(?1)|((?R))b)/
+ aaaabcde
+
+/(a+|(?R)b)/
+
/-- End of testinput2 --/
Modified: code/trunk/testdata/testinput7
===================================================================
--- code/trunk/testdata/testinput7 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/testdata/testinput7 2011-07-28 18:59:40 UTC (rev 642)
@@ -4681,4 +4681,22 @@
abcxyz
pqrxyz
+/((?2))((?1))/
+ abc
+
+/(?(R)a+|(?R)b)/
+ aaaabcde
+
+/(?(R)a+|((?R))b)/
+ aaaabcde
+
+/((?(R)a+|(?1)b))/
+ aaaabcde
+
+/((?(R2)a+|(?1)b))/
+ aaaabcde
+
+/(?(R)a*(?1)|((?R))b)/
+ aaaabcde
+
/-- End of testinput7 --/
Modified: code/trunk/testdata/testoutput11
===================================================================
--- code/trunk/testdata/testoutput11 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/testdata/testoutput11 2011-07-28 18:59:40 UTC (rev 642)
@@ -1233,4 +1233,23 @@
abc\ndef
0: abc
+/(?(R)a+|(?R)b)/
+ aaaabcde
+ 0: aaaab
+
+/(?(R)a+|((?R))b)/
+ aaaabcde
+ 0: aaaab
+ 1: aaaa
+
+/((?(R)a+|(?1)b))/
+ aaaabcde
+ 0: aaaab
+ 1: aaaab
+
+/((?(R1)a+|(?1)b))/
+ aaaabcde
+ 0: aaaab
+ 1: aaaab
+
/-- End of testinput11 --/
Modified: code/trunk/testdata/testoutput2
===================================================================
--- code/trunk/testdata/testoutput2 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/testdata/testoutput2 2011-07-28 18:59:40 UTC (rev 642)
@@ -12139,4 +12139,19 @@
/[:a[:abc]b:]/
Failed: unknown POSIX class name at offset 5
+/((?2))((?1))/
+ abc
+Error -26 (nested recursion at the same subject position)
+
+/((?(R2)a+|(?1)b))/
+ aaaabcde
+Error -26 (nested recursion at the same subject position)
+
+/(?(R)a*(?1)|((?R))b)/
+ aaaabcde
+Error -26 (nested recursion at the same subject position)
+
+/(a+|(?R)b)/
+Failed: recursive call could loop indefinitely at offset 7
+
/-- End of testinput2 --/
Modified: code/trunk/testdata/testoutput7
===================================================================
--- code/trunk/testdata/testoutput7 2011-07-25 16:56:54 UTC (rev 641)
+++ code/trunk/testdata/testoutput7 2011-07-28 18:59:40 UTC (rev 642)
@@ -7822,4 +7822,28 @@
pqrxyz
0: xyz
+/((?2))((?1))/
+ abc
+Error -26 (nested recursion at the same subject position)
+
+/(?(R)a+|(?R)b)/
+ aaaabcde
+ 0: aaaab
+
+/(?(R)a+|((?R))b)/
+ aaaabcde
+ 0: aaaab
+
+/((?(R)a+|(?1)b))/
+ aaaabcde
+ 0: aaaab
+
+/((?(R2)a+|(?1)b))/
+ aaaabcde
+Error -17 (backreference condition or recursion test not supported for DFA matching)
+
+/(?(R)a*(?1)|((?R))b)/
+ aaaabcde
+Error -26 (nested recursion at the same subject position)
+
/-- End of testinput7 --/