Changeset 233451 in webkit


Ignore:
Timestamp:
Jul 2, 2018 5:49:48 PM (6 years ago)
Author:
Sukolsak Sakshuwong
Message:

RegExp.exec returns wrong value with a long integer quantifier
https://bugs.webkit.org/show_bug.cgi?id=187042

Reviewed by Saam Barati.

JSTests:

  • stress/regexp-large-quantifier.js: Added.

(testRegExp):

  • stress/regress-159744.js:

Source/JavaScriptCore:

Prior to this patch, the Yarr parser checked for integer overflow when
parsing quantifiers in regular expressions by adding one digit at a time
to a number and checking if the result got larger. This is wrong;
The parser would fail to detect overflow when parsing, for example,
10,000,000,003 because (1000000000*10 + 3) % (232) = 1410065411 > 1000000000.

Another issue was that once it detected overflow, it stopped consuming
the remaining digits. Since it didn't find the closing bracket, it
parsed the quantifier as a normal string instead.

This patch fixes these issues by reading all the digits and checking for
overflow with Checked<unsigned, RecordOverflow>. If it overflows, it
returns the largest possible value (quantifyInfinite in this case). This
matches Chrome [1], Firefox [2], and Edge [3].

[1] https://chromium.googlesource.com/v8/v8.git/+/23222f0a88599dcf302ccf395883944620b70fd5/src/regexp/regexp-parser.cc#1042
[2] https://dxr.mozilla.org/mozilla-central/rev/aea3f3457f1531706923b8d4c595a1f271de83da/js/src/irregexp/RegExpParser.cpp#1310
[3] https://github.com/Microsoft/ChakraCore/blob/fc08987381da141bb686b5d0c71d75da96f9eb8a/lib/Parser/RegexParser.cpp#L1149

  • yarr/YarrParser.h:

(JSC::Yarr::Parser::consumeNumber):

LayoutTests:

  • fast/regex/overflow-expected.txt:
  • fast/regex/script-tests/overflow.js:
Location:
trunk
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r233446 r233451  
     12018-07-02  Sukolsak Sakshuwong  <sukolsak@gmail.com>
     2
     3        RegExp.exec returns wrong value with a long integer quantifier
     4        https://bugs.webkit.org/show_bug.cgi?id=187042
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/regexp-large-quantifier.js: Added.
     9        (testRegExp):
     10        * stress/regress-159744.js:
     11
    1122018-07-02  Ryosuke Niwa  <rniwa@webkit.org>
    213
  • trunk/JSTests/stress/regress-159744.js

    r203206 r233451  
    88}
    99
    10 testRegExp("((?=$))??(?:\\1){34359738368,}", "gm", "abc\nabc\nabc\nabc\n", null);
    1110testRegExp("(\\w+)(?:\\s(\\1)){1100000000,}", "i", "word Word WORD WoRd", null);
    1211testRegExp("\\d{4,}.{1073741825}", "", "1234567\u1234", null);
  • trunk/LayoutTests/ChangeLog

    r233447 r233451  
     12018-07-02  Sukolsak Sakshuwong  <sukolsak@gmail.com>
     2
     3        RegExp.exec returns wrong value with a long integer quantifier
     4        https://bugs.webkit.org/show_bug.cgi?id=187042
     5
     6        Reviewed by Saam Barati.
     7
     8        * fast/regex/overflow-expected.txt:
     9        * fast/regex/script-tests/overflow.js:
     10
    1112018-07-02  Myles C. Maxfield  <mmaxfield@apple.com>
    212
  • trunk/LayoutTests/fast/regex/overflow-expected.txt

    r108999 r233451  
    88PASS regexp3.exec(s3) is null
    99PASS function f() { /[^a$]{4294967295}/ } threw exception SyntaxError: Invalid regular expression: number too large in {} quantifier.
     10PASS new RegExp('((?=$))??(?:\\1){34359738368,}') threw exception SyntaxError: Invalid regular expression: number too large in {} quantifier.
    1011PASS successfullyParsed is true
    1112
  • trunk/LayoutTests/fast/regex/script-tests/overflow.js

    r217408 r233451  
    1212
    1313shouldThrow("function f() { /[^a$]{4294967295}/ }", '"SyntaxError: Invalid regular expression: number too large in {} quantifier"');
     14
     15shouldThrow("new RegExp('((?=$))??(?:\\\\1){34359738368,}')", '"SyntaxError: Invalid regular expression: number too large in {} quantifier"');
  • trunk/Source/JavaScriptCore/ChangeLog

    r233427 r233451  
     12018-07-02  Sukolsak Sakshuwong  <sukolsak@gmail.com>
     2
     3        RegExp.exec returns wrong value with a long integer quantifier
     4        https://bugs.webkit.org/show_bug.cgi?id=187042
     5
     6        Reviewed by Saam Barati.
     7
     8        Prior to this patch, the Yarr parser checked for integer overflow when
     9        parsing quantifiers in regular expressions by adding one digit at a time
     10        to a number and checking if the result got larger. This is wrong;
     11        The parser would fail to detect overflow when parsing, for example,
     12        10,000,000,003 because (1000000000*10 + 3) % (2^32) = 1410065411 > 1000000000.
     13
     14        Another issue was that once it detected overflow, it stopped consuming
     15        the remaining digits. Since it didn't find the closing bracket, it
     16        parsed the quantifier as a normal string instead.
     17
     18        This patch fixes these issues by reading all the digits and checking for
     19        overflow with Checked<unsigned, RecordOverflow>. If it overflows, it
     20        returns the largest possible value (quantifyInfinite in this case). This
     21        matches Chrome [1], Firefox [2], and Edge [3].
     22
     23        [1] https://chromium.googlesource.com/v8/v8.git/+/23222f0a88599dcf302ccf395883944620b70fd5/src/regexp/regexp-parser.cc#1042
     24        [2] https://dxr.mozilla.org/mozilla-central/rev/aea3f3457f1531706923b8d4c595a1f271de83da/js/src/irregexp/RegExpParser.cpp#1310
     25        [3] https://github.com/Microsoft/ChakraCore/blob/fc08987381da141bb686b5d0c71d75da96f9eb8a/lib/Parser/RegexParser.cpp#L1149
     26
     27        * yarr/YarrParser.h:
     28        (JSC::Yarr::Parser::consumeNumber):
     29
    1302018-07-02  Keith Miller  <keith_miller@apple.com>
    231
  • trunk/Source/JavaScriptCore/yarr/YarrParser.h

    r226128 r233451  
    975975    unsigned consumeNumber()
    976976    {
    977         unsigned n = consumeDigit();
    978         // check for overflow.
    979         for (unsigned newValue; peekIsDigit() && ((newValue = n * 10 + peekDigit()) >= n); ) {
    980             n = newValue;
    981             consume();
    982         }
    983         return n;
     977        Checked<unsigned, RecordOverflow> n = consumeDigit();
     978        while (peekIsDigit())
     979            n = n * 10 + consumeDigit();
     980        return n.hasOverflowed() ? quantifyInfinite : n.unsafeGet();
    984981    }
    985982
Note: See TracChangeset for help on using the changeset viewer.