Changeset 207518 in webkit


Ignore:
Timestamp:
Oct 18, 2016 8:52:29 PM (8 years ago)
Author:
mark.lam@apple.com
Message:

Invoking Object.prototype.proto accessors directly should throw a TypeError.
https://bugs.webkit.org/show_bug.cgi?id=154377
<rdar://problem/27330808>

Reviewed by Filip Pizlo and Saam Barati.

JSTests:

  • stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js: Added.

Source/JavaScriptCore:

In a scenario where we cache the proto accessors in global variables, and
later explicitly invoke those accessors as functions, the spec for Function Calls
(see https://tc39.github.io/ecma262/#sec-function-calls) states that the function
ref value is of type Reference, and base of ref is an Environment Record. Then,
it follows that the thisValue should be set to refEnv.WithBaseObject()
(see section 4.b.ii of 12.3.4.1 at
https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation).

refEnv in this case is the environment record that the cached accessors were
found in i.e. the global object. The WithBaseObject() of the global object is
undefined (see details about WithBaseObject at
https://tc39.github.io/ecma262/#sec-environment-records).

Hence, the proto accessors should see a thisValue of undefined, and throw
TypeErrors. See https://tc39.github.io/ecma262/#sec-get-object.prototype.__proto,
https://tc39.github.io/ecma262/#sec-set-object.prototype.__proto
,
https://tc39.github.io/ecma262/#sec-toobject, and
https://tc39.github.io/ecma262/#sec-requireobjectcoercible.

In JSC's implementation, the callee needs to do a ToThis operation on the
incoming "this" argument in order to get the specified thisValue. The
implementations of the proto accessors were not doing this correctly. This
has now been fixed.

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncProtoGetter):
(JSC::globalFuncProtoSetter):

LayoutTests:

  • http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto.html:
  • js/dom/activation-proto-expected.txt:
  • js/dom/script-tests/activation-proto.js:
  • js/object-literal-shorthand-construction-expected.txt:
  • js/script-tests/object-literal-shorthand-construction.js:
  • js/script-tests/sloppy-getter-setter-global-object.js:
  • js/sloppy-getter-setter-global-object-expected.txt:
Location:
trunk
Files:
1 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r207500 r207518  
     12016-10-18  Mark Lam  <mark.lam@apple.com>
     2
     3        Invoking Object.prototype.__proto__ accessors directly should throw a TypeError.
     4        https://bugs.webkit.org/show_bug.cgi?id=154377
     5        <rdar://problem/27330808>
     6
     7        Reviewed by Filip Pizlo and Saam Barati.
     8
     9        * stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js: Added.
     10
    1112016-10-18  Keith Miller  <keith_miller@apple.com>
    212
  • trunk/LayoutTests/ChangeLog

    r207515 r207518  
     12016-10-18  Mark Lam  <mark.lam@apple.com>
     2
     3        Invoking Object.prototype.__proto__ accessors directly should throw a TypeError.
     4        https://bugs.webkit.org/show_bug.cgi?id=154377
     5        <rdar://problem/27330808>
     6
     7        Reviewed by Filip Pizlo and Saam Barati.
     8
     9        * http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt:
     10        * http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt:
     11        * http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt:
     12        * http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto-expected.txt:
     13        * http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto.html:
     14        * js/dom/activation-proto-expected.txt:
     15        * js/dom/script-tests/activation-proto.js:
     16        * js/object-literal-shorthand-construction-expected.txt:
     17        * js/script-tests/object-literal-shorthand-construction.js:
     18        * js/script-tests/sloppy-getter-setter-global-object.js:
     19        * js/sloppy-getter-setter-global-object-expected.txt:
     20
    1212016-10-18  Chris Dumez  <cdumez@apple.com>
    222
  • trunk/LayoutTests/http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt

    r205670 r207518  
    55
    66
    7 PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
     7PASS __proto__ = targetWindow threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
    88PASS targetWindow.myinput threw exception SecurityError (DOM Exception 18): Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match..
    99PASS: successfullyParsed should be 'true' and is.
  • trunk/LayoutTests/http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt

    r205670 r207518  
    88
    99
    10 PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
     10PASS __proto__ = targetWindow threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
    1111PASS: successfullyParsed should be 'true' and is.
    1212
  • trunk/LayoutTests/http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt

    r205670 r207518  
    55
    66
    7 PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
     7PASS __proto__ = targetWindow threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
    88PASS: location === originalLocation should be 'true' and is.
    99PASS: this.location === originalLocation should be 'true' and is.
  • trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto-expected.txt

    r205670 r207518  
    55
    66
    7 PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
     7PASS this.__proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
     8PASS __proto__ = targetWindow threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
    89PASS: innerHeight === originalInnerHeight should be 'true' and is.
    910PASS: this.innerHeight === originalInnerHeight should be 'true' and is.
  • trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto.html

    r205670 r207518  
    1616  originalInnerHeight = innerHeight;
    1717
     18  shouldThrowErrorName("this.__proto__ = targetWindow", "TypeError");
    1819  shouldThrowErrorName("__proto__ = targetWindow", "TypeError");
    1920
  • trunk/LayoutTests/js/dom/activation-proto-expected.txt

    r156066 r207518  
    44
    55
    6 PASS (function() { __proto__.testVariable = 'found'; return window.testVariable; })() is 'found'
     6PASS (function() { this.__proto__.testVariable = 'found'; return window.testVariable; })() is 'found'
    77PASS successfullyParsed is true
    88
  • trunk/LayoutTests/js/dom/script-tests/activation-proto.js

    r156066 r207518  
    55);
    66
    7 shouldBe("(function() { __proto__.testVariable = 'found'; return window.testVariable; })()", "'found'");
     7shouldBe("(function() { this.__proto__.testVariable = 'found'; return window.testVariable; })()", "'found'");
  • trunk/LayoutTests/js/object-literal-shorthand-construction-expected.txt

    r205939 r207518  
    6262PASS !!Object.getOwnPropertyDescriptor({set 'x'(value){}}, 'x').set is true
    6363PASS !!Object.getOwnPropertyDescriptor({set 42(value){}}, '42').set is true
    64 PASS __proto__ = [] threw exception TypeError: Cannot set prototype of this object.
    65 PASS ({__proto__: __proto__}) instanceof Array is false
     64PASS this.__proto__ = [] threw exception TypeError: Cannot set prototype of this object.
     65PASS ({__proto__: this.__proto__}) instanceof Array is false
     66PASS __proto__ = [] threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
     67PASS ({__proto__: __proto__}) instanceof Array threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
    6668PASS successfullyParsed is true
    6769
  • trunk/LayoutTests/js/script-tests/object-literal-shorthand-construction.js

    r205939 r207518  
    111111
    112112// __proto__ shorthand should not modify the prototype.
    113 shouldThrow("__proto__ = []");
    114 shouldBeFalse("({__proto__: __proto__}) instanceof Array");
     113shouldThrow("this.__proto__ = []");
     114shouldBeFalse("({__proto__: this.__proto__}) instanceof Array");
     115shouldThrow("__proto__ = []", '"TypeError: Object.prototype.__proto__ called on null or undefined"');
     116shouldThrow("({__proto__: __proto__}) instanceof Array", '"TypeError: Object.prototype.__proto__ called on null or undefined"');
  • trunk/LayoutTests/js/script-tests/sloppy-getter-setter-global-object.js

    r205939 r207518  
    2626shouldNotThrow("Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set(['foo'])");
    2727
    28 shouldThrow("(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)()", "\"TypeError: Can't convert undefined or null to object\"");
    29 shouldThrow("(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set)(['foo'])", "\"TypeError: Can't convert undefined or null to object\"");
     28shouldThrow("(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)()", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");
     29shouldThrow("(0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set)(['foo'])", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");
    3030
    3131
    3232var top_level_sloppy_getter = Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get;
    33 shouldNotThrow("top_level_sloppy_getter();");
     33shouldThrow("top_level_sloppy_getter();", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");
    3434
    3535var top_level_sloppy_setter = Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set;
    36 shouldThrow("top_level_sloppy_setter(['foo']);");
     36shouldThrow("top_level_sloppy_setter(['foo']);", "\"TypeError: Object.prototype.__proto__ called on null or undefined\"");
  • trunk/LayoutTests/js/sloppy-getter-setter-global-object-expected.txt

    r205939 r207518  
    99PASS Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get() did not throw exception.
    1010PASS Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set(['foo']) did not throw exception.
    11 PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)() threw exception TypeError: Can't convert undefined or null to object.
    12 PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set)(['foo']) threw exception TypeError: Can't convert undefined or null to object.
    13 PASS top_level_sloppy_getter(); did not throw exception.
    14 PASS top_level_sloppy_setter(['foo']); threw exception TypeError: Cannot set prototype of this object.
     11PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)() threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
     12PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set)(['foo']) threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
     13PASS top_level_sloppy_getter(); threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
     14PASS top_level_sloppy_setter(['foo']); threw exception TypeError: Object.prototype.__proto__ called on null or undefined.
    1515PASS successfullyParsed is true
    1616
  • trunk/Source/JavaScriptCore/ChangeLog

    r207517 r207518  
     12016-10-18  Mark Lam  <mark.lam@apple.com>
     2
     3        Invoking Object.prototype.__proto__ accessors directly should throw a TypeError.
     4        https://bugs.webkit.org/show_bug.cgi?id=154377
     5        <rdar://problem/27330808>
     6
     7        Reviewed by Filip Pizlo and Saam Barati.
     8
     9        In a scenario where we cache the __proto__ accessors in global variables, and
     10        later explicitly invoke those accessors as functions, the spec for Function Calls
     11        (see https://tc39.github.io/ecma262/#sec-function-calls) states that the function
     12        ref value is of type Reference, and base of ref is an Environment Record.  Then,
     13        it follows that the thisValue should be set to refEnv.WithBaseObject()
     14        (see section 4.b.ii of 12.3.4.1 at
     15        https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation).
     16
     17        refEnv in this case is the environment record that the cached accessors were
     18        found in i.e. the global object.  The WithBaseObject() of the global object is
     19        undefined (see details about WithBaseObject at
     20        https://tc39.github.io/ecma262/#sec-environment-records).
     21
     22        Hence, the __proto__ accessors should see a thisValue of undefined, and throw
     23        TypeErrors.  See https://tc39.github.io/ecma262/#sec-get-object.prototype.__proto__,
     24        https://tc39.github.io/ecma262/#sec-set-object.prototype.__proto__,
     25        https://tc39.github.io/ecma262/#sec-toobject, and
     26        https://tc39.github.io/ecma262/#sec-requireobjectcoercible.
     27
     28        In JSC's implementation, the callee needs to do a ToThis operation on the
     29        incoming "this" argument in order to get the specified thisValue.  The
     30        implementations of the __proto__ accessors were not doing this correctly.  This
     31        has now been fixed.
     32
     33        * runtime/JSGlobalObjectFunctions.cpp:
     34        (JSC::globalFuncProtoGetter):
     35        (JSC::globalFuncProtoSetter):
     36
    1372016-10-18  Sam Weinig  <sam@webkit.org>
    238
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r207461 r207518  
    5353
    5454namespace JSC {
     55
     56static const char* const ObjectProtoCalledOnNullOrUndefinedError = "Object.prototype.__proto__ called on null or undefined";
    5557
    5658template<typename CallbackWhenNoException>
     
    871873    auto scope = DECLARE_THROW_SCOPE(vm);
    872874
    873     if (exec->thisValue().isUndefinedOrNull())
    874         return throwVMTypeError(exec, scope, ASCIILiteral("Can't convert undefined or null to object"));
    875 
    876     JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
    877 
     875    JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
     876    if (thisValue.isUndefinedOrNull())
     877        return throwVMTypeError(exec, scope, ASCIILiteral(ObjectProtoCalledOnNullOrUndefinedError));
     878
     879    JSObject* thisObject = jsDynamicCast<JSObject*>(thisValue);
    878880    if (!thisObject) {
    879881        JSObject* prototype = exec->thisValue().synthesizePrototype(exec);
     
    891893    auto scope = DECLARE_THROW_SCOPE(vm);
    892894
    893     if (exec->thisValue().isUndefinedOrNull())
    894         return throwVMTypeError(exec, scope, ASCIILiteral("Can't convert undefined or null to object"));
     895    JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
     896    if (thisValue.isUndefinedOrNull())
     897        return throwVMTypeError(exec, scope, ASCIILiteral(ObjectProtoCalledOnNullOrUndefinedError));
    895898
    896899    JSValue value = exec->argument(0);
    897900
    898     JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
     901    JSObject* thisObject = jsDynamicCast<JSObject*>(thisValue);
    899902
    900903    // Setting __proto__ of a primitive should have no effect.
Note: See TracChangeset for help on using the changeset viewer.