Changeset 31388

Show
Ignore:
Timestamp:
2008-03-27 23:41:17 (5 months ago)
Author:
mrowe@apple.com
Message:

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:
Location:
trunk
Files:
5 modified

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r31353 r31388  
     12008-03-27  Darin Adler  <darin@apple.com> 
     2 
     3        Reviewed by Mark Rowe. 
     4 
     5        <rdar://problem/5826236> Regular expressions with large nested repetition counts can have their 
     6        compiled length calculated incorrectly. 
     7 
     8        * pcre/pcre_compile.cpp: 
     9        (multiplyWithOverflowCheck): 
     10        (calculateCompiledPatternLength): Check for overflow when dealing with nested repetition counts 
     11        and bail with an error rather than returning incorrect results. 
     12 
    1132008-03-26  Mark Rowe  <mrowe@apple.com> 
    214 
  • trunk/JavaScriptCore/pcre/pcre_compile.cpp

    r29110 r31388  
    19861986} 
    19871987 
     1988static inline int multiplyWithOverflowCheck(int a, int b) 
     1989{ 
     1990    if (!a || !b) 
     1991        return 0; 
     1992    if (a > MAX_PATTERN_SIZE / b) 
     1993        return -1; 
     1994    return a * b; 
     1995} 
     1996 
    19881997static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, 
    19891998    CompileData& cd, ErrorCode& errorcode) 
     
    19922001     amount of store required to hold the compiled code. This does not have to be 
    19932002     perfect as long as errors are overestimates. */ 
    1994      
     2003 
     2004    if (patternLength > MAX_PATTERN_SIZE) { 
     2005        errorcode = ERR16; 
     2006        return -1; 
     2007    } 
     2008 
    19952009    int length = 1 + LINK_SIZE;      /* For initial BRA plus length */ 
    19962010    int branch_extra = 0; 
     
    24142428                 bracket set. */ 
    24152429                 
     2430                int repeatsLength; 
    24162431                if (minRepeats == 0) { 
    24172432                    length++; 
    2418                     if (maxRepeats > 0) length += (maxRepeats - 1) * (duplength + 3 + 2 * LINK_SIZE); 
     2433                    if (maxRepeats > 0) { 
     2434                        repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + 3 + 2 * LINK_SIZE); 
     2435                        if (repeatsLength < 0) { 
     2436                            errorcode = ERR16; 
     2437                            return -1; 
     2438                        } 
     2439                        length += repeatsLength; 
     2440                        if (length > MAX_PATTERN_SIZE) { 
     2441                            errorcode = ERR16; 
     2442                            return -1; 
     2443                        } 
     2444                    } 
    24192445                } 
    24202446                 
     
    24262452                 
    24272453                else { 
    2428                     length += (minRepeats - 1) * duplength; 
    2429                     if (maxRepeats > minRepeats)   /* Need this test as maxRepeats=-1 means no limit */ 
    2430                         length += (maxRepeats - minRepeats) * (duplength + 3 + 2 * LINK_SIZE) 
    2431                         - (2 + 2 * LINK_SIZE); 
     2454                    repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); 
     2455                    if (repeatsLength < 0) { 
     2456                        errorcode = ERR16; 
     2457                        return -1; 
     2458                    } 
     2459                    length += repeatsLength; 
     2460                    if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ 
     2461                        repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + 3 + 2 * LINK_SIZE); 
     2462                        if (repeatsLength < 0) { 
     2463                            errorcode = ERR16; 
     2464                            return -1; 
     2465                        } 
     2466                        length += repeatsLength - (2 + 2 * LINK_SIZE); 
     2467                    } 
     2468                    if (length > MAX_PATTERN_SIZE) { 
     2469                        errorcode = ERR16; 
     2470                        return -1; 
     2471                    } 
    24322472                } 
    24332473                 
  • trunk/LayoutTests/ChangeLog

    r31384 r31388  
     12008-03-27  Mark Rowe  <mrowe@apple.com> 
     2 
     3        Reviewed by Adam Roben. 
     4 
     5        Tests for <rdar://problem/5826236> Regular expressions with large nested repetition counts can have their 
     6        compiled length calculated incorrectly. 
     7 
     8        * fast/js/regexp-overflow-expected.txt: 
     9        * fast/js/resources/regexp-overflow.js: 
     10 
    1112008-03-27  Brady Eidson  <beidson@apple.com> 
    212 
  • trunk/LayoutTests/fast/js/regexp-overflow-expected.txt

    r28787 r31388  
    1313PASS /{([\D-\ca]]â€şÂ£Âµ+?)}|[[\B-\u00d4]√π- ]]]{0,3}/i.exec("B√π- ]]").toString() is "B√π- ]]," 
    1414PASS /|[x\B-\u00b5]/i.exec("").toString() is "" 
     15PASS new RegExp(s); threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     16PASS /(([ab]){30}){3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     17PASS /(([ab]){30}){0,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     18PASS /(([ab]){30}){10,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     19PASS /(([ab]){0,30}){3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     20PASS /(([ab]){0,30}){0,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     21PASS /(([ab]){0,30}){10,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     22PASS /(([ab]){10,30}){3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     23PASS /(([ab]){10,30}){0,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     24PASS /(([ab]){10,30}){10,3360}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
     25PASS /(([ab]){12})(([ab]){65535}){1680}(([ab]){38}){722}([ab]){27}/ threw exception SyntaxError: Invalid regular expression: regular expression too large. 
    1526 
    1627PASS successfullyParsed is true 
  • trunk/LayoutTests/fast/js/resources/regexp-overflow.js

    r28785 r31388  
    2121shouldBe('/|[x\\B-\\u00b5]/i.exec("").toString()', '""'); 
    2222 
     23var s = "a"; 
     24for (var i = 0; i < 17; i++) 
     25    s += s; 
     26 
     27shouldThrow('new RegExp(s);'); 
     28 
     29shouldThrow('/(([ab]){30}){3360}/'); 
     30shouldThrow('/(([ab]){30}){0,3360}/'); 
     31shouldThrow('/(([ab]){30}){10,3360}/'); 
     32shouldThrow('/(([ab]){0,30}){3360}/'); 
     33shouldThrow('/(([ab]){0,30}){0,3360}/'); 
     34shouldThrow('/(([ab]){0,30}){10,3360}/'); 
     35shouldThrow('/(([ab]){10,30}){3360}/'); 
     36shouldThrow('/(([ab]){10,30}){0,3360}/'); 
     37shouldThrow('/(([ab]){10,30}){10,3360}/'); 
     38shouldThrow('/(([ab]){12})(([ab]){65535}){1680}(([ab]){38}){722}([ab]){27}/'); 
     39 
    2340debug(''); 
    2441