Diff
Modified: trunk/LayoutTests/ChangeLog (278584 => 278585)
--- trunk/LayoutTests/ChangeLog 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/ChangeLog 2021-06-08 01:10:23 UTC (rev 278585)
@@ -1,3 +1,21 @@
+2021-06-07 Alexey Shvayka <[email protected]>
+
+ Window should behave like a legacy platform object without indexed setter
+ https://bugs.webkit.org/show_bug.cgi?id=225894
+
+ Reviewed by Darin Adler.
+
+ * fast/dom/Window/orphaned-frame-access.html:
+ * fast/frames/iframe-detached-window-still-writable-eval-expected.txt:
+ * fast/frames/iframe-detached-window-still-writable-eval.html:
+ * http/tests/security/cross-frame-access-delete-expected.txt:
+ * http/tests/security/resources/cross-frame-iframe-for-delete-test.html:
+ * js/dom/dfg-ensure-array-storage-on-window-expected.txt:
+ * js/dom/indexed-setter-on-global-object-expected.txt:
+ * js/dom/script-tests/dfg-ensure-array-storage-on-window.js:
+ * js/dom/script-tests/dfg-ensure-non-array-array-storage-on-window.js:
+ * js/dom/script-tests/indexed-setter-on-global-object.js:
+
2021-06-07 Wenson Hsieh <[email protected]>
Upstream WebKit support for Live Text
Modified: trunk/LayoutTests/fast/dom/Window/orphaned-frame-access.html (278584 => 278585)
--- trunk/LayoutTests/fast/dom/Window/orphaned-frame-access.html 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/fast/dom/Window/orphaned-frame-access.html 2021-06-08 01:10:23 UTC (rev 278585)
@@ -17,7 +17,7 @@
// schedule to run after the frame is null
setTimeout(function() {
document.body.appendChild(document.createTextNode(win.test || 'property: FAIL ... '));
- document.body.appendChild(document.createTextNode(win[20] || 'array: FAIL ... '));
+ document.body.appendChild(document.createTextNode(win[20] === undefined ? 'array: PASS ... ' : 'array: FAIL ... '));
document.body.appendChild(document.createTextNode(win.Comment ? 'constructor: PASS .... ' : 'constructor: FAIL ... '));
document.body.appendChild(document.createTextNode(win.postMessage ? 'operation: PASS.' : 'operation: FAIL.'));
if (window.testRunner)
Modified: trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval-expected.txt (278584 => 278585)
--- trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval-expected.txt 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval-expected.txt 2021-06-08 01:10:23 UTC (rev 278585)
@@ -4,9 +4,9 @@
PASS () => foo is 2
-PASS () => globalThis[0] is 2
+PASS () => globalThis[0] is undefined
PASS iframeContentWindow.foo is 2
-PASS iframeContentWindow[0] is 2
+PASS iframeContentWindow[0] is undefined
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval.html (278584 => 278585)
--- trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval.html 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval.html 2021-06-08 01:10:23 UTC (rev 278585)
@@ -15,10 +15,10 @@
foo++;
globalThis[0]++;
shouldBe(() => foo, "2");
- shouldBe(() => globalThis[0], "2");
+ shouldBe(() => globalThis[0], "undefined");
`);
shouldBe("iframeContentWindow.foo", "2");
- shouldBe("iframeContentWindow[0]", "2");
+ shouldBe("iframeContentWindow[0]", "undefined");
</script>
</body>
</html>
\ No newline at end of file
Modified: trunk/LayoutTests/http/tests/security/cross-frame-access-delete-expected.txt (278584 => 278585)
--- trunk/LayoutTests/http/tests/security/cross-frame-access-delete-expected.txt 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/http/tests/security/cross-frame-access-delete-expected.txt 2021-06-08 01:10:23 UTC (rev 278585)
@@ -22,7 +22,7 @@
----- tests for deleting the properties of window, window.history, and window.location cross-domain -----
PASS: window.existingProperty should be 'test value' and is.
-PASS: window[1] should be 'test value' and is.
+PASS: window[1] should be 'undefined' and is.
PASS: window.history.existingProperty should be 'test value' and is.
PASS: window.history[1] should be 'test value' and is.
PASS: window.location.existingProperty should be 'test value' and is.
Modified: trunk/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-delete-test.html (278584 => 278585)
--- trunk/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-delete-test.html 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-delete-test.html 2021-06-08 01:10:23 UTC (rev 278585)
@@ -26,7 +26,7 @@
log("\n----- tests for deleting the properties of window, window.history, and window.location cross-domain -----\n");
shouldBe("window.existingProperty", "'test value'");
- shouldBe("window[1]", "'test value'");
+ shouldBe("window[1]", "undefined");
shouldBe("window.history.existingProperty", "'test value'");
shouldBe("window.history[1]", "'test value'");
shouldBe("window.location.existingProperty", "'test value'");
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (278584 => 278585)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2021-06-08 01:10:23 UTC (rev 278585)
@@ -1,3 +1,17 @@
+2021-06-07 Alexey Shvayka <[email protected]>
+
+ Window should behave like a legacy platform object without indexed setter
+ https://bugs.webkit.org/show_bug.cgi?id=225894
+
+ Reviewed by Darin Adler.
+
+ * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache-expected.txt: Added.
+ * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache.html: Added.
+ * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-expected.txt:
+ * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict-expected.txt:
+ * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html:
+ * web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html:
+
2021-06-07 Imanol Fernandez <[email protected]>
Use 3D points to map the WebXRBoundedReferenceSpace bounds transform
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache-expected.txt (0 => 278585)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache-expected.txt 2021-06-08 01:10:23 UTC (rev 278585)
@@ -0,0 +1,4 @@
+
+PASS Absence of index '0' is not cached
+PASS Presence of index '0' is not cached
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache.html (0 => 278585)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache.html 2021-06-08 01:10:23 UTC (rev 278585)
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Deletion of WindowProxy's indexed properties is not cached</title>
+<link rel="help" href=""
+<script src=""
+<script src=""
+<div id=log></div>
+<script>
+const iframe = document.createElement("iframe");
+iframe.srcdoc = "";
+
+test(() => {
+ assert_equals(window.length, 0);
+ for (let i = 0; i < 1e5; i++) {
+ assert_true(delete window[0]);
+ }
+
+ document.body.append(iframe);
+ assert_false(delete window[0]);
+}, "Absence of index '0' is not cached");
+
+test(() => {
+ assert_equals(window.length, 1);
+ for (let i = 0; i < 1e5; i++) {
+ assert_false(delete window[0]);
+ }
+
+ iframe.remove();
+ assert_true(delete window[0]);
+}, "Presence of index '0' is not cached");
+</script>
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-expected.txt (278584 => 278585)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-expected.txt 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-expected.txt 2021-06-08 01:10:23 UTC (rev 278585)
@@ -1,7 +1,9 @@
PASS Indexed properties of the window object (non-strict mode)
PASS Ensure indexed properties have the correct configuration
-FAIL Indexed properties of the window object (non-strict mode) 1 assert_throws_js: function "() => Object.defineProperty(window, 0, { value: "bar" })" did not throw
-FAIL Indexed properties of the window object (non-strict mode) 2 assert_throws_js: function "() => Object.defineProperty(window, 1, { value: "bar" })" did not throw
+PASS Indexed properties of the window object (non-strict mode) 1
+PASS Indexed properties of the window object (non-strict mode) 2
+PASS Borderline numeric key: 2 ** 32 - 2 is an index
+PASS Borderline numeric key: 2 ** 32 - 1 is not an index
PASS Indexed properties of the window object (non-strict mode) 3
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict-expected.txt (278584 => 278585)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict-expected.txt 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict-expected.txt 2021-06-08 01:10:23 UTC (rev 278585)
@@ -1,10 +1,8 @@
PASS Indexed properties of the window object (strict mode)
-FAIL Indexed properties of the window object (strict mode) 1 assert_throws_js: function "function () {
- window[0] = "foo";
- }" did not throw
-FAIL Indexed properties of the window object (strict mode) 2 assert_throws_js: function "function () {
- window[1] = "foo";
- }" did not throw
+PASS Indexed properties of the window object (strict mode) 1
+PASS Indexed properties of the window object (strict mode) 2
+PASS Borderline numeric key: 2 ** 32 - 2 is an index (strict mode)
+PASS Borderline numeric key: 2 ** 32 - 1 is not an index (strict mode)
PASS Indexed properties of the window object (strict mode) 3
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html (278584 => 278585)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html 2021-06-08 01:10:23 UTC (rev 278585)
@@ -44,6 +44,29 @@
});
test(function() {
"use strict";
+ assert_throws_js(TypeError, () => { window[4294967294] = 1; });
+ assert_false(Reflect.set(window, 4294967294, 2));
+ assert_false(Reflect.defineProperty(window, 4294967294, { value: 3 }));
+ assert_throws_js(TypeError, () => Object.defineProperty(window, 4294967294, { get: () => 4 }));
+ assert_equals(window[4294967294], undefined);
+ assert_false(4294967294 in window);
+ assert_true(delete window[4294967294]);
+}, "Borderline numeric key: 2 ** 32 - 2 is an index (strict mode)");
+test(function() {
+ "use strict";
+ window[4294967295] = 1;
+ assert_equals(window[4294967295], 1);
+ assert_true(Reflect.set(window, 4294967295, 2));
+ assert_equals(window[4294967295], 2);
+ assert_true(Reflect.defineProperty(window, 4294967295, { value: 3 }));
+ assert_equals(window[4294967295], 3);
+ Object.defineProperty(window, 4294967295, { get: () => 4 });
+ assert_equals(window[4294967295], 4);
+ assert_true(delete window[4294967295]);
+ assert_false(4294967295 in window);
+}, "Borderline numeric key: 2 ** 32 - 1 is not an index (strict mode)");
+test(function() {
+ "use strict";
var proto = Window.prototype;
[-1, 0, 1].forEach(function(idx) {
assert_false(idx in proto, idx + " in proto");
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html (278584 => 278585)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html 2021-06-08 01:10:23 UTC (rev 278585)
@@ -42,6 +42,27 @@
assert_equals(delete window[1], true);
});
test(function() {
+ window[4294967294] = 1;
+ assert_false(Reflect.set(window, 4294967294, 2));
+ assert_false(Reflect.defineProperty(window, 4294967294, { value: 3 }));
+ assert_throws_js(TypeError, () => Object.defineProperty(window, 4294967294, { get: () => 4 }));
+ assert_equals(window[4294967294], undefined);
+ assert_false(4294967294 in window);
+ assert_true(delete window[4294967294]);
+}, "Borderline numeric key: 2 ** 32 - 2 is an index");
+test(function() {
+ window[4294967295] = 1;
+ assert_equals(window[4294967295], 1);
+ assert_true(Reflect.set(window, 4294967295, 2));
+ assert_equals(window[4294967295], 2);
+ assert_true(Reflect.defineProperty(window, 4294967295, { value: 3 }));
+ assert_equals(window[4294967295], 3);
+ Object.defineProperty(window, 4294967295, { get: () => 4 });
+ assert_equals(window[4294967295], 4);
+ assert_true(delete window[4294967295]);
+ assert_false(4294967295 in window);
+}, "Borderline numeric key: 2 ** 32 - 1 is not an index");
+test(function() {
var proto = Window.prototype;
[-1, 0, 1].forEach(function(idx) {
assert_false(idx in proto, idx + " in proto");
Modified: trunk/LayoutTests/js/dom/dfg-ensure-array-storage-on-window-expected.txt (278584 => 278585)
--- trunk/LayoutTests/js/dom/dfg-ensure-array-storage-on-window-expected.txt 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/js/dom/dfg-ensure-array-storage-on-window-expected.txt 2021-06-08 01:10:23 UTC (rev 278585)
@@ -3,7 +3,7 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-PASS foo(w) is 1
+PASS foo(w) is NaN
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/dom/indexed-setter-on-global-object-expected.txt (278584 => 278585)
--- trunk/LayoutTests/js/dom/indexed-setter-on-global-object-expected.txt 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/js/dom/indexed-setter-on-global-object-expected.txt 2021-06-08 01:10:23 UTC (rev 278585)
@@ -3,7 +3,8 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-PASS thingy is "foo"
+PASS this.__defineSetter__(42, function() {}) threw exception TypeError: Failed to set an indexed property on Window: Indexed property setter is not supported..
+PASS this[42] is undefined
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/dom/script-tests/dfg-ensure-array-storage-on-window.js (278584 => 278585)
--- trunk/LayoutTests/js/dom/script-tests/dfg-ensure-array-storage-on-window.js 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/js/dom/script-tests/dfg-ensure-array-storage-on-window.js 2021-06-08 01:10:23 UTC (rev 278585)
@@ -23,4 +23,4 @@
var w = this;
w[0] = 1;
w.length = 1;
-shouldBe("foo(w)", "1");
+shouldBe("foo(w)", "NaN");
Modified: trunk/LayoutTests/js/dom/script-tests/dfg-ensure-non-array-array-storage-on-window.js (278584 => 278585)
--- trunk/LayoutTests/js/dom/script-tests/dfg-ensure-non-array-array-storage-on-window.js 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/js/dom/script-tests/dfg-ensure-non-array-array-storage-on-window.js 2021-06-08 01:10:23 UTC (rev 278585)
@@ -51,10 +51,8 @@
var w = this;
w[0] = 1;
w.length = 1;
-var thingy = false;
-w.__defineSetter__(1, function(value) { thingy = value; });
-shouldBe("foo(w)", "1");
-shouldBe("thingy", "false");
+shouldThrowErrorName("w.__defineSetter__(1, function() {})", "TypeError");
+shouldBe("foo(w)", "NaN");
// At this point we check to make sure that bar doesn't end up either creating array storage for
// the window proxy, or equally badly, storing to the already created array storage on the proxy
@@ -62,8 +60,7 @@
// thingy, to detect that for index 1 we fall through the proxy to the real window object.
bar(w);
-shouldBe("thingy", "42");
-shouldBe("foo(w)", "1");
w.length = 2;
-shouldBe("foo(w)", "0/0");
+shouldBe("w[1]", "");
+shouldBe("foo(w)", "NaN");
Modified: trunk/LayoutTests/js/dom/script-tests/indexed-setter-on-global-object.js (278584 => 278585)
--- trunk/LayoutTests/js/dom/script-tests/indexed-setter-on-global-object.js 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/LayoutTests/js/dom/script-tests/indexed-setter-on-global-object.js 2021-06-08 01:10:23 UTC (rev 278585)
@@ -2,13 +2,9 @@
"Tests that creating an indexed setter on the global object doesn't break things."
);
-var thingy;
+shouldThrowErrorName("this.__defineSetter__(42, function() {})", "TypeError");
-this.__defineSetter__(42, function(value) {
- thingy = value;
-});
-
this[42] = "foo";
-shouldBe("thingy", "\"foo\"");
+shouldBe("this[42]", "undefined");
Modified: trunk/Source/_javascript_Core/ChangeLog (278584 => 278585)
--- trunk/Source/_javascript_Core/ChangeLog 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-06-08 01:10:23 UTC (rev 278585)
@@ -1,3 +1,13 @@
+2021-06-07 Alexey Shvayka <[email protected]>
+
+ Window should behave like a legacy platform object without indexed setter
+ https://bugs.webkit.org/show_bug.cgi?id=225894
+
+ Reviewed by Darin Adler.
+
+ * runtime/TypeError.h:
+ (JSC::typeError):
+
2021-06-07 Saam Barati <[email protected]>
Short circuit read modify write nodes emit byte code that uses the wrong locals
Modified: trunk/Source/_javascript_Core/runtime/TypeError.h (278584 => 278585)
--- trunk/Source/_javascript_Core/runtime/TypeError.h 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/Source/_javascript_Core/runtime/TypeError.h 2021-06-08 01:10:23 UTC (rev 278585)
@@ -30,7 +30,8 @@
namespace JSC {
-inline bool typeError(JSGlobalObject* globalObject, ThrowScope& scope, bool throwException, ASCIILiteral message)
+template<typename Message>
+inline bool typeError(JSGlobalObject* globalObject, ThrowScope& scope, bool throwException, Message message)
{
if (throwException)
throwTypeError(globalObject, scope, message);
Modified: trunk/Source/WebCore/ChangeLog (278584 => 278585)
--- trunk/Source/WebCore/ChangeLog 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/Source/WebCore/ChangeLog 2021-06-08 01:10:23 UTC (rev 278585)
@@ -1,3 +1,55 @@
+2021-06-07 Alexey Shvayka <[email protected]>
+
+ Window should behave like a legacy platform object without indexed setter
+ https://bugs.webkit.org/show_bug.cgi?id=225894
+
+ Reviewed by Darin Adler.
+
+ This change fixes major interop issue by disallowing expando indexed properties on WindowProxy,
+ raising TypeError only when needed, which aligns WebKit with Blink and Gecko.
+
+ While [[DefineOwnProperty]] [1] and [[Delete]] [2] methods of WindowProxy are implemented
+ precisely per spec, current [[Set]] [3] algorithm seems to allow invoking setters from
+ the prototype chain. Blink and Gecko implement stricter semantics by failing early rather
+ than traversing the prototype chain, as does this patch.
+
+ To avoid breaking native apps that either add expando indexed properties to WindowProxy, or
+ more likely read / write indices of sloppy function's |this| value, which accidently happens
+ to be a WindowProxy, the new behavior is introduced only for web content and newly-built apps.
+
+ Since unlike putByIndex(), deletePropertyByIndex() might be invoked with UINT_MAX, which is
+ not an array index [4], isIndex() check is required. In future, JSC will be fixed to remove
+ such checks from all indexed overrides.
+
+ DeletePropertySlot::disableCaching() is not called because indexed deletes are not currently
+ repatched, and once they are, cacheability should be inferred from added type info flags.
+
+ Also, removes extra jsDOMWindowGetOwnPropertySlotRestrictedAccess() call for indices, which
+ is missing from the spec [5]; this is unobservable.
+
+ [1] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-defineownproperty (step 2.1)
+ [2] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete (step 2.1)
+ [3] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set (step 3)
+ [4] https://tc39.es/ecma262/#array-index
+ [5] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty (step 2.5.2)
+
+ Tests: imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache.html
+ imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html
+ imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html
+
+ * bindings/js/JSDOMExceptionHandling.cpp:
+ (WebCore::makeUnsupportedIndexedSetterErrorMessage):
+ * bindings/js/JSDOMExceptionHandling.h:
+ * bindings/js/JSDOMWindowCustom.cpp:
+ (WebCore::allowsLegacyExpandoIndexedProperties):
+ (WebCore::JSDOMWindow::getOwnPropertySlotByIndex): Remove outdated comments.
+ (WebCore::JSDOMWindow::put):
+ (WebCore::JSDOMWindow::putByIndex): Release scope when calling Base::putByIndex(), which could throw.
+ (WebCore::JSDOMWindow::deleteProperty):
+ (WebCore::JSDOMWindow::deletePropertyByIndex):
+ (WebCore::JSDOMWindow::defineOwnProperty):
+ * platform/cocoa/VersionChecks.h:
+
2021-06-07 Chris Dumez <[email protected]>
Drop legacy MainThreadTaskQueue & EventLoopTaskQueue classes
Modified: trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp (278584 => 278585)
--- trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp 2021-06-08 01:10:23 UTC (rev 278585)
@@ -280,6 +280,11 @@
return makeString("Can only call ", interfaceName, '.', functionName, " on instances of ", interfaceName);
}
+String makeUnsupportedIndexedSetterErrorMessage(const char* interfaceName)
+{
+ return makeString("Failed to set an indexed property on ", interfaceName, ": Indexed property setter is not supported.");
+}
+
EncodedJSValue throwThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName, const char* functionName)
{
return throwTypeError(lexicalGlobalObject, scope, makeThisTypeErrorMessage(interfaceName, functionName));
Modified: trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.h (278584 => 278585)
--- trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.h 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.h 2021-06-08 01:10:23 UTC (rev 278585)
@@ -55,6 +55,7 @@
JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* interfaceName);
String makeThisTypeErrorMessage(const char* interfaceName, const char* attributeName);
+String makeUnsupportedIndexedSetterErrorMessage(const char* interfaceName);
WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* interfaceName, const char* functionName);
Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp (278584 => 278585)
--- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp 2021-06-08 01:10:23 UTC (rev 278585)
@@ -59,6 +59,10 @@
#include "JSWebKitNamespace.h"
#endif
+#if PLATFORM(COCOA)
+#include "VersionChecks.h"
+#endif
+
namespace WebCore {
using namespace JSC;
@@ -91,6 +95,18 @@
}
#endif
+static ALWAYS_INLINE bool allowsLegacyExpandoIndexedProperties()
+{
+#if PLATFORM(COCOA)
+ // Given that WindowProxy is the default |this| value for sloppy mode functions, it's hard to prove
+ // that older iOS and macOS apps don't accidentally depend on this behavior, so we keep it for them.
+ static bool requiresQuirk = !linkedOnOrAfter(SDKVersion::FirstWithoutExpandoIndexedPropertiesOnWindow);
+ return requiresQuirk;
+#else
+ return false;
+#endif
+}
+
template <DOMWindowType windowType>
bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMGlobalObject* thisObject, AbstractDOMWindow& window, JSGlobalObject& lexicalGlobalObject, PropertyName propertyName, PropertySlot& slot, const String& errorMessage)
{
@@ -218,13 +234,8 @@
return false;
}
-// Property access sequence is:
-// (1) indexed properties,
-// (2) regular own properties,
-// (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, JSGlobalObject* lexicalGlobalObject, unsigned index, PropertySlot& slot)
{
- VM& vm = lexicalGlobalObject->vm();
auto* thisObject = jsCast<JSDOMWindow*>(object);
auto& window = thisObject->wrapped();
auto* frame = window.frame();
@@ -232,7 +243,6 @@
// Indexed getters take precendence over regular properties, so caching would be invalid.
slot.disableCaching();
- // (1) First, indexed properties.
// These are also allowed cross-origin, so come before the access check.
if (frame && index < frame->tree().scopedChildCount()) {
slot.setValue(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly), toJS(lexicalGlobalObject, frame->tree().scopedChild(index)->document()->domWindow()));
@@ -239,13 +249,11 @@
return true;
}
- // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
- String errorMessage;
- if (!BindingSecurity::shouldAllowAccessToDOMWindow(*lexicalGlobalObject, window, errorMessage))
- return jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Local>(thisObject, window, *lexicalGlobalObject, Identifier::from(vm, index), slot, errorMessage);
-
- // (2) Regular own properties.
- return Base::getOwnPropertySlotByIndex(thisObject, lexicalGlobalObject, index, slot);
+ if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, window, ThrowSecurityError))
+ return false;
+ if (allowsLegacyExpandoIndexedProperties())
+ return Base::getOwnPropertySlotByIndex(thisObject, lexicalGlobalObject, index, slot);
+ return false;
}
void JSDOMWindow::doPutPropertySecurityCheck(JSObject* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, PutPropertySlot&)
@@ -285,6 +293,8 @@
return false;
}
+ if (parseIndex(propertyName) && !allowsLegacyExpandoIndexedProperties())
+ return typeError(lexicalGlobalObject, scope, slot.isStrictMode(), makeUnsupportedIndexedSetterErrorMessage("Window"));
RELEASE_AND_RETURN(scope, Base::put(thisObject, lexicalGlobalObject, propertyName, value, slot));
}
@@ -300,7 +310,12 @@
return false;
}
- return Base::putByIndex(thisObject, lexicalGlobalObject, index, value, shouldThrow);
+ if (allowsLegacyExpandoIndexedProperties()) {
+ if (auto* document = thisObject->wrapped().document())
+ document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, "Adding expando indexed properties to 'window' was a non-standard behavior that is now removed."_s);
+ RELEASE_AND_RETURN(scope, Base::putByIndex(thisObject, lexicalGlobalObject, index, value, shouldThrow));
+ }
+ return typeError(lexicalGlobalObject, scope, shouldThrow, makeUnsupportedIndexedSetterErrorMessage("Window"));
}
bool JSDOMWindow::deleteProperty(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, DeletePropertySlot& slot)
@@ -309,6 +324,10 @@
// Only allow deleting properties by frames in the same origin.
if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
return false;
+ if (std::optional<uint32_t> index = parseIndex(propertyName)) {
+ if (!allowsLegacyExpandoIndexedProperties())
+ return index.value() >= thisObject->wrapped().length();
+ }
return Base::deleteProperty(thisObject, lexicalGlobalObject, propertyName, slot);
}
@@ -318,6 +337,8 @@
// Only allow deleting properties by frames in the same origin.
if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
return false;
+ if (isIndex(propertyName) && !allowsLegacyExpandoIndexedProperties())
+ return propertyName >= thisObject->wrapped().length();
return Base::deletePropertyByIndex(thisObject, lexicalGlobalObject, propertyName);
}
@@ -409,12 +430,18 @@
bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::JSGlobalObject* lexicalGlobalObject, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
{
+ VM& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
// Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
return false;
+ if (parseIndex(propertyName) && !allowsLegacyExpandoIndexedProperties())
+ return typeError(lexicalGlobalObject, scope, shouldThrow, makeUnsupportedIndexedSetterErrorMessage("Window"));
+ scope.release();
- auto& builtinNames = static_cast<JSVMClientData*>(lexicalGlobalObject->vm().clientData)->builtinNames();
+ auto& builtinNames = static_cast<JSVMClientData*>(vm.clientData)->builtinNames();
if (propertyName == builtinNames.documentPublicName() || propertyName == builtinNames.windowPublicName())
return JSObject::defineOwnProperty(thisObject, lexicalGlobalObject, propertyName, descriptor, shouldThrow);
Modified: trunk/Source/WebCore/platform/cocoa/VersionChecks.h (278584 => 278585)
--- trunk/Source/WebCore/platform/cocoa/VersionChecks.h 2021-06-08 01:04:17 UTC (rev 278584)
+++ trunk/Source/WebCore/platform/cocoa/VersionChecks.h 2021-06-08 01:10:23 UTC (rev 278585)
@@ -73,6 +73,7 @@
FirstWithSharedNetworkProcess = DYLD_IOS_VERSION_14_5,
FirstWithBlankViewOnJSPrompt = DYLD_IOS_VERSION_14_5,
FirstWithApplicationCacheDisabledByDefault = DYLD_IOS_VERSION_15_0,
+ FirstWithoutExpandoIndexedPropertiesOnWindow = DYLD_IOS_VERSION_15_0,
#elif PLATFORM(MAC)
FirstWithNetworkCache = DYLD_MACOSX_VERSION_10_11,
FirstWithExceptionsForDuplicateCompletionHandlerCalls = DYLD_MACOSX_VERSION_10_13,
@@ -96,6 +97,7 @@
FirstWithDOMWindowReuseRestriction = DYLD_MACOSX_VERSION_11_3,
FirstWithBlankViewOnJSPrompt = DYLD_MACOSX_VERSION_11_3,
FirstWithApplicationCacheDisabledByDefault = DYLD_MACOSX_VERSION_12_00,
+ FirstWithoutExpandoIndexedPropertiesOnWindow = DYLD_MACOSX_VERSION_12_00,
#endif
};