Title: [205354] trunk
Revision
205354
Author
[email protected]
Date
2016-09-02 11:04:25 -0700 (Fri, 02 Sep 2016)

Log Message

Align proto getter / setter behavior with other browsers
https://bugs.webkit.org/show_bug.cgi?id=161455

Reviewed by Mark Lam.

Source/_javascript_Core:

Drop allowsAccessFrom from the methodTable and delegate cross-origin
checking to the DOM bindings for [[SetPrototypeOf]] / [[GetPrototypeOf]].
This is more consistent with other operations (e.g. [[GetOwnProperty]]).

* jsc.cpp:
* runtime/JSGlobalObject.cpp:
* runtime/JSGlobalObject.h:
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncProtoGetter):
(JSC::globalFuncProtoSetter):
(JSC::globalFuncBuiltinLog): Deleted.
* runtime/JSGlobalObjectFunctions.h:
* runtime/JSObject.h:
(JSC::JSObject::getArrayLength): Deleted.
* runtime/JSProxy.cpp:
(JSC::JSProxy::setPrototype):
(JSC::JSProxy::getPrototype):
* runtime/JSProxy.h:
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorGetPrototypeOf):
(JSC::objectConstructorSetPrototypeOf):
(JSC::objectConstructorGetOwnPropertyDescriptor): Deleted.
(JSC::objectConstructorGetOwnPropertyDescriptors): Deleted.
* runtime/ObjectConstructor.h:
* runtime/ReflectObject.cpp:
(JSC::reflectObjectGetPrototypeOf):
(JSC::reflectObjectSetPrototypeOf):

* runtime/JSObject.cpp:
(JSC::JSObject::setPrototypeWithCycleCheck):
Comment out check added in r197648. This check was added to match
the latest EcmaScript spec:
- https://tc39.github.io/ecma262/#sec-ordinarysetprototypeof (step 8)
This check allowed for [[Prototype]] chain cycles if the prototype
chain includes objects that do not use the ordinary object definitions
for [[GetPrototypeOf]] and [[SetPrototypeOf]].
The issue is that the rest of our code base does not properly handle
such cycles and we can end up in infinite loops. This became obvious
because this patch updates Window / Location so that they no longer
use the default [[GetPrototypeOf]] / [[SetPrototypeOf]]. If I do not
comment out this check, I get an infinite loop in
Structure::anyObjectInChainMayInterceptIndexedAccesses(), which is
called from JSObject::setPrototypeDirect(), when running the following
layout test:
- html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html
I filed https://bugs.webkit.org/show_bug.cgi?id=161534 to track this
issue.

Source/WebCore:

Align cross-origin __proto__ getter / setter behavior with other
browsers and the specification:

[[SetPrototypeOf]] should throw a TypeError:
- https://html.spec.whatwg.org/#windowproxy-setprototypeof
- https://html.spec.whatwg.org/#location-setprototypeof
- https://tc39.github.io/ecma262/#sec-object.setprototypeof (step 5)

[[GetPrototypeOf]] should return null cross-origin:
- https://html.spec.whatwg.org/#windowproxy-getprototypeof
- https://html.spec.whatwg.org/#location-getprototypeof

Test: js/dom/setPrototypeOf-location-window.html

* bindings/js/JSDOMWindowBase.cpp:
(WebCore::JSDOMWindowBase::JSDOMWindowBase): Deleted.
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::setPrototype):
(WebCore::JSDOMWindow::getPrototype):
* bindings/js/JSLocationCustom.cpp:
(WebCore::JSLocation::setPrototype):
(WebCore::JSLocation::getPrototype):
* bindings/js/JSWorkerGlobalScopeBase.cpp:
(WebCore::JSWorkerGlobalScopeBase::supportsRichSourceInfo): Deleted.
* bindings/js/JSWorkerGlobalScopeBase.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
* bindings/scripts/IDLAttributes.txt:
* page/DOMWindow.idl:
* page/Location.idl:

LayoutTests:

Add layout test coverage and update a few existing test to reflect
behavior change.

* http/tests/security/cross-frame-access-object-getPrototypeOf-expected.txt:
* http/tests/security/cross-frame-access-object-getPrototypeOf.html:
* http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt:
* http/tests/security/cross-frame-access-object-setPrototypeOf.html:
* http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt:
* http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto.html:
* http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt:
* http/tests/security/xss-DENIED-method-with-iframe-proto.html:
* http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt:
* http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto.html:
* 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/setPrototypeOf-location-window-expected.txt: Added.
* js/dom/setPrototypeOf-location-window.html: Added.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (205353 => 205354)


--- trunk/LayoutTests/ChangeLog	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/ChangeLog	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,3 +1,28 @@
+2016-09-02  Chris Dumez  <[email protected]>
+
+        Align proto getter / setter behavior with other browsers
+        https://bugs.webkit.org/show_bug.cgi?id=161455
+
+        Reviewed by Mark Lam.
+
+        Add layout test coverage and update a few existing test to reflect
+        behavior change.
+
+        * http/tests/security/cross-frame-access-object-getPrototypeOf-expected.txt:
+        * http/tests/security/cross-frame-access-object-getPrototypeOf.html:
+        * http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt:
+        * http/tests/security/cross-frame-access-object-setPrototypeOf.html:
+        * http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt:
+        * http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto.html:
+        * http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt:
+        * http/tests/security/xss-DENIED-method-with-iframe-proto.html:
+        * http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt:
+        * http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto.html:
+        * 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/setPrototypeOf-location-window-expected.txt: Added.
+        * js/dom/setPrototypeOf-location-window.html: Added.
+
 2016-09-02  Eric Carlson  <[email protected]>
 
         [MediaStream] applyConstraints pt. 1 - mandatory constraints

Deleted: trunk/LayoutTests/fast/dom/Window/script-tests/window-custom-prototype.js (205353 => 205354)


--- trunk/LayoutTests/fast/dom/Window/script-tests/window-custom-prototype.js	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/fast/dom/Window/script-tests/window-custom-prototype.js	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,18 +0,0 @@
-description("Test what happens when you set the window's prototype to various values.");
-
-var originalWindowPrototype = __proto__;
-var chainPointingBackToWindow = { __proto__: window };
-var anotherObject = { };
-
-shouldThrow("__proto__ = window; __proto", "'TypeError: cyclic __proto__ value'");
-shouldThrow("__proto__ = chainPointingBackToWindow; __proto__", "'TypeError: cyclic __proto__ value'");
-shouldBe("__proto__ = 1; __proto__", "originalWindowPrototype");
-shouldBe("__proto__ = 'a string'; __proto__", "originalWindowPrototype");
-shouldBe("__proto__ = anotherObject; __proto__", "anotherObject");
-shouldThrow("anotherObject.__proto__ = window; __proto__", "'TypeError: cyclic __proto__ value'");
-shouldBe("__proto__ = 1; __proto__", "anotherObject");
-shouldBe("__proto__ = 'a string'; __proto__", "anotherObject");
-shouldBe("__proto__ = anotherObject; __proto__", "anotherObject");
-shouldBe("__proto__ = originalWindowPrototype; __proto__", "originalWindowPrototype");
-shouldBe("anotherObject.__proto__ = window; anotherObject.__proto__", "window");
-shouldBe("__proto__ = null; __proto__", "null");

Modified: trunk/LayoutTests/fast/dom/Window/window-custom-prototype-crash-expected.txt (205353 => 205354)


--- trunk/LayoutTests/fast/dom/Window/window-custom-prototype-crash-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/fast/dom/Window/window-custom-prototype-crash-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1 +1,2 @@
+CONSOLE MESSAGE: line 7: TypeError: Cannot set prototype of this object
 If this did not crash the test has succeeded.

Deleted: trunk/LayoutTests/fast/dom/Window/window-custom-prototype-expected.txt (205353 => 205354)


--- trunk/LayoutTests/fast/dom/Window/window-custom-prototype-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/fast/dom/Window/window-custom-prototype-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,21 +0,0 @@
-Test what happens when you set the window's prototype to various values.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS __proto__ = window; __proto threw exception TypeError: cyclic __proto__ value.
-PASS __proto__ = chainPointingBackToWindow; __proto__ threw exception TypeError: cyclic __proto__ value.
-PASS __proto__ = 1; __proto__ is originalWindowPrototype
-PASS __proto__ = 'a string'; __proto__ is originalWindowPrototype
-PASS __proto__ = anotherObject; __proto__ is anotherObject
-PASS anotherObject.__proto__ = window; __proto__ threw exception TypeError: cyclic __proto__ value.
-PASS __proto__ = 1; __proto__ is anotherObject
-PASS __proto__ = 'a string'; __proto__ is anotherObject
-PASS __proto__ = anotherObject; __proto__ is anotherObject
-PASS __proto__ = originalWindowPrototype; __proto__ is originalWindowPrototype
-PASS anotherObject.__proto__ = window; anotherObject.__proto__ is window
-PASS __proto__ = null; __proto__ is null
-PASS successfullyParsed is true
-
-TEST COMPLETE
-

Deleted: trunk/LayoutTests/fast/dom/Window/window-custom-prototype.html (205353 => 205354)


--- trunk/LayoutTests/fast/dom/Window/window-custom-prototype.html	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/fast/dom/Window/window-custom-prototype.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src=""
-</head>
-<body>
-<script src=""
-<script src=""
-</body>
-</html>

Modified: trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf-expected.txt (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,9 +1,9 @@
-CONSOLE MESSAGE: line 1: 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.
-CONSOLE MESSAGE: line 1: 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.
 This tests that you can't get the prototype of the window or history objects cross-origin using Object.getPrototypeOf().
 
 PASS: Object.getPrototypeOf(targetWindow) should be 'null' and is.
 PASS: Object.getPrototypeOf(targetWindow.location) should be 'null' and is.
+PASS: protoGetter.call(targetWindow) should be 'null' and is.
+PASS: protoGetter.call(targetWindow.location) should be 'null' and is.
 PASS targetWindow.history 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..
 PASS: successfullyParsed should be 'true' and is.
 

Modified: trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf.html (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf.html	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -18,6 +18,10 @@
 
             shouldBeNull("Object.getPrototypeOf(targetWindow)");
             shouldBeNull("Object.getPrototypeOf(targetWindow.location)");
+            protoGetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get;
+            shouldBeNull("protoGetter.call(targetWindow)");
+            shouldBeNull("protoGetter.call(targetWindow.location)");
+
             shouldThrowErrorName("targetWindow.history", "SecurityError");
 
             finishJSTest();

Modified: trunk/LayoutTests/http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,5 +1,3 @@
-CONSOLE MESSAGE: line 1: 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.
-CONSOLE MESSAGE: line 1: 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.
 This tests that you can't set the prototype of the window or location objects cross-origin using Object.setPrototypeOf()
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
@@ -6,11 +4,17 @@
 
 
 PASS: targetWindow instanceof Array should be 'false' and is.
-PASS Object.setPrototypeOf(targetWindow, Array.prototype) threw exception TypeError: Permission denied.
+PASS Object.setPrototypeOf(targetWindow, Array.prototype) threw exception TypeError: Cannot set prototype of this object.
 PASS: targetWindow instanceof Array should be 'false' and is.
 PASS: targetWindow.location instanceof Array should be 'false' and is.
-PASS Object.setPrototypeOf(targetWindow.location, Array.prototype) threw exception TypeError: Permission denied.
+PASS Object.setPrototypeOf(targetWindow.location, Array.prototype) threw exception TypeError: Cannot set prototype of this object.
 PASS: targetWindow.location instanceof Array should be 'false' and is.
+PASS: targetWindow instanceof Array should be 'false' and is.
+PASS protoSetter.call(targetWindow, Array.prototype) threw exception TypeError: Cannot set prototype of this object.
+PASS: targetWindow instanceof Array should be 'false' and is.
+PASS: targetWindow.location instanceof Array should be 'false' and is.
+PASS protoSetter.call(targetWindow.location, Array.prototype) threw exception TypeError: Cannot set prototype of this object.
+PASS: targetWindow.location instanceof Array should be 'false' and is.
 PASS: successfullyParsed should be 'true' and is.
 
 TEST COMPLETE

Modified: trunk/LayoutTests/http/tests/security/cross-frame-access-object-setPrototypeOf.html (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/cross-frame-access-object-setPrototypeOf.html	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/cross-frame-access-object-setPrototypeOf.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -24,6 +24,15 @@
             shouldThrowErrorName("Object.setPrototypeOf(targetWindow.location, Array.prototype)", "TypeError");
             shouldBeFalse("targetWindow.location instanceof Array");
 
+            protoSetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
+            shouldBeFalse("targetWindow instanceof Array");
+            shouldThrowErrorName("protoSetter.call(targetWindow, Array.prototype)", "TypeError");
+            shouldBeFalse("targetWindow instanceof Array");
+
+            shouldBeFalse("targetWindow.location instanceof Array");
+            shouldThrowErrorName("protoSetter.call(targetWindow.location, Array.prototype)", "TypeError");
+            shouldBeFalse("targetWindow.location instanceof Array");
+
             finishJSTest();
         }
     </script>

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -4,6 +4,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
 PASS 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..
 PASS: successfullyParsed should be 'true' and is.
 

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto.html (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto.html	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -14,7 +14,7 @@
 targetWindow = frames[0];
 
 window._onload_ = function() {
-  __proto__ = targetWindow;
+  shouldThrowErrorName("__proto__ = targetWindow", "TypeError");
   shouldThrowErrorName('targetWindow.myinput', 'SecurityError');
   finishJSTest();
 }

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,6 +1,14 @@
-CONSOLE MESSAGE: line 40: 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.
-CONSOLE MESSAGE: line 47: 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.
-CONSOLE MESSAGE: line 54: 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.
+CONSOLE MESSAGE: line 36: 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.
+CONSOLE MESSAGE: line 43: 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.
+CONSOLE MESSAGE: line 50: 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.
 
 Tests that making other frame window a prototype doesn't expose that window methods
 
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
+PASS: successfullyParsed should be 'true' and is.
+
+TEST COMPLETE
+

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-method-with-iframe-proto.html (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-method-with-iframe-proto.html	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-method-with-iframe-proto.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,5 +1,6 @@
 <html>
 <head>
+<script src=""
 <script src=""
 </head>
 <body>
@@ -6,13 +7,9 @@
 <iframe src="" style=""></iframe>
 <pre id="console"></pre>
 <script>
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
+description("Tests that making other frame window a prototype doesn't expose that window methods");
+jsTestIsAsync = true;
 
-log("Tests that making other frame window a prototype doesn't expose that window methods");
-
 targetWindow = frames[0];
 
 wasInvoked = false;
@@ -23,14 +20,13 @@
 
 function check() {
   shouldBeFalse('this.wasInvoked');
-  if (window.testRunner)
-      testRunner.notifyDone();
+  finishJSTest();
 }
 
 window._onload_ = function() {
   originalSetTimeout = setTimeout;
 
-  __proto__ = targetWindow;
+  shouldThrowErrorName("__proto__ = targetWindow", "TypeError");
 
   var needsCheck = false;
   try {
@@ -57,10 +53,10 @@
   if (needsCheck) {
     originalSetTimeout(check, 10);
   } else {
-    if (window.testRunner)
-      testRunner.notifyDone();
+    finishJSTest();
   }
 }
 </script>
+<script src=""
 </body>
 </html>

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,5 +1,13 @@
 
 Tests that making other frame window a prototype doesn't expose that window properties
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
 PASS: location === originalLocation should be 'true' and is.
 PASS: this.location === originalLocation should be 'true' and is.
+PASS: successfullyParsed should be 'true' and is.
 
+TEST COMPLETE
+

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto.html (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto.html	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,5 +1,6 @@
 <html>
 <head>
+<script src=""
 <script src=""
 </head>
 <body>
@@ -6,21 +7,21 @@
 <iframe src="" style=""></iframe>
 <pre id="console"></pre>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+description("Tests that making other frame window a prototype doesn't expose that window properties");
+jsTestIsAsync = true;
 
-log("Tests that making other frame window a prototype doesn't expose that window properties");
-
 targetWindow = frames[0];
 
 window._onload_ = function() {
   originalLocation = location;
 
-  __proto__ = targetWindow;
+  shouldThrowErrorName("__proto__ = targetWindow", "TypeError");
 
   shouldBeTrue('location === originalLocation');
   shouldBeTrue('this.location === originalLocation');
+  finishJSTest();
 }
 </script>
+<script src=""
 </body>
 </html>

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto-expected.txt (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,5 +1,13 @@
 
 Tests that making other frame window a prototype doesn't expose that window properties
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS __proto__ = targetWindow threw exception TypeError: Cannot set prototype of this object.
 PASS: innerHeight === originalInnerHeight should be 'true' and is.
 PASS: this.innerHeight === originalInnerHeight should be 'true' and is.
+PASS: successfullyParsed should be 'true' and is.
 
+TEST COMPLETE
+

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto.html (205353 => 205354)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto.html	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,5 +1,6 @@
 <html>
 <head>
+<script src=""
 <script src=""
 </head>
 <body>
@@ -6,21 +7,21 @@
 <iframe src="" style=""></iframe>
 <pre id="console"></pre>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+description("Tests that making other frame window a prototype doesn't expose that window properties");
+jsTestIsAsync = true;
 
-log("Tests that making other frame window a prototype doesn't expose that window properties");
-
 targetWindow = frames[0];
 
 window._onload_ = function() {
   originalInnerHeight = innerHeight;
 
-  __proto__ = targetWindow;
+  shouldThrowErrorName("__proto__ = targetWindow", "TypeError");
 
   shouldBeTrue('innerHeight === originalInnerHeight');
   shouldBeTrue('this.innerHeight === originalInnerHeight');
+  finishJSTest();
 }
 </script>
+<script src=""
 </body>
 </html>

Added: trunk/LayoutTests/js/dom/setPrototypeOf-location-window-expected.txt (0 => 205354)


--- trunk/LayoutTests/js/dom/setPrototypeOf-location-window-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/dom/setPrototypeOf-location-window-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -0,0 +1,21 @@
+Test that it is not possible to set the prototype of Window or Location.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Object.getPrototypeOf(window) is Window.prototype
+PASS Object.setPrototypeOf(window, Node.prototype) threw exception TypeError: Cannot set prototype of this object.
+PASS Object.getPrototypeOf(window) is Window.prototype
+PASS Object.getPrototypeOf(window) is Window.prototype
+PASS protoSetter.call(window, Node.prototype) threw exception TypeError: Cannot set prototype of this object.
+PASS Object.getPrototypeOf(window) is Window.prototype
+PASS Object.getPrototypeOf(window.location) is Location.prototype
+PASS Object.setPrototypeOf(window.location, Node.prototype) threw exception TypeError: Cannot set prototype of this object.
+PASS Object.getPrototypeOf(window.location) is Location.prototype
+PASS Object.getPrototypeOf(window.location) is Location.prototype
+PASS protoSetter.call(window.location, Node.prototype) threw exception TypeError: Cannot set prototype of this object.
+PASS Object.getPrototypeOf(window.location) is Location.prototype
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/dom/setPrototypeOf-location-window.html (0 => 205354)


--- trunk/LayoutTests/js/dom/setPrototypeOf-location-window.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/setPrototypeOf-location-window.html	2016-09-02 18:04:25 UTC (rev 205354)
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Test that it is not possible to set the prototype of Window or Location.");
+
+var protoSetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
+
+shouldBe("Object.getPrototypeOf(window)", "Window.prototype");
+shouldThrowErrorName("Object.setPrototypeOf(window, Node.prototype)", "TypeError");
+shouldBe("Object.getPrototypeOf(window)", "Window.prototype");
+
+shouldBe("Object.getPrototypeOf(window)", "Window.prototype");
+shouldThrowErrorName("protoSetter.call(window, Node.prototype)", "TypeError");
+shouldBe("Object.getPrototypeOf(window)", "Window.prototype");
+
+shouldBe("Object.getPrototypeOf(window.location)", "Location.prototype");
+shouldThrowErrorName("Object.setPrototypeOf(window.location, Node.prototype)", "TypeError");
+shouldBe("Object.getPrototypeOf(window.location)", "Location.prototype");
+
+shouldBe("Object.getPrototypeOf(window.location)", "Location.prototype");
+shouldThrowErrorName("protoSetter.call(window.location, Node.prototype)", "TypeError");
+shouldBe("Object.getPrototypeOf(window.location)", "Location.prototype");
+</script>
+<script src=""
+</body>
+</script>

Modified: trunk/LayoutTests/js/object-literal-shorthand-construction-expected.txt (205353 => 205354)


--- trunk/LayoutTests/js/object-literal-shorthand-construction-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/js/object-literal-shorthand-construction-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -61,9 +61,7 @@
 PASS !!Object.getOwnPropertyDescriptor({set x(value){}}, 'x').set is true
 PASS !!Object.getOwnPropertyDescriptor({set 'x'(value){}}, 'x').set is true
 PASS !!Object.getOwnPropertyDescriptor({set 42(value){}}, '42').set is true
-PASS __proto__ = []; ({__proto__: __proto__}) instanceof Array is true
-PASS __proto__ = []; ({__proto__}) instanceof Array is false
-PASS __proto__ = []; ({__proto__}).__proto__ instanceof Array is true
+PASS __proto__ = [] threw exception TypeError: Cannot set prototype of this object.
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/js/script-tests/object-literal-shorthand-construction.js (205353 => 205354)


--- trunk/LayoutTests/js/script-tests/object-literal-shorthand-construction.js	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/js/script-tests/object-literal-shorthand-construction.js	2016-09-02 18:04:25 UTC (rev 205354)
@@ -109,7 +109,4 @@
 shouldBeTrue("!!Object.getOwnPropertyDescriptor({set 'x'(value){}}, 'x').set");
 shouldBeTrue("!!Object.getOwnPropertyDescriptor({set 42(value){}}, '42').set");
 
-// __proto__ shorthand should be not modify the prototype.
-shouldBeTrue("__proto__ = []; ({__proto__: __proto__}) instanceof Array");
-shouldBeFalse("__proto__ = []; ({__proto__}) instanceof Array");
-shouldBeTrue("__proto__ = []; ({__proto__}).__proto__ instanceof Array");
+shouldThrowErrorName("__proto__ = []", "TypeError");

Modified: trunk/LayoutTests/js/script-tests/sloppy-getter-setter-global-object.js (205353 => 205354)


--- trunk/LayoutTests/js/script-tests/sloppy-getter-setter-global-object.js	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/js/script-tests/sloppy-getter-setter-global-object.js	2016-09-02 18:04:25 UTC (rev 205354)
@@ -33,4 +33,4 @@
 shouldNotThrow("top_level_sloppy_getter();");
 
 var top_level_sloppy_setter = Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set;
-shouldNotThrow("top_level_sloppy_setter(['foo']);");
+shouldThrowErrorName("top_level_sloppy_setter(['foo']);", "TypeError");

Modified: trunk/LayoutTests/js/sloppy-getter-setter-global-object-expected.txt (205353 => 205354)


--- trunk/LayoutTests/js/sloppy-getter-setter-global-object-expected.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/LayoutTests/js/sloppy-getter-setter-global-object-expected.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -11,7 +11,7 @@
 PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').get)() threw exception TypeError: Can't convert undefined or null to object.
 PASS (0,Object.getOwnPropertyDescriptor(Object.prototype,'__proto__').set)(['foo']) threw exception TypeError: Can't convert undefined or null to object.
 PASS top_level_sloppy_getter(); did not throw exception.
-PASS top_level_sloppy_setter(['foo']); did not throw exception.
+PASS top_level_sloppy_setter(['foo']); threw exception TypeError: Cannot set prototype of this object.
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/Source/_javascript_Core/ChangeLog (205353 => 205354)


--- trunk/Source/_javascript_Core/ChangeLog	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,3 +1,58 @@
+2016-09-02  Chris Dumez  <[email protected]>
+
+        Align proto getter / setter behavior with other browsers
+        https://bugs.webkit.org/show_bug.cgi?id=161455
+
+        Reviewed by Mark Lam.
+
+        Drop allowsAccessFrom from the methodTable and delegate cross-origin
+        checking to the DOM bindings for [[SetPrototypeOf]] / [[GetPrototypeOf]].
+        This is more consistent with other operations (e.g. [[GetOwnProperty]]).
+
+        * jsc.cpp:
+        * runtime/JSGlobalObject.cpp:
+        * runtime/JSGlobalObject.h:
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncProtoGetter):
+        (JSC::globalFuncProtoSetter):
+        (JSC::globalFuncBuiltinLog): Deleted.
+        * runtime/JSGlobalObjectFunctions.h:
+        * runtime/JSObject.h:
+        (JSC::JSObject::getArrayLength): Deleted.
+        * runtime/JSProxy.cpp:
+        (JSC::JSProxy::setPrototype):
+        (JSC::JSProxy::getPrototype):
+        * runtime/JSProxy.h:
+        * runtime/ObjectConstructor.cpp:
+        (JSC::objectConstructorGetPrototypeOf):
+        (JSC::objectConstructorSetPrototypeOf):
+        (JSC::objectConstructorGetOwnPropertyDescriptor): Deleted.
+        (JSC::objectConstructorGetOwnPropertyDescriptors): Deleted.
+        * runtime/ObjectConstructor.h:
+        * runtime/ReflectObject.cpp:
+        (JSC::reflectObjectGetPrototypeOf):
+        (JSC::reflectObjectSetPrototypeOf):
+
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::setPrototypeWithCycleCheck):
+        Comment out check added in r197648. This check was added to match
+        the latest EcmaScript spec:
+        - https://tc39.github.io/ecma262/#sec-ordinarysetprototypeof (step 8)
+        This check allowed for [[Prototype]] chain cycles if the prototype
+        chain includes objects that do not use the ordinary object definitions
+        for [[GetPrototypeOf]] and [[SetPrototypeOf]].
+        The issue is that the rest of our code base does not properly handle
+        such cycles and we can end up in infinite loops. This became obvious
+        because this patch updates Window / Location so that they no longer
+        use the default [[GetPrototypeOf]] / [[SetPrototypeOf]]. If I do not
+        comment out this check, I get an infinite loop in
+        Structure::anyObjectInChainMayInterceptIndexedAccesses(), which is
+        called from JSObject::setPrototypeDirect(), when running the following
+        layout test:
+        - html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html
+        I filed https://bugs.webkit.org/show_bug.cgi?id=161534 to track this
+        issue.
+
 2016-09-01  Yusuke Suzuki  <[email protected]>
 
         Add toJS for JSC::PrivateName

Modified: trunk/Source/_javascript_Core/jsc.cpp (205353 => 205354)


--- trunk/Source/_javascript_Core/jsc.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/jsc.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -903,7 +903,7 @@
 };
 
 const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, nullptr, CREATE_METHOD_TABLE(GlobalObject) };
-const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, nullptr, nullptr };
+const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, nullptr, nullptr };
 
 
 GlobalObject::GlobalObject(VM& vm, Structure* structure)

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -207,7 +207,7 @@
 
 const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &Base::s_info, &globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) };
 
-const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, nullptr, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
+const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, nullptr, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
 
 /* Source for JSGlobalObject.lut.h
 @begin globalObjectTable

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2016-09-02 18:04:25 UTC (rev 205354)
@@ -148,9 +148,6 @@
 typedef Vector<ExecState*, 16> ExecStateStack;
 
 struct GlobalObjectMethodTable {
-    typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*);
-    AllowsAccessFromFunctionPtr allowsAccessFrom;
-
     typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*);
     SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo;
 
@@ -712,7 +709,6 @@
 
     const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; }
 
-    static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; }
     static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; }
 
     JS_EXPORT_PRIVATE ExecState* globalExec();

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -866,38 +866,6 @@
     return throwVMTypeError(exec, scope, "'arguments', 'callee', and 'caller' cannot be accessed in strict mode.");
 }
 
-class GlobalFuncProtoGetterFunctor {
-public:
-    GlobalFuncProtoGetterFunctor(ExecState* exec, JSObject* thisObject)
-        : m_exec(exec)
-        , m_hasSkippedFirstFrame(false)
-        , m_thisObject(thisObject)
-        , m_result(JSValue::encode(jsUndefined()))
-    {
-    }
-
-    EncodedJSValue result() { return m_result; }
-
-    StackVisitor::Status operator()(StackVisitor& visitor) const
-    {
-        if (!m_hasSkippedFirstFrame) {
-            m_hasSkippedFirstFrame = true;
-            return StackVisitor::Continue;
-        }
-
-        if (m_thisObject->allowsAccessFrom(visitor->callFrame()))
-            m_result = JSValue::encode(m_thisObject->getPrototype(m_exec->vm(), m_exec));
-
-        return StackVisitor::Done;
-    }
-
-private:
-    ExecState* m_exec;
-    mutable bool m_hasSkippedFirstFrame;
-    JSObject* m_thisObject;
-    mutable EncodedJSValue m_result;
-};
-
 EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -915,49 +883,9 @@
         return JSValue::encode(prototype);
     }
 
-    GlobalFuncProtoGetterFunctor functor(exec, thisObject);
-    // This can throw but it's just unneeded extra work to check for it. The return
-    // value from this function is only used as the return value from a host call.
-    // Therefore, the return value is only used if there wasn't an exception.
-    exec->iterate(functor);
-    return functor.result();
+    return JSValue::encode(thisObject->getPrototype(vm, exec));
 }
 
-class GlobalFuncProtoSetterFunctor {
-public:
-    GlobalFuncProtoSetterFunctor(JSObject* thisObject)
-        : m_hasSkippedFirstFrame(false)
-        , m_allowsAccess(false)
-        , m_thisObject(thisObject)
-    {
-    }
-
-    bool allowsAccess() const { return m_allowsAccess; }
-
-    StackVisitor::Status operator()(StackVisitor& visitor) const
-    {
-        if (!m_hasSkippedFirstFrame) {
-            m_hasSkippedFirstFrame = true;
-            return StackVisitor::Continue;
-        }
-
-        m_allowsAccess = m_thisObject->allowsAccessFrom(visitor->callFrame());
-        return StackVisitor::Done;
-    }
-
-private:
-    mutable bool m_hasSkippedFirstFrame;
-    mutable bool m_allowsAccess;
-    JSObject* m_thisObject;
-};
-
-bool checkProtoSetterAccessAllowed(ExecState* exec, JSObject* object)
-{
-    GlobalFuncProtoSetterFunctor functor(object);
-    exec->iterate(functor);
-    return functor.allowsAccess();
-}
-
 EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -974,9 +902,6 @@
     if (!thisObject)
         return JSValue::encode(jsUndefined());
 
-    if (!checkProtoSetterAccessAllowed(exec, thisObject))
-        return JSValue::encode(jsUndefined());
-
     // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
     if (!value.isObject() && !value.isNull())
         return JSValue::encode(jsUndefined());

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2016-09-02 18:04:25 UTC (rev 205354)
@@ -52,8 +52,6 @@
 EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState*);
 
-bool checkProtoSetterAccessAllowed(ExecState*, JSObject*);
-
 static const double mantissaOverflowLowerBound = 9007199254740992.0;
 double parseIntOverflow(const LChar*, unsigned length, int radix);
 bool isStrWhiteSpace(UChar);

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1371,7 +1371,6 @@
     }
 
     JSValue nextPrototype = prototype;
-    MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
     while (nextPrototype && nextPrototype.isObject()) {
         if (nextPrototype == this) {
             if (shouldThrowIfCantSet)
@@ -1378,8 +1377,11 @@
                 throwTypeError(exec, scope, ASCIILiteral("cyclic __proto__ value"));
             return false;
         }
-        if (UNLIKELY(asObject(nextPrototype)->methodTable(vm)->getPrototype != defaultGetPrototype))
-            break; // We're done. Set the prototype.
+        // FIXME: The specification says we should do this but this allows for cycles and our
+        // code base currently does not deal properly with such cycles.
+        // https://bugs.webkit.org/show_bug.cgi?id=161534
+        // if (UNLIKELY(asObject(nextPrototype)->methodTable(vm)->getPrototype != JSObject::getPrototype))
+        //    break; // We're done. Set the prototype.
         nextPrototype = asObject(nextPrototype)->getPrototypeDirect();
     }
     setPrototypeDirect(vm, prototype);
@@ -1401,12 +1403,6 @@
     return methodTable(vm)->setPrototype(this, exec, prototype, shouldThrowIfCantSet);
 }
 
-bool JSObject::allowsAccessFrom(ExecState* exec)
-{
-    JSGlobalObject* globalObject = this->globalObject();
-    return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
-}
-
 bool JSObject::putGetter(ExecState* exec, PropertyName propertyName, JSValue getter, unsigned attributes)
 {
     PropertyDescriptor descriptor;

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2016-09-02 18:04:25 UTC (rev 205354)
@@ -168,8 +168,6 @@
     // being returned. Once this is fixed we should migrate code & remove this method.
     JS_EXPORT_PRIVATE bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
 
-    JS_EXPORT_PRIVATE bool allowsAccessFrom(ExecState*);
-
     unsigned getArrayLength() const
     {
         if (!hasIndexedProperties(indexingType()))

Modified: trunk/Source/_javascript_Core/runtime/JSProxy.cpp (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSProxy.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSProxy.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -139,4 +139,16 @@
     thisObject->target()->methodTable(exec->vm())->getOwnPropertyNames(thisObject->target(), exec, propertyNames, mode);
 }
 
+bool JSProxy::setPrototype(JSObject* object, ExecState* exec, JSValue value, bool shouldThrowIfCantSet)
+{
+    JSProxy* thisObject = jsCast<JSProxy*>(object);
+    return thisObject->target()->methodTable(exec->vm())->setPrototype(thisObject->target(), exec, value, shouldThrowIfCantSet);
+}
+
+JSValue JSProxy::getPrototype(JSObject* object, ExecState* exec)
+{
+    JSProxy* thisObject = jsCast<JSProxy*>(object);
+    return thisObject->target()->methodTable(exec->vm())->getPrototype(thisObject->target(), exec);
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSProxy.h (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/JSProxy.h	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/JSProxy.h	2016-09-02 18:04:25 UTC (rev 205354)
@@ -94,6 +94,8 @@
     JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
+    JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue, bool shouldThrowIfCantSet);
+    JS_EXPORT_PRIVATE static JSValue getPrototype(JSObject*, ExecState*);
 
 private:
     WriteBarrier<JSObject> m_target;

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -166,55 +166,12 @@
     return CallType::Host;
 }
 
-class ObjectConstructorGetPrototypeOfFunctor {
-public:
-    ObjectConstructorGetPrototypeOfFunctor(ExecState* exec, JSObject* object)
-        : m_exec(exec)
-        , m_hasSkippedFirstFrame(false)
-        , m_object(object)
-        , m_result(jsUndefined())
-    {
-    }
-
-    JSValue result() const { return m_result; }
-
-    StackVisitor::Status operator()(StackVisitor& visitor) const
-    {
-        if (!m_hasSkippedFirstFrame) {
-            m_hasSkippedFirstFrame = true;
-            return StackVisitor::Continue;
-        }
-
-        if (m_object->allowsAccessFrom(visitor->callFrame()))
-            m_result = m_object->getPrototype(m_exec->vm(), m_exec);
-        else
-            m_result = jsNull();
-        return StackVisitor::Done;
-    }
-
-private:
-    ExecState* m_exec;
-    mutable bool m_hasSkippedFirstFrame;
-    JSObject* m_object;
-    mutable JSValue m_result;
-};
-
-JSValue objectConstructorGetPrototypeOf(ExecState* exec, JSObject* object)
-{
-    ObjectConstructorGetPrototypeOfFunctor functor(exec, object);
-    // This can throw but it's just unneeded extra work to check for it. The return
-    // value from this function is only used as the return value from a host call.
-    // Therefore, the return value is only used if there wasn't an exception.
-    exec->iterate(functor);
-    return functor.result();
-}
-
 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
 {
     JSObject* object = exec->argument(0).toObject(exec);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
-    return JSValue::encode(objectConstructorGetPrototypeOf(exec, object));
+    return JSValue::encode(object->getPrototype(exec->vm(), exec));
 }
 
 EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState* exec)
@@ -234,11 +191,6 @@
     if (exec->hadException())
         return JSValue::encode(objectValue);
 
-    if (!checkProtoSetterAccessAllowed(exec, object)) {
-        throwTypeError(exec, scope, ASCIILiteral("Permission denied"));
-        return JSValue::encode(objectValue);
-    }
-
     bool shouldThrowIfCantSet = true;
     bool didSetPrototype = object->setPrototype(vm, exec, protoValue, shouldThrowIfCantSet);
     ASSERT_UNUSED(didSetPrototype, vm.exception() || didSetPrototype);

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.h (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.h	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.h	2016-09-02 18:04:25 UTC (rev 205354)
@@ -124,7 +124,6 @@
 
 
 JS_EXPORT_PRIVATE JSObject* objectConstructorFreeze(ExecState*, JSObject*);
-JSValue objectConstructorGetPrototypeOf(ExecState*, JSObject*);
 JSValue objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, const Identifier&);
 JSValue objectConstructorGetOwnPropertyDescriptors(ExecState*, JSObject*);
 JSArray* ownPropertyKeys(ExecState*, JSObject*, PropertyNameMode, DontEnumPropertiesMode);

Modified: trunk/Source/_javascript_Core/runtime/ReflectObject.cpp (205353 => 205354)


--- trunk/Source/_javascript_Core/runtime/ReflectObject.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/_javascript_Core/runtime/ReflectObject.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -215,7 +215,7 @@
     JSValue target = exec->argument(0);
     if (!target.isObject())
         return JSValue::encode(throwTypeError(exec, scope, ASCIILiteral("Reflect.getPrototypeOf requires the first argument be an object")));
-    return JSValue::encode(objectConstructorGetPrototypeOf(exec, asObject(target)));
+    return JSValue::encode(asObject(target)->getPrototype(exec->vm(), exec));
 }
 
 // https://tc39.github.io/ecma262/#sec-reflect.isextensible
@@ -302,9 +302,6 @@
 
     JSObject* object = asObject(target);
 
-    if (!checkProtoSetterAccessAllowed(exec, object))
-        return JSValue::encode(jsBoolean(false));
-
     bool shouldThrowIfCantSet = false;
     bool didSetPrototype = object->setPrototype(vm, exec, proto, shouldThrowIfCantSet);
     if (vm.exception())

Modified: trunk/Source/WebCore/ChangeLog (205353 => 205354)


--- trunk/Source/WebCore/ChangeLog	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/ChangeLog	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1,3 +1,41 @@
+2016-09-02  Chris Dumez  <[email protected]>
+
+        Align proto getter / setter behavior with other browsers
+        https://bugs.webkit.org/show_bug.cgi?id=161455
+
+        Reviewed by Mark Lam.
+
+        Align cross-origin __proto__ getter / setter behavior with other
+        browsers and the specification:
+
+        [[SetPrototypeOf]] should throw a TypeError:
+        - https://html.spec.whatwg.org/#windowproxy-setprototypeof
+        - https://html.spec.whatwg.org/#location-setprototypeof
+        - https://tc39.github.io/ecma262/#sec-object.setprototypeof (step 5)
+
+        [[GetPrototypeOf]] should return null cross-origin:
+        - https://html.spec.whatwg.org/#windowproxy-getprototypeof
+        - https://html.spec.whatwg.org/#location-getprototypeof
+
+        Test: js/dom/setPrototypeOf-location-window.html
+
+        * bindings/js/JSDOMWindowBase.cpp:
+        (WebCore::JSDOMWindowBase::JSDOMWindowBase): Deleted.
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::setPrototype):
+        (WebCore::JSDOMWindow::getPrototype):
+        * bindings/js/JSLocationCustom.cpp:
+        (WebCore::JSLocation::setPrototype):
+        (WebCore::JSLocation::getPrototype):
+        * bindings/js/JSWorkerGlobalScopeBase.cpp:
+        (WebCore::JSWorkerGlobalScopeBase::supportsRichSourceInfo): Deleted.
+        * bindings/js/JSWorkerGlobalScopeBase.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        * bindings/scripts/IDLAttributes.txt:
+        * page/DOMWindow.idl:
+        * page/Location.idl:
+
 2016-09-02  Eric Carlson  <[email protected]>
 
         [MediaStream] applyConstraints pt. 1 - mandatory constraints

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp (205353 => 205354)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -57,14 +57,9 @@
 
 namespace WebCore {
 
-static bool shouldAllowAccessFrom(const JSGlobalObject* thisObject, ExecState* exec)
-{
-    return BindingSecurity::shouldAllowAccessToDOMWindow(exec, asJSDOMWindow(thisObject)->wrapped());
-}
-
 const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSDOMWindowBase) };
 
-const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { &shouldAllowAccessFrom, &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, &moduleLoaderEvaluate, &defaultLanguage };
+const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, &moduleLoaderEvaluate, &defaultLanguage };
 
 JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, RefPtr<DOMWindow>&& window, JSDOMWindowShell* shell)
     : JSDOMGlobalObject(vm, structure, shell->world(), &s_globalObjectMethodTable)

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp (205353 => 205354)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -342,6 +342,25 @@
     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
 }
 
+bool JSDOMWindow::setPrototype(JSObject*, ExecState* exec, JSValue, bool shouldThrowIfCantSet)
+{
+    auto scope = DECLARE_THROW_SCOPE(exec->vm());
+
+    if (shouldThrowIfCantSet)
+        throwTypeError(exec, scope, ASCIILiteral("Cannot set prototype of this object"));
+
+    return false;
+}
+
+JSValue JSDOMWindow::getPrototype(JSObject* object, ExecState* exec)
+{
+    JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
+    if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError))
+        return jsNull();
+
+    return Base::getPrototype(object, exec);
+}
+
 // Custom Attributes
 
 void JSDOMWindow::setLocation(ExecState& state, JSValue value)

Modified: trunk/Source/WebCore/bindings/js/JSLocationCustom.cpp (205353 => 205354)


--- trunk/Source/WebCore/bindings/js/JSLocationCustom.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/bindings/js/JSLocationCustom.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -124,6 +124,25 @@
     return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
 }
 
+bool JSLocation::setPrototype(JSObject*, ExecState* exec, JSValue, bool shouldThrowIfCantSet)
+{
+    auto scope = DECLARE_THROW_SCOPE(exec->vm());
+
+    if (shouldThrowIfCantSet)
+        throwTypeError(exec, scope, ASCIILiteral("Cannot set prototype of this object"));
+
+    return false;
+}
+
+JSValue JSLocation::getPrototype(JSObject* object, ExecState* exec)
+{
+    JSLocation* thisObject = jsCast<JSLocation*>(object);
+    if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), DoNotReportSecurityError))
+        return jsNull();
+
+    return Base::getPrototype(object, exec);
+}
+
 bool JSLocationPrototype::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&, bool& putResult)
 {
     putResult = false;

Modified: trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp (205353 => 205354)


--- trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp	2016-09-02 18:04:25 UTC (rev 205354)
@@ -45,7 +45,7 @@
 
 const ClassInfo JSWorkerGlobalScopeBase::s_info = { "WorkerGlobalScope", &JSDOMGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSWorkerGlobalScopeBase) };
 
-const GlobalObjectMethodTable JSWorkerGlobalScopeBase::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr, &defaultLanguage };
+const GlobalObjectMethodTable JSWorkerGlobalScopeBase::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, &_javascript_RuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr, &defaultLanguage };
 
 JSWorkerGlobalScopeBase::JSWorkerGlobalScopeBase(JSC::VM& vm, JSC::Structure* structure, RefPtr<WorkerGlobalScope>&& impl)
     : JSDOMGlobalObject(vm, structure, normalWorld(vm), &s_globalObjectMethodTable)
@@ -79,11 +79,6 @@
     return m_wrapped.get();
 }
 
-bool JSWorkerGlobalScopeBase::allowsAccessFrom(const JSGlobalObject* object, ExecState* exec)
-{
-    return JSGlobalObject::allowsAccessFrom(object, exec);
-}
-
 bool JSWorkerGlobalScopeBase::supportsRichSourceInfo(const JSGlobalObject* object)
 {
     return JSGlobalObject::supportsRichSourceInfo(object);

Modified: trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h (205353 => 205354)


--- trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h	2016-09-02 18:04:25 UTC (rev 205354)
@@ -53,7 +53,6 @@
 
         static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable;
 
-        static bool allowsAccessFrom(const JSC::JSGlobalObject*, JSC::ExecState*);
         static bool supportsRichSourceInfo(const JSC::JSGlobalObject*);
         static bool shouldInterruptScript(const JSC::JSGlobalObject*);
         static bool shouldInterruptScriptBeforeTimeout(const JSC::JSGlobalObject*);

Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (205353 => 205354)


--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-09-02 18:04:25 UTC (rev 205354)
@@ -1322,6 +1322,10 @@
     # Custom defineOwnProperty function
     push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnProperty"};
 
+    # Custom getPrototype / setPrototype functions.
+    push (@headerContent, "    static JSC::JSValue getPrototype(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{"CustomGetPrototype"};
+    push (@headerContent, "    static bool setPrototype(JSC::JSObject*, JSC::ExecState*, JSC::JSValue, bool shouldThrowIfCantSet);\n") if $interface->extendedAttributes->{"CustomSetPrototype"};
+
     # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
     if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
         $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;

Modified: trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt (205353 => 205354)


--- trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt	2016-09-02 18:04:25 UTC (rev 205354)
@@ -41,6 +41,7 @@
 CustomDeleteProperty
 CustomEnumerateProperty
 CustomGetOwnPropertySlot
+CustomGetPrototype
 CustomGetter
 CustomIndexedSetter
 CustomIsReachable
@@ -49,6 +50,7 @@
 CustomProxyToJSObject
 CustomPutFunction
 CustomReturn
+CustomSetPrototype
 CustomSetter
 CustomToJSObject
 Deletable

Modified: trunk/Source/WebCore/page/DOMWindow.idl (205353 => 205354)


--- trunk/Source/WebCore/page/DOMWindow.idl	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/page/DOMWindow.idl	2016-09-02 18:04:25 UTC (rev 205354)
@@ -29,8 +29,10 @@
     CustomDeleteProperty,
     CustomEnumerateProperty,
     CustomGetOwnPropertySlot,
+    CustomGetPrototype,
     CustomProxyToJSObject,
     CustomPutFunction,
+    CustomSetPrototype,
     ExportMacro=WEBCORE_EXPORT,
     ImplicitThis,
     InterfaceName=Window,

Modified: trunk/Source/WebCore/page/Location.idl (205353 => 205354)


--- trunk/Source/WebCore/page/Location.idl	2016-09-02 18:01:51 UTC (rev 205353)
+++ trunk/Source/WebCore/page/Location.idl	2016-09-02 18:04:25 UTC (rev 205354)
@@ -30,7 +30,9 @@
     CheckSecurity,
     CustomDeleteProperty,
     CustomEnumerateProperty,
+    CustomGetPrototype,
     CustomNamedSetter,
+    CustomSetPrototype,
     GenerateIsReachable=ImplFrame,
     JSCustomDefineOwnProperty,
     JSCustomDefineOwnPropertyOnPrototype,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to