Commit cb17bd09 authored by mrowe@apple.com's avatar mrowe@apple.com

2008-03-27 Darin Adler <darin@apple.com>

        Reviewed by Mark Rowe.

        <rdar://problem/5826236> Regular expressions with large nested repetition counts can have their
        compiled length calculated incorrectly.

        * pcre/pcre_compile.cpp:
        (multiplyWithOverflowCheck):
        (calculateCompiledPatternLength): Check for overflow when dealing with nested repetition counts
        and bail with an error rather than returning incorrect results.

2008-03-27  Mark Rowe  <mrowe@apple.com>

        Reviewed by Adam Roben.

        Tests for <rdar://problem/5826236> Regular expressions with large nested repetition counts can have their
        compiled length calculated incorrectly.

        * fast/js/regexp-overflow-expected.txt:
        * fast/js/resources/regexp-overflow.js:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@31388 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0ff3b99b
2008-03-27 Darin Adler <darin@apple.com>
Reviewed by Mark Rowe.
<rdar://problem/5826236> Regular expressions with large nested repetition counts can have their
compiled length calculated incorrectly.
* pcre/pcre_compile.cpp:
(multiplyWithOverflowCheck):
(calculateCompiledPatternLength): Check for overflow when dealing with nested repetition counts
and bail with an error rather than returning incorrect results.
2008-03-26 Mark Rowe <mrowe@apple.com>
Rubber-stamped by Brady Eidson.
......
......@@ -1985,13 +1985,27 @@ static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool ina
return c;
}
static inline int multiplyWithOverflowCheck(int a, int b)
{
if (!a || !b)
return 0;
if (a > MAX_PATTERN_SIZE / b)
return -1;
return a * b;
}
static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase,
CompileData& cd, ErrorCode& errorcode)
{
/* Make a pass over the pattern to compute the
amount of store required to hold the compiled code. This does not have to be
perfect as long as errors are overestimates. */
if (patternLength > MAX_PATTERN_SIZE) {
errorcode = ERR16;
return -1;
}
int length = 1 + LINK_SIZE; /* For initial BRA plus length */
int branch_extra = 0;
int lastitemlength = 0;
......@@ -2413,9 +2427,21 @@ static int calculateCompiledPatternLength(const UChar* pattern, int patternLengt
maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
bracket set. */
int repeatsLength;
if (minRepeats == 0) {
length++;
if (maxRepeats > 0) length += (maxRepeats - 1) * (duplength + 3 + 2 * LINK_SIZE);
if (maxRepeats > 0) {
repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + 3 + 2 * LINK_SIZE);
if (repeatsLength < 0) {
errorcode = ERR16;
return -1;
}
length += repeatsLength;
if (length > MAX_PATTERN_SIZE) {
errorcode = ERR16;
return -1;
}
}
}
/* When the minimum is greater than zero, we have to replicate up to
......@@ -2425,10 +2451,24 @@ static int calculateCompiledPatternLength(const UChar* pattern, int patternLengt
but one of the optional copies. */
else {
length += (minRepeats - 1) * duplength;
if (maxRepeats > minRepeats) /* Need this test as maxRepeats=-1 means no limit */
length += (maxRepeats - minRepeats) * (duplength + 3 + 2 * LINK_SIZE)
- (2 + 2 * LINK_SIZE);
repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength);
if (repeatsLength < 0) {
errorcode = ERR16;
return -1;
}
length += repeatsLength;
if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */
repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + 3 + 2 * LINK_SIZE);
if (repeatsLength < 0) {
errorcode = ERR16;
return -1;
}
length += repeatsLength - (2 + 2 * LINK_SIZE);
}
if (length > MAX_PATTERN_SIZE) {
errorcode = ERR16;
return -1;
}
}
/* Allow space for once brackets for "possessive quantifier" */
......
2008-03-27 Mark Rowe <mrowe@apple.com>
Reviewed by Adam Roben.
Tests for <rdar://problem/5826236> Regular expressions with large nested repetition counts can have their
compiled length calculated incorrectly.
* fast/js/regexp-overflow-expected.txt:
* fast/js/resources/regexp-overflow.js:
2008-03-27 Brady Eidson <beidson@apple.com>
Reviewed by Adam Roben
......@@ -12,6 +12,17 @@ PASS /[¡]{4,6}/.exec("¡¡¡¡").toString() is "¡¡¡¡"
PASS /[¡]{1,100}[¡]{1,100}[¡]{1,100}[¡]{1,100}[¡]{1,100}[¡]{1,100}[¡]{1,100}[¡]{1,100}/.exec("¡¡¡¡¡¡¡¡").toString() is "¡¡¡¡¡¡¡¡"
PASS /{([\D-\ca]]„£µ+?)}|[[\B-\u00d4]√π- ]]]{0,3}/i.exec("B√π- ]]").toString() is "B√π- ]],"
PASS /|[x\B-\u00b5]/i.exec("").toString() is ""
PASS new RegExp(s); threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){30}){3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){30}){0,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){30}){10,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){0,30}){3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){0,30}){0,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){0,30}){10,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){10,30}){3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){10,30}){0,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){10,30}){10,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS /(([ab]){12})(([ab]){65535}){1680}(([ab]){38}){722}([ab]){27}/ threw exception SyntaxError: Invalid regular expression: regular expression too large.
PASS successfullyParsed is true
......
......@@ -20,6 +20,23 @@ shouldBe('/[\u00A1]{1,100}[\u00A1]{1,100}[\u00A1]{1,100}[\u00A1]{1,100}[\u00A1]{
shouldBe('/{([\\D-\\ca]]„£µ+?)}|[[\\B-\\u00d4]√π- ]]]{0,3}/i.exec("B√π- ]]").toString()', '"B√π- ]],"');
shouldBe('/|[x\\B-\\u00b5]/i.exec("").toString()', '""');
var s = "a";
for (var i = 0; i < 17; i++)
s += s;
shouldThrow('new RegExp(s);');
shouldThrow('/(([ab]){30}){3360}/');
shouldThrow('/(([ab]){30}){0,3360}/');
shouldThrow('/(([ab]){30}){10,3360}/');
shouldThrow('/(([ab]){0,30}){3360}/');
shouldThrow('/(([ab]){0,30}){0,3360}/');
shouldThrow('/(([ab]){0,30}){10,3360}/');
shouldThrow('/(([ab]){10,30}){3360}/');
shouldThrow('/(([ab]){10,30}){0,3360}/');
shouldThrow('/(([ab]){10,30}){10,3360}/');
shouldThrow('/(([ab]){12})(([ab]){65535}){1680}(([ab]){38}){722}([ab]){27}/');
debug('');
var successfullyParsed = true;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment