summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorph10 <ph10@2f5784b3-3f2a-0410-8824-cb99058d5e15>2015-04-01 15:43:53 +0000
committerph10 <ph10@2f5784b3-3f2a-0410-8824-cb99058d5e15>2015-04-01 15:43:53 +0000
commit256d94987eecd7eb87b37e1c981a4e753ed8ab7a (patch)
treed6ff6ddcb018b6b92bc4b8e4b337a50d5bb21bdc
parent14ce0b0c24bfb4dff4bcb602057014a487a19eef (diff)
downloadpcre-256d94987eecd7eb87b37e1c981a4e753ed8ab7a.tar.gz
Fix stack overflow instead of diagnostic for mutual recursion inside a
lookbehind assertion. git-svn-id: svn://vcs.exim.org/pcre/code/trunk@1542 2f5784b3-3f2a-0410-8824-cb99058d5e15
-rw-r--r--ChangeLog4
-rw-r--r--pcre_compile.c38
-rw-r--r--testdata/testinput22
-rw-r--r--testdata/testoutput23
4 files changed, 35 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 9d13613..53f6853 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -142,6 +142,10 @@ Version 8.37 xx-xxx-2015
incorrectly compiled and could trigger buffer overflow. This bug was
discovered by the LLVM fuzzer.
+35. A mutual recursion within a lookbehind assertion such as (?<=((?2))((?1)))
+ caused a stack overflow instead of the diagnosis of a non-fixed length
+ lookbehind assertion. This bug was discovered by the LLVM fuzzer.
+
Version 8.36 26-September-2014
------------------------------
diff --git a/pcre_compile.c b/pcre_compile.c
index ce65777..6510835 100644
--- a/pcre_compile.c
+++ b/pcre_compile.c
@@ -866,6 +866,14 @@ static const pcre_uint8 opcode_possessify[] = {
};
+/* Structure for mutual recursion detection. */
+
+typedef struct recurse_check {
+ struct recurse_check *prev;
+ const pcre_uchar *group;
+} recurse_check;
+
+
/*************************************************
* Find an error text *
@@ -1704,6 +1712,7 @@ Arguments:
utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
atend TRUE if called when the pattern is complete
cd the "compile data" structure
+ recurses chain of recurse_check to catch mutual recursion
Returns: the fixed length,
or -1 if there is no fixed length,
@@ -1713,10 +1722,11 @@ Returns: the fixed length,
*/
static int
-find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd)
+find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd,
+ recurse_check *recurses)
{
int length = -1;
-
+recurse_check this_recurse;
register int branchlength = 0;
register pcre_uchar *cc = code + 1 + LINK_SIZE;
@@ -1741,7 +1751,8 @@ for (;;)
case OP_ONCE:
case OP_ONCE_NC:
case OP_COND:
- d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd);
+ d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd,
+ recurses);
if (d < 0) return d;
branchlength += d;
do cc += GET(cc, 1); while (*cc == OP_ALT);
@@ -1775,7 +1786,15 @@ for (;;)
cs = ce = (pcre_uchar *)cd->start_code + GET(cc, 1); /* Start subpattern */
do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */
if (cc > cs && cc < ce) return -1; /* Recursion */
- d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd);
+ else /* Check for mutual recursion */
+ {
+ recurse_check *r = recurses;
+ for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
+ if (r != NULL) return -1; /* Mutual recursion */
+ }
+ this_recurse.prev = recurses;
+ this_recurse.group = cs;
+ d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd, &this_recurse);
if (d < 0) return d;
branchlength += d;
cc += 1 + LINK_SIZE;
@@ -2362,11 +2381,6 @@ Arguments:
Returns: TRUE if what is matched could be empty
*/
-typedef struct recurse_check {
- struct recurse_check *prev;
- const pcre_uchar *group;
-} recurse_check;
-
static BOOL
could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode,
BOOL utf, compile_data *cd, recurse_check *recurses)
@@ -5924,7 +5938,7 @@ for (;; ptr++)
{
register int i;
int len = (int)(code - previous);
- size_t base_hwm_offset = save_hwm_offset;
+ size_t base_hwm_offset = save_hwm_offset;
pcre_uchar *bralink = NULL;
pcre_uchar *brazeroptr = NULL;
@@ -8291,7 +8305,7 @@ for (;;)
int fixed_length;
*code = OP_END;
fixed_length = find_fixedlength(last_branch, (options & PCRE_UTF8) != 0,
- FALSE, cd);
+ FALSE, cd, NULL);
DPRINTF(("fixed length = %d\n", fixed_length));
if (fixed_length == -3)
{
@@ -9394,7 +9408,7 @@ if (cd->check_lookbehind)
int end_op = *be;
*be = OP_END;
fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE,
- cd);
+ cd, NULL);
*be = end_op;
DPRINTF(("fixed length = %d\n", fixed_length));
if (fixed_length < 0)
diff --git a/testdata/testinput2 b/testdata/testinput2
index 8ba0b7b..c31b6c9 100644
--- a/testdata/testinput2
+++ b/testdata/testinput2
@@ -4142,4 +4142,6 @@ backtracking verbs. --/
"X((?2)()*+){2}"BZ
+"(?<=((?2))((?1)))"
+
/-- End of testinput2 --/
diff --git a/testdata/testoutput2 b/testdata/testoutput2
index 5d93d4c..4b8eec2 100644
--- a/testdata/testoutput2
+++ b/testdata/testoutput2
@@ -14390,4 +14390,7 @@ Failed: assertion expected after (?( at offset 3
End
------------------------------------------------------------------
+"(?<=((?2))((?1)))"
+Failed: lookbehind assertion is not fixed length at offset 17
+
/-- End of testinput2 --/