Fix bad compile for possessive quantifier on group containing a subroutine

reference.
This commit is contained in:
Philip.Hazel 2015-03-29 17:34:04 +00:00
parent 63cab0dba9
commit 2327a5860b
4 changed files with 63 additions and 11 deletions

View File

@ -50,6 +50,11 @@ assertion after (?(. The code was failing to check the character after (?(?<
for the ! or = that would indicate a lookbehind assertion. This bug was for the ! or = that would indicate a lookbehind assertion. This bug was
discovered by the LLVM fuzzer. discovered by the LLVM fuzzer.
13. A pattern such as /X((?2)()*+){2}+/ which has a possessive quantifier with
a fixed maximum following a group that contains a subroutine reference was
incorrectly compiled and could trigger buffer overflow. This bug was discovered
by the LLVM fuzzer.
Version 10.10 06-March-2015 Version 10.10 06-March-2015
--------------------------- ---------------------------

View File

@ -1331,7 +1331,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
empty_branch = FALSE; empty_branch = FALSE;
do do
{ {
if (!empty_branch && could_be_empty_branch(code, endcode, utf, cb, if (!empty_branch && could_be_empty_branch(code, endcode, utf, cb,
recurses)) empty_branch = TRUE; recurses)) empty_branch = TRUE;
code += GET(code, 1); code += GET(code, 1);
} }
@ -4520,6 +4520,7 @@ for (;; ptr++)
{ {
register int i; register int i;
int len = (int)(code - previous); int len = (int)(code - previous);
size_t base_hwm_offset = save_hwm_offset;
PCRE2_UCHAR *bralink = NULL; PCRE2_UCHAR *bralink = NULL;
PCRE2_UCHAR *brazeroptr = NULL; PCRE2_UCHAR *brazeroptr = NULL;
@ -4668,20 +4669,20 @@ for (;; ptr++)
while (cb->hwm > cb->start_workspace + cb->workspace_size - while (cb->hwm > cb->start_workspace + cb->workspace_size -
WORK_SIZE_SAFETY_MARGIN - WORK_SIZE_SAFETY_MARGIN -
(this_hwm_offset - save_hwm_offset)) (this_hwm_offset - base_hwm_offset))
{ {
*errorcodeptr = expand_workspace(cb); *errorcodeptr = expand_workspace(cb);
if (*errorcodeptr != 0) goto FAILED; if (*errorcodeptr != 0) goto FAILED;
} }
for (hc = (PCRE2_UCHAR *)cb->start_workspace + save_hwm_offset; for (hc = (PCRE2_UCHAR *)cb->start_workspace + base_hwm_offset;
hc < (PCRE2_UCHAR *)cb->start_workspace + this_hwm_offset; hc < (PCRE2_UCHAR *)cb->start_workspace + this_hwm_offset;
hc += LINK_SIZE) hc += LINK_SIZE)
{ {
PUT(cb->hwm, 0, GET(hc, 0) + len); PUT(cb->hwm, 0, GET(hc, 0) + len);
cb->hwm += LINK_SIZE; cb->hwm += LINK_SIZE;
} }
save_hwm_offset = this_hwm_offset; base_hwm_offset = this_hwm_offset;
code += len; code += len;
} }
} }
@ -4749,20 +4750,20 @@ for (;; ptr++)
while (cb->hwm > cb->start_workspace + cb->workspace_size - while (cb->hwm > cb->start_workspace + cb->workspace_size -
WORK_SIZE_SAFETY_MARGIN - WORK_SIZE_SAFETY_MARGIN -
(this_hwm_offset - save_hwm_offset)) (this_hwm_offset - base_hwm_offset))
{ {
*errorcodeptr = expand_workspace(cb); *errorcodeptr = expand_workspace(cb);
if (*errorcodeptr != 0) goto FAILED; if (*errorcodeptr != 0) goto FAILED;
} }
for (hc = (PCRE2_UCHAR *)cb->start_workspace + save_hwm_offset; for (hc = (PCRE2_UCHAR *)cb->start_workspace + base_hwm_offset;
hc < (PCRE2_UCHAR *)cb->start_workspace + this_hwm_offset; hc < (PCRE2_UCHAR *)cb->start_workspace + this_hwm_offset;
hc += LINK_SIZE) hc += LINK_SIZE)
{ {
PUT(cb->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); PUT(cb->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1));
cb->hwm += LINK_SIZE; cb->hwm += LINK_SIZE;
} }
save_hwm_offset = this_hwm_offset; base_hwm_offset = this_hwm_offset;
code += len; code += len;
} }
@ -5029,9 +5030,9 @@ for (;; ptr++)
/* First deal with comments. Putting this code right at the start ensures /* First deal with comments. Putting this code right at the start ensures
that comments have no bad side effects. */ that comments have no bad side effects. */
if (ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN) if (ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN)
{ {
ptr += 2; ptr += 2;
while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
if (*ptr != CHAR_RIGHT_PARENTHESIS) if (*ptr != CHAR_RIGHT_PARENTHESIS)
@ -5163,7 +5164,7 @@ for (;; ptr++)
*errorcodeptr = ERR60; /* Verb not recognized */ *errorcodeptr = ERR60; /* Verb not recognized */
goto FAILED; goto FAILED;
} }
/* Initialization for "real" parentheses */ /* Initialization for "real" parentheses */
newoptions = options; newoptions = options;
@ -5274,7 +5275,7 @@ for (;; ptr++)
tempptr[2] == CHAR_EXCLAMATION_MARK || tempptr[2] == CHAR_EXCLAMATION_MARK ||
(tempptr[2] == CHAR_LESS_THAN_SIGN && (tempptr[2] == CHAR_LESS_THAN_SIGN &&
(tempptr[3] == CHAR_EQUALS_SIGN || (tempptr[3] == CHAR_EQUALS_SIGN ||
tempptr[3] == CHAR_EXCLAMATION_MARK)))) tempptr[3] == CHAR_EXCLAMATION_MARK))))
{ {
cb->iscondassert = TRUE; cb->iscondassert = TRUE;
break; break;

4
testdata/testinput2 vendored
View File

@ -4245,4 +4245,8 @@ a random value. /Ix
"(?(?<E>.*!.*)?)" "(?(?<E>.*!.*)?)"
"X((?2)()*+){2}+"B
"X((?2)()*+){2}"B
# End of testinput2 # End of testinput2

42
testdata/testoutput2 vendored
View File

@ -14209,4 +14209,46 @@ Failed: error -52: nested recursion at the same subject position
"(?(?<E>.*!.*)?)" "(?(?<E>.*!.*)?)"
Failed: error 128 at offset 3: assertion expected after (?( or (?(?C) Failed: error 128 at offset 3: assertion expected after (?( or (?(?C)
"X((?2)()*+){2}+"B
------------------------------------------------------------------
Bra
X
Once
CBra 1
Recurse
Braposzero
SCBraPos 2
KetRpos
Ket
CBra 1
Recurse
Braposzero
SCBraPos 2
KetRpos
Ket
Ket
Ket
End
------------------------------------------------------------------
"X((?2)()*+){2}"B
------------------------------------------------------------------
Bra
X
CBra 1
Recurse
Braposzero
SCBraPos 2
KetRpos
Ket
CBra 1
Recurse
Braposzero
SCBraPos 2
KetRpos
Ket
Ket
End
------------------------------------------------------------------
# End of testinput2 # End of testinput2