Changeset 198698 in webkit


Ignore:
Timestamp:
Mar 25, 2016 4:23:17 PM (8 years ago)
Author:
mark.lam@apple.com
Message:

ES6's throwing of TypeErrors on access of RegExp.prototype flag properties breaks websites.
https://bugs.webkit.org/show_bug.cgi?id=155904

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

There exists a JS library XRegExp (see http://xregexp.com) that extends the regexp
implementation. XRegExp does feature testing by comparing RegExp.prototype.sticky
to undefined. See:

Example 1. https://github.com/slevithan/xregexp/blob/28a2b033c5951477bed8c7c867ddf7e89c431cd4/tests/perf/index.html

...
} else if (knownVersion[version]) {

Hack around ES6 incompatibility in XRegExp versions prior to 3.0.0
if (parseInt(version, 10) < 3) {

delete RegExp.prototype.sticky;

}
...

Example 2. https://github.com/slevithan/xregexp/blob/d0e665d4068cec4d15919215b098b2373f1f12e9/tests/perf/versions/xregexp-all-v2.0.0.js

...
Check for flag y support (Firefox 3+)

hasNativeY = RegExp.prototype.sticky !== undef,

...

The ES6 spec states that we should throw a TypeError here because RegExp.prototype
is not a RegExp object, and the sticky getter is only allowed to be called on
RegExp objects. See https://tc39.github.io/ecma262/2016/#sec-get-regexp.prototype.sticky.
As a result, websites that uses XRegExp can break (e.g. some Atlassian tools).

As a workaround, we'll return undefined instead of throwing on access of these
flag properties that may be used for feature testing.

  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoGetterGlobal):
(JSC::regExpProtoGetterIgnoreCase):
(JSC::regExpProtoGetterMultiline):
(JSC::regExpProtoGetterSticky):
(JSC::regExpProtoGetterUnicode):

LayoutTests:

  • ietestcenter/Javascript/TestCases/15.10.7.2-1.js:

(ES5Harness.registerTest.test):

  • ietestcenter/Javascript/TestCases/15.10.7.3-1.js:

(ES5Harness.registerTest.test):

  • ietestcenter/Javascript/TestCases/15.10.7.4-1.js:

(ES5Harness.registerTest.test):

  • updated these tests to not expect a TypeError due to the workaround.
  • js/pic/cached-named-property-getter.html:
  • updated this test to use the source property (which still throws a TypeError) instead of the ignoreCase property which no longer does.
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r198689 r198698  
     12016-03-25  Mark Lam  <mark.lam@apple.com>
     2
     3        ES6's throwing of TypeErrors on access of RegExp.prototype flag properties breaks websites.
     4        https://bugs.webkit.org/show_bug.cgi?id=155904
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * ietestcenter/Javascript/TestCases/15.10.7.2-1.js:
     9        (ES5Harness.registerTest.test):
     10        * ietestcenter/Javascript/TestCases/15.10.7.3-1.js:
     11        (ES5Harness.registerTest.test):
     12        * ietestcenter/Javascript/TestCases/15.10.7.4-1.js:
     13        (ES5Harness.registerTest.test):
     14        - updated these tests to not expect a TypeError due to the workaround.
     15
     16        * js/pic/cached-named-property-getter.html:
     17        - updated this test to use the source property (which still throws a TypeError)
     18          instead of the ignoreCase property which no longer does.
     19
    1202016-03-25  Ryan Haddad  <ryanhaddad@apple.com>
    221
  • trunk/LayoutTests/ietestcenter/Javascript/TestCases/15.10.7.2-1.js

    r198447 r198698  
    2828
    2929test: function testcase() {
    30     try {
    31         RegExp.prototype.global;
    32         return false;
    33     } catch (e) {
     30    if ((typeof(RegExp.prototype.global)) === 'undefined')
    3431        return true;
    35     }
     32    return false;
    3633 }
    3734});
  • trunk/LayoutTests/ietestcenter/Javascript/TestCases/15.10.7.3-1.js

    r198447 r198698  
    2828
    2929test: function testcase() {
    30     try {
    31         RegExp.prototype.ignoreCase;
    32         return false;
    33     } catch (e) {
     30    if ((typeof(RegExp.prototype.ignoreCase)) === 'undefined')
    3431        return true;
    35     }
     32    return false;
    3633 }
    3734});
  • trunk/LayoutTests/ietestcenter/Javascript/TestCases/15.10.7.4-1.js

    r198447 r198698  
    2828
    2929test: function testcase() {
    30     try {
    31         RegExp.prototype.multiline;
    32         return false;
    33     } catch (e) {
     30    if ((typeof(RegExp.prototype.multiline)) === 'undefined')
    3431        return true;
    35     }
     32    return false;
    3633 }
    3734});
  • trunk/LayoutTests/js/pic/cached-named-property-getter.html

    r185370 r198698  
    6565    function testCustomGetter(o) {
    6666        for (var i = 0; i < 10; i++)
    67             o.ignoreCase;
     67            o.source;
    6868    }
    6969    var r=/a/;
  • trunk/Source/JavaScriptCore/ChangeLog

    r198695 r198698  
     12016-03-25  Mark Lam  <mark.lam@apple.com>
     2
     3        ES6's throwing of TypeErrors on access of RegExp.prototype flag properties breaks websites.
     4        https://bugs.webkit.org/show_bug.cgi?id=155904
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        There exists a JS library XRegExp (see http://xregexp.com) that extends the regexp
     9        implementation.  XRegExp does feature testing by comparing RegExp.prototype.sticky
     10        to undefined.  See:
     11
     12        Example 1. https://github.com/slevithan/xregexp/blob/28a2b033c5951477bed8c7c867ddf7e89c431cd4/tests/perf/index.html
     13            ...
     14            } else if (knownVersion[version]) {
     15                // Hack around ES6 incompatibility in XRegExp versions prior to 3.0.0
     16                if (parseInt(version, 10) < 3) {
     17                    delete RegExp.prototype.sticky;
     18            }
     19            ...
     20
     21        Example 2. https://github.com/slevithan/xregexp/blob/d0e665d4068cec4d15919215b098b2373f1f12e9/tests/perf/versions/xregexp-all-v2.0.0.js
     22            ...
     23            // Check for flag y support (Firefox 3+)
     24                hasNativeY = RegExp.prototype.sticky !== undef,
     25            ...
     26
     27        The ES6 spec states that we should throw a TypeError here because RegExp.prototype
     28        is not a RegExp object, and the sticky getter is only allowed to be called on
     29        RegExp objects.  See https://tc39.github.io/ecma262/2016/#sec-get-regexp.prototype.sticky.
     30        As a result, websites that uses XRegExp can break (e.g. some Atlassian tools).
     31
     32        As a workaround, we'll return undefined instead of throwing on access of these
     33        flag properties that may be used for feature testing.
     34
     35        * runtime/RegExpPrototype.cpp:
     36        (JSC::regExpProtoGetterGlobal):
     37        (JSC::regExpProtoGetterIgnoreCase):
     38        (JSC::regExpProtoGetterMultiline):
     39        (JSC::regExpProtoGetterSticky):
     40        (JSC::regExpProtoGetterUnicode):
     41
    1422016-03-25  Caitlin Potter  <caitp@igalia.com>
    243
  • trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp

    r198554 r198698  
    246246    JSValue thisValue = exec->thisValue();
    247247    if (!thisValue.inherits(RegExpObject::info()))
    248         return throwVMTypeError(exec);
     248        return JSValue::encode(jsUndefined());
    249249
    250250    return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->global()));
     
    255255    JSValue thisValue = exec->thisValue();
    256256    if (!thisValue.inherits(RegExpObject::info()))
    257         return throwVMTypeError(exec);
     257        return JSValue::encode(jsUndefined());
    258258
    259259    return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->ignoreCase()));
     
    264264    JSValue thisValue = exec->thisValue();
    265265    if (!thisValue.inherits(RegExpObject::info()))
    266         return throwVMTypeError(exec);
     266        return JSValue::encode(jsUndefined());
    267267
    268268    return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->multiline()));
     
    273273    JSValue thisValue = exec->thisValue();
    274274    if (!thisValue.inherits(RegExpObject::info()))
    275         return throwVMTypeError(exec);
     275        return JSValue::encode(jsUndefined());
    276276   
    277277    return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->sticky()));
     
    282282    JSValue thisValue = exec->thisValue();
    283283    if (!thisValue.inherits(RegExpObject::info()))
    284         return throwVMTypeError(exec);
     284        return JSValue::encode(jsUndefined());
    285285   
    286286    return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->unicode()));
Note: See TracChangeset for help on using the changeset viewer.