Revision: 1498
http://vcs.pcre.org/viewvc?view=rev&revision=1498
Author: ph10
Date: 2014-08-08 16:22:51 +0100 (Fri, 08 Aug 2014)
Log Message:
-----------
Fix compile-time loop for recursive reference within a group with an indefinite
repeat.
Modified Paths:
--------------
code/trunk/ChangeLog
code/trunk/pcre_compile.c
code/trunk/testdata/testinput1
code/trunk/testdata/testoutput1
Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog 2014-08-08 14:50:26 UTC (rev 1497)
+++ code/trunk/ChangeLog 2014-08-08 15:22:51 UTC (rev 1498)
@@ -89,6 +89,11 @@
back reference was optional (had quantifier with a minimum of zero). This
example compiled incorrect code: /(((a\2)|(a*)\g<-1>))*/ and other examples
caused segmentation faults because of stack overflows at compile time.
+
+20. A pattern such as /((?(R)a|(?1)))+/, which contains a recursion within a
+ group that is quantified with an indefinite repeat, caused a compile-time
+ loop which used up all the system stack and provoked a segmentation fault.
+ This was not the same bug as 19 above.
Version 8.35 04-April-2014
Modified: code/trunk/pcre_compile.c
===================================================================
--- code/trunk/pcre_compile.c 2014-08-08 14:50:26 UTC (rev 1497)
+++ code/trunk/pcre_compile.c 2014-08-08 15:22:51 UTC (rev 1498)
@@ -2374,6 +2374,7 @@
if (c == OP_RECURSE)
{
const pcre_uchar *scode = cd->start_code + GET(code, 1);
+ const pcre_uchar *endgroup = scode;
BOOL empty_branch;
/* Test for forward reference or uncompleted reference. This is disabled
@@ -2388,24 +2389,20 @@
if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
}
- /* If we are scanning a completed pattern, there are no forward references
- and all groups are complete. We need to detect whether this is a recursive
- call, as otherwise there will be an infinite loop. If it is a recursion,
- just skip over it. Simple recursions are easily detected. For mutual
- recursions we keep a chain on the stack. */
+ /* If the reference is to a completed group, we need to detect whether this
+ is a recursive call, as otherwise there will be an infinite loop. If it is
+ a recursion, just skip over it. Simple recursions are easily detected. For
+ mutual recursions we keep a chain on the stack. */
+ do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
+ if (code >= scode && code <= endgroup) continue; /* Simple recursion */
else
- {
+ {
recurse_check *r = recurses;
- const pcre_uchar *endgroup = scode;
-
- do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
- if (code >= scode && code <= endgroup) continue; /* Simple recursion */
-
for (r = recurses; r != NULL; r = r->prev)
if (r->group == scode) break;
if (r != NULL) continue; /* Mutual recursion */
- }
+ }
/* Completed reference; scan the referenced group, remembering it on the
stack chain to detect mutual recursions. */
Modified: code/trunk/testdata/testinput1
===================================================================
--- code/trunk/testdata/testinput1 2014-08-08 14:50:26 UTC (rev 1497)
+++ code/trunk/testdata/testinput1 2014-08-08 15:22:51 UTC (rev 1498)
@@ -4937,7 +4937,13 @@
/((?(R1)a+|(?1)b))/
aaaabcde
+
+/((?(R)a|(?1)))*/
+ aaa
+/((?(R)a|(?1)))+/
+ aaa
+
/a(*:any
name)/K
abc
Modified: code/trunk/testdata/testoutput1
===================================================================
--- code/trunk/testdata/testoutput1 2014-08-08 14:50:26 UTC (rev 1497)
+++ code/trunk/testdata/testoutput1 2014-08-08 15:22:51 UTC (rev 1498)
@@ -8234,7 +8234,17 @@
aaaabcde
0: aaaab
1: aaaab
+
+/((?(R)a|(?1)))*/
+ aaa
+ 0: aaa
+ 1: a
+/((?(R)a|(?1)))+/
+ aaa
+ 0: aaa
+ 1: a
+
/a(*:any
name)/K
abc