Log Message
Align internal methods of WindowProperties object with the spec https://bugs.webkit.org/show_bug.cgi?id=222918
Reviewed by Sam Weinig. LayoutTests/imported/w3c: * web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window-expected.txt: * web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window.js: * web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object-expected.txt: Added. * web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object.html: Added. * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html: * web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties-expected.txt: * web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html: Source/WebCore: This patch: 1. Implements [[PreventExtensions]], [[DefineOwnProperty]], and [[Delete]] methods that always fail [1], ensuring [[Set]] with altered receiver is passed through, indexed properties are rejected as well, and an exception is thrown if neccessary. Adding a put() override would a) slow down global `var` creation and b) require factoring out most of JSObject::putInlineSlow(). Instead, we prevent extensions on a structure while defining isExtensible() override to cover that up. 2. Corrects property attributes reported by [[GetOwnProperty]] methods of cross-origin WindowProxy [2] and WindowProperties, bringing these objects in compliance with invariants of internal methods [3]. 3. Removes comments on cross-browser differences and priority order from [[GetOwnProperty]] because it correctly implements the now detailed spec [4]. Browsing contexts precedence is covered by wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html test. 4. Asserts that WindowProperties [[Prototype]] is an object, as guaranteed by its [[SetPrototypeOf]]. This change fully implements the current spec, aligning WebKit with Blink and Gecko. [1] https://heycam.github.io/webidl/#named-properties-object-defineownproperty [2] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty (step 6.2) [3] https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods [4] https://html.spec.whatwg.org/multipage/window-object.html#dom-window-nameditem (step 2) Tests: imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object.html imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html * bindings/js/JSDOMWindowCustom.cpp: (WebCore::jsDOMWindowGetOwnPropertySlotRestrictedAccess): * bindings/js/JSDOMWindowProperties.cpp: (WebCore::jsDOMWindowPropertiesGetOwnPropertySlotNamedItemGetter): (WebCore::JSDOMWindowProperties::finishCreation): (WebCore::JSDOMWindowProperties::getOwnPropertySlot): (WebCore::JSDOMWindowProperties::deleteProperty): (WebCore::JSDOMWindowProperties::deletePropertyByIndex): (WebCore::JSDOMWindowProperties::preventExtensions): (WebCore::JSDOMWindowProperties::isExtensible): (WebCore::JSDOMWindowProperties::defineOwnProperty): * bindings/js/JSDOMWindowProperties.h:
Modified Paths
- trunk/LayoutTests/imported/w3c/ChangeLog
- trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window-expected.txt
- trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window.js
- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties-expected.txt
- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html
- trunk/Source/WebCore/ChangeLog
- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
- trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp
- trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.h
Added Paths
Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (277828 => 277829)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2021-05-20 22:14:40 UTC (rev 277829)
@@ -1,3 +1,18 @@
+2021-05-20 Alexey Shvayka <shvaikal...@gmail.com>
+
+ Align internal methods of WindowProperties object with the spec
+ https://bugs.webkit.org/show_bug.cgi?id=222918
+
+ Reviewed by Sam Weinig.
+
+ * web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window-expected.txt:
+ * web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window.js:
+ * web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object-expected.txt: Added.
+ * web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object.html: Added.
+ * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html:
+ * web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties-expected.txt:
+ * web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html:
+
2021-05-20 Felipe Erias <felipeer...@igalia.com>
[css-flexbox] Wrong height of an empty table inside an orthogonal flex parent
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window-expected.txt (277828 => 277829)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window-expected.txt 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window-expected.txt 2021-05-20 22:14:40 UTC (rev 277829)
@@ -1,5 +1,4 @@
PASS @@toStringTag exists with the appropriate descriptor
PASS Object.prototype.toString
-PASS Object.prototype.toString applied after modifying @@toStringTag
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window.js (277828 => 277829)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window.js 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-named-properties-object.window.js 2021-05-20 22:14:40 UTC (rev 277829)
@@ -16,17 +16,6 @@
assert_equals(Object.prototype.toString.call(namedPropertiesObject), "[object WindowProperties]");
}, "Object.prototype.toString");
-test(t => {
- assert_own_property(namedPropertiesObject, Symbol.toStringTag, "Precondition for this test: @@toStringTag exists");
-
- t.add_cleanup(() => {
- Object.defineProperty(namedPropertiesObject, Symbol.toStringTag, { value: "WindowProperties" });
- });
-
- Object.defineProperty(namedPropertiesObject, Symbol.toStringTag, { value: "NotWindowProperties" });
- assert_equals(Object.prototype.toString.call(namedPropertiesObject), "[object NotWindowProperties]");
-}, "Object.prototype.toString applied after modifying @@toStringTag");
-
// Chrome had a bug (https://bugs.chromium.org/p/chromium/issues/detail?id=793406) where if there
// was no @@toStringTag, it would fall back to a magic class string. Tests for this are present in
// the sibling class-string*.any.js tests. However, the named properties object always fails calls
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object-expected.txt (0 => 277829)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object-expected.txt 2021-05-20 22:14:40 UTC (rev 277829)
@@ -0,0 +1,15 @@
+
+PASS [[SetPrototypeOf]] and [[GetPrototypeOf]]
+PASS [[PreventExtensions]] and [[IsExtensible]]
+PASS [[GetOwnProperty]]
+PASS [[GetOwnProperty]] (named property visibility algorithm)
+PASS [[DefineOwnProperty]]
+PASS [[HasProperty]]
+PASS [[Get]]
+PASS [[Get]] (named property visibility algorithm)
+PASS [[Set]] (direct)
+PASS [[Set]] (prototype chain)
+PASS [[Set]] (Reflect.set)
+PASS [[Delete]]
+PASS [[OwnPropertyKeys]]
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object.html (0 => 277829)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object.html 2021-05-20 22:14:40 UTC (rev 277829)
@@ -0,0 +1,284 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Internal methods of Window's named properties object</title>
+<link rel="help" href=""
+<script src=""
+<script src=""
+<body>
+<script>
+function sloppyModeSet(base, key, value) { base[key] = value; }
+</script>
+<script>
+"use strict";
+
+const supportedNonIndex = "supported non-index property name";
+const supportedIndex = "supported indexed property name";
+const unsupportedNonIndex = "unsupported non-index property name";
+const unsupportedIndex = "unsupported indexed property name";
+const existingSymbol = "existing symbol property name";
+const nonExistingSymbol = "non-existing symbol property name";
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+
+ Object.setPrototypeOf(wp, w.EventTarget.prototype); // Setting current [[Prototype]] value shouldn't throw
+
+ assert_throws_js(TypeError, () => { Object.setPrototypeOf(wp, {}); });
+ assert_throws_js(w.TypeError, () => { wp.__proto__ = null; });
+ assert_false(Reflect.setPrototypeOf(wp, w.Object.prototype));
+
+ assert_equals(Object.getPrototypeOf(wp), w.EventTarget.prototype);
+}, "[[SetPrototypeOf]] and [[GetPrototypeOf]]");
+
+test(t => {
+ const { wp } = createWindowProperties(t);
+
+ assert_throws_js(TypeError, () => { Object.preventExtensions(wp); });
+ assert_false(Reflect.preventExtensions(wp));
+
+ assert_true(Object.isExtensible(wp));
+}, "[[PreventExtensions]] and [[IsExtensible]]");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+
+ const elA = appendElementWithId(w, "a");
+ const el0 = appendIframeWithName(w, 0);
+
+ assert_prop_desc(Object.getOwnPropertyDescriptor(wp, "a"), elA, supportedNonIndex);
+ assert_prop_desc(Reflect.getOwnPropertyDescriptor(wp, 0), el0, supportedIndex);
+ assert_equals(Reflect.getOwnPropertyDescriptor(wp, "b"), undefined, unsupportedNonIndex);
+ assert_equals(Object.getOwnPropertyDescriptor(wp, 1), undefined, unsupportedIndex);
+}, "[[GetOwnProperty]]");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+
+ appendIframeWithName(w, "hasOwnProperty");
+ appendFormWithName(w, "addEventListener");
+ appendElementWithId(w, "a");
+ appendIframeWithName(w, 0);
+
+ w.Object.prototype.a = {};
+ w.EventTarget.prototype[0] = {};
+
+ // These are shadowed by properties higher in [[Prototype]] chain. See https://heycam.github.io/webidl/#dfn-named-property-visibility
+ assert_equals(Object.getOwnPropertyDescriptor(wp, "hasOwnProperty"), undefined, supportedNonIndex);
+ assert_equals(Reflect.getOwnPropertyDescriptor(wp, "addEventListener"), undefined, supportedNonIndex);
+ assert_equals(Object.getOwnPropertyDescriptor(wp, "a"), undefined, supportedNonIndex);
+ assert_equals(Reflect.getOwnPropertyDescriptor(wp, 0), undefined, supportedIndex);
+}, "[[GetOwnProperty]] (named property visibility algorithm)");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+
+ appendElementWithId(w, "a");
+ appendFormWithName(w, 0);
+
+ assert_define_own_property_fails(wp, "a", {}, supportedNonIndex);
+ assert_define_own_property_fails(wp, 0, {}, supportedIndex);
+ assert_define_own_property_fails(wp, "b", {}, unsupportedNonIndex);
+ assert_define_own_property_fails(wp, 1, {}, unsupportedIndex);
+ assert_define_own_property_fails(wp, Symbol.toStringTag, {}, existingSymbol);
+ assert_define_own_property_fails(wp, Symbol(), {}, nonExistingSymbol);
+}, "[[DefineOwnProperty]]");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+
+ appendFormWithName(w, "a");
+ appendElementWithId(w, 0);
+
+ assert_true("a" in wp, supportedNonIndex);
+ assert_true(Reflect.has(wp, "a"), supportedNonIndex);
+ assert_true(0 in wp, supportedIndex);
+ assert_true(Reflect.has(wp, 0), supportedIndex);
+
+ assert_false("b" in wp, unsupportedNonIndex);
+ assert_false(Reflect.has(wp, 1), unsupportedIndex);
+}, "[[HasProperty]]");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+ const elA = appendFormWithName(w, "a");
+ const el0 = appendIframeWithName(w, 0);
+
+ assert_equals(wp.a, elA, supportedNonIndex);
+ assert_equals(wp[0], el0, supportedIndex);
+ assert_equals(wp[Symbol.toStringTag], "WindowProperties", existingSymbol);
+
+ assert_equals(wp.b, undefined, unsupportedNonIndex);
+ assert_equals(wp[1], undefined, unsupportedIndex);
+ assert_equals(wp[Symbol.iterator], undefined, nonExistingSymbol);
+}, "[[Get]]");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+
+ appendIframeWithName(w, "isPrototypeOf");
+ appendFormWithName(w, "dispatchEvent");
+ appendElementWithId(w, "a");
+ appendElementWithId(w, 0);
+
+ w.EventTarget.prototype.a = 10;
+ w.Object.prototype[0] = 20;
+
+ // These are shadowed by properties higher in [[Prototype]] chain. See https://heycam.github.io/webidl/#dfn-named-property-visibility
+ assert_equals(wp.isPrototypeOf, w.Object.prototype.isPrototypeOf, supportedNonIndex);
+ assert_equals(wp.dispatchEvent, w.EventTarget.prototype.dispatchEvent, supportedNonIndex);
+ assert_equals(wp.a, 10, supportedNonIndex);
+ assert_equals(wp[0], 20, supportedIndex);
+}, "[[Get]] (named property visibility algorithm)");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+ const elA = appendIframeWithName(w, "a");
+ const el0 = appendFormWithName(w, 0);
+
+ assert_set_fails(wp, "a", supportedNonIndex);
+ assert_set_fails(wp, "b", unsupportedNonIndex);
+ assert_set_fails(wp, 0, supportedIndex);
+ assert_set_fails(wp, 1, unsupportedIndex);
+ assert_set_fails(wp, Symbol.toStringTag, existingSymbol);
+ assert_set_fails(wp, Symbol(), nonExistingSymbol);
+
+ assert_equals(wp.a, elA, supportedNonIndex);
+ assert_equals(wp[0], el0, supportedIndex);
+ assert_equals(wp.b, undefined, unsupportedNonIndex);
+ assert_equals(wp[1], undefined, unsupportedIndex);
+}, "[[Set]] (direct)");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+ const receiver = Object.create(wp);
+
+ appendIframeWithName(w, "a");
+ appendElementWithId(w, 0);
+
+ let setterThisValue;
+ Object.defineProperty(w.Object.prototype, 1, { set() { setterThisValue = this; } });
+ Object.defineProperty(w.EventTarget.prototype, "b", { writable: false });
+
+ receiver.a = 10;
+ assert_throws_js(TypeError, () => { receiver.b = {}; }, unsupportedNonIndex);
+ receiver[0] = 20;
+ receiver[1] = {};
+
+ assert_equals(receiver.a, 10, supportedNonIndex);
+ assert_equals(receiver[0], 20, supportedIndex);
+ assert_false(receiver.hasOwnProperty("b"), unsupportedNonIndex);
+ assert_false(receiver.hasOwnProperty(1), unsupportedIndex);
+ assert_equals(setterThisValue, receiver, "setter |this| value is receiver");
+}, "[[Set]] (prototype chain)");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+ const receiver = {};
+
+ appendFormWithName(w, "a");
+ appendIframeWithName(w, 0);
+
+ let setterThisValue;
+ Object.defineProperty(w.Object.prototype, "b", { set() { setterThisValue = this; } });
+ Object.defineProperty(w.EventTarget.prototype, 1, { writable: false });
+
+ assert_true(Reflect.set(wp, "a", 10, receiver), supportedNonIndex);
+ assert_true(Reflect.set(wp, 0, 20, receiver), supportedIndex);
+ assert_true(Reflect.set(wp, "b", {}, receiver), unsupportedNonIndex);
+ assert_false(Reflect.set(wp, 1, {}, receiver), unsupportedIndex);
+
+ assert_equals(receiver.a, 10, supportedNonIndex);
+ assert_equals(receiver[0], 20, supportedIndex);
+ assert_false(receiver.hasOwnProperty("b"), unsupportedNonIndex);
+ assert_equals(setterThisValue, receiver, "setter |this| value is receiver");
+ assert_false(receiver.hasOwnProperty(1), unsupportedIndex);
+}, "[[Set]] (Reflect.set)");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+ const elA = appendFormWithName(w, "a");
+ const el0 = appendElementWithId(w, 0);
+
+ assert_delete_fails(wp, "a", supportedNonIndex);
+ assert_delete_fails(wp, 0, supportedIndex);
+ assert_delete_fails(wp, "b", unsupportedNonIndex);
+ assert_delete_fails(wp, 1, unsupportedIndex);
+ assert_delete_fails(wp, Symbol.toStringTag, existingSymbol);
+ assert_delete_fails(wp, Symbol("foo"), nonExistingSymbol);
+
+ assert_equals(wp.a, elA, supportedNonIndex);
+ assert_equals(wp[0], el0, supportedIndex);
+ assert_equals(wp[Symbol.toStringTag], "WindowProperties", existingSymbol);
+}, "[[Delete]]");
+
+test(t => {
+ const { w, wp } = createWindowProperties(t);
+
+ appendIframeWithName(w, "a");
+ appendElementWithId(w, 0);
+ appendFormWithName(w, "b");
+
+ const forInKeys = [];
+ for (const key in wp)
+ forInKeys.push(key);
+
+ assert_array_equals(forInKeys, Object.keys(w.EventTarget.prototype));
+ assert_array_equals(Object.getOwnPropertyNames(wp), []);
+ assert_array_equals(Reflect.ownKeys(wp), [Symbol.toStringTag]);
+}, "[[OwnPropertyKeys]]");
+
+function createWindowProperties(t) {
+ const iframe = document.createElement("iframe");
+ document.body.append(iframe);
+ t.add_cleanup(() => { iframe.remove(); });
+
+ const w = iframe.contentWindow;
+ const wp = Object.getPrototypeOf(w.Window.prototype);
+ return { w, wp };
+}
+
+function appendIframeWithName(w, name) {
+ const el = w.document.createElement("iframe");
+ el.name = name;
+ w.document.body.append(el);
+ return el.contentWindow;
+}
+
+function appendFormWithName(w, name) {
+ const el = w.document.createElement("form");
+ el.name = name;
+ w.document.body.append(el);
+ return el;
+}
+
+function appendElementWithId(w, id) {
+ const el = w.document.createElement("div");
+ el.id = id;
+ w.document.body.append(el);
+ return el;
+}
+
+function assert_prop_desc(desc, value, testInfo) {
+ assert_equals(typeof desc, "object", `${testInfo} typeof desc`);
+ assert_equals(desc.value, value, `${testInfo} [[Value]]`);
+ assert_true(desc.writable, `${testInfo} [[Writable]]`);
+ assert_false(desc.enumerable, `${testInfo} [[Enumerable]]`);
+ assert_true(desc.configurable, `${testInfo} [[Configurable]]`);
+}
+
+function assert_define_own_property_fails(object, key, desc, testInfo) {
+ assert_throws_js(TypeError, () => { Object.defineProperty(object, key, desc); }, testInfo);
+ assert_false(Reflect.defineProperty(object, key, desc), testInfo);
+}
+
+function assert_set_fails(object, key, value, testInfo) {
+ sloppyModeSet(object, key, value);
+ assert_throws_js(TypeError, () => { object[key] = value; }, testInfo);
+ assert_false(Reflect.set(object, key, value), testInfo);
+}
+
+function assert_delete_fails(object, key, testInfo) {
+ assert_throws_js(TypeError, () => { delete object[key]; }, testInfo);
+ assert_false(Reflect.deleteProperty(object, key), testInfo);
+}
+</script>
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html (277828 => 277829)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html 2021-05-20 22:14:40 UTC (rev 277829)
@@ -232,7 +232,10 @@
}
for (var prop of windowAllowlists.namedFrames) {
win[prop]; // Shouldn't throw.
- Object.getOwnPropertyDescriptor(win, prop); // Shouldn't throw.
+ var desc = Object.getOwnPropertyDescriptor(win, prop);
+ assert_false(desc.writable, "[[Writable]] for named frame " + String(prop));
+ assert_false(desc.enumerable, "[[Enumerable]] for named frame " + String(prop));
+ assert_true(desc.configurable, "[[Configurable]] for named frame " + String(prop));
assert_true(Object.prototype.hasOwnProperty.call(win, prop), "hasOwnProperty for " + String(prop));
}
for (var prop in location) {
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties-expected.txt (277828 => 277829)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties-expected.txt 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties-expected.txt 2021-05-20 22:14:40 UTC (rev 277829)
@@ -1,9 +1,9 @@
PASS Static name
PASS Static id
-FAIL Static name on the prototype assert_equals: expected true but got false
+PASS Static name on the prototype
PASS constructor
-FAIL duplicate property names assert_equals: expected 1 but got 0
+PASS duplicate property names
PASS Dynamic name
PASS Ghost name
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html (277828 => 277829)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html 2021-05-20 22:14:40 UTC (rev 277829)
@@ -60,9 +60,7 @@
}, "constructor");
test(function() {
var gsp = Object.getPrototypeOf(Object.getPrototypeOf(window));
- var names = Object.getOwnPropertyNames(gsp);
- assert_equals(names.filter((name) => name == "baz").length, 1);
-
+ assert_equals(gsp.baz, document.getElementsByTagName("iframe")[1].contentWindow);
}, "duplicate property names")
var t = async_test("Dynamic name")
var t2 = async_test("Ghost name")
Modified: trunk/Source/WebCore/ChangeLog (277828 => 277829)
--- trunk/Source/WebCore/ChangeLog 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/Source/WebCore/ChangeLog 2021-05-20 22:14:40 UTC (rev 277829)
@@ -1,3 +1,53 @@
+2021-05-20 Alexey Shvayka <shvaikal...@gmail.com>
+
+ Align internal methods of WindowProperties object with the spec
+ https://bugs.webkit.org/show_bug.cgi?id=222918
+
+ Reviewed by Sam Weinig.
+
+ This patch:
+
+ 1. Implements [[PreventExtensions]], [[DefineOwnProperty]], and [[Delete]] methods that always fail [1],
+ ensuring [[Set]] with altered receiver is passed through, indexed properties are rejected as well,
+ and an exception is thrown if neccessary.
+
+ Adding a put() override would a) slow down global `var` creation and b) require factoring out most of
+ JSObject::putInlineSlow(). Instead, we prevent extensions on a structure while defining isExtensible()
+ override to cover that up.
+
+ 2. Corrects property attributes reported by [[GetOwnProperty]] methods of cross-origin WindowProxy [2]
+ and WindowProperties, bringing these objects in compliance with invariants of internal methods [3].
+
+ 3. Removes comments on cross-browser differences and priority order from [[GetOwnProperty]] because
+ it correctly implements the now detailed spec [4]. Browsing contexts precedence is covered by
+ wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html test.
+
+ 4. Asserts that WindowProperties [[Prototype]] is an object, as guaranteed by its [[SetPrototypeOf]].
+
+ This change fully implements the current spec, aligning WebKit with Blink and Gecko.
+
+ [1] https://heycam.github.io/webidl/#named-properties-object-defineownproperty
+ [2] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty (step 6.2)
+ [3] https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods
+ [4] https://html.spec.whatwg.org/multipage/window-object.html#dom-window-nameditem (step 2)
+
+ Tests: imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/window-named-properties-object.html
+ imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
+ imported/w3c/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html
+
+ * bindings/js/JSDOMWindowCustom.cpp:
+ (WebCore::jsDOMWindowGetOwnPropertySlotRestrictedAccess):
+ * bindings/js/JSDOMWindowProperties.cpp:
+ (WebCore::jsDOMWindowPropertiesGetOwnPropertySlotNamedItemGetter):
+ (WebCore::JSDOMWindowProperties::finishCreation):
+ (WebCore::JSDOMWindowProperties::getOwnPropertySlot):
+ (WebCore::JSDOMWindowProperties::deleteProperty):
+ (WebCore::JSDOMWindowProperties::deletePropertyByIndex):
+ (WebCore::JSDOMWindowProperties::preventExtensions):
+ (WebCore::JSDOMWindowProperties::isExtensible):
+ (WebCore::JSDOMWindowProperties::defineOwnProperty):
+ * bindings/js/JSDOMWindowProperties.h:
+
2021-05-20 Chris Dumez <cdu...@apple.com>
WebAudioBufferList::setSampleCount() should early return if computeBufferSizes() fails
Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp (277828 => 277829)
--- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp 2021-05-20 22:14:40 UTC (rev 277829)
@@ -140,7 +140,7 @@
auto* frame = window.frame();
if (frame && is<Frame>(*frame)) {
if (auto* scopedChild = downcast<Frame>(*frame).tree().scopedChild(propertyNameToAtomString(propertyName))) {
- slot.setValue(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, toJS(&lexicalGlobalObject, scopedChild->document()->domWindow()));
+ slot.setValue(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, toJS(&lexicalGlobalObject, scopedChild->document()->domWindow()));
return true;
}
}
Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp (277828 => 277829)
--- trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp 2021-05-20 22:14:40 UTC (rev 277829)
@@ -42,15 +42,12 @@
const ClassInfo JSDOMWindowProperties::s_info = { "WindowProperties", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDOMWindowProperties) };
+// https://html.spec.whatwg.org/multipage/window-object.html#dom-window-nameditem
static bool jsDOMWindowPropertiesGetOwnPropertySlotNamedItemGetter(JSDOMWindowProperties* thisObject, DOMWindow& window, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, PropertySlot& slot)
{
- // Check for child frames by name before built-in properties to match Mozilla. This does
- // not match IE, but some sites end up naming frames things that conflict with window
- // properties that are in Moz but not IE. Since we have some of these, we have to do it
- // the Moz way.
if (auto* frame = window.frame()) {
if (auto* scopedChild = frame->tree().scopedChild(propertyNameToAtomString(propertyName))) {
- slot.setValue(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, toJS(lexicalGlobalObject, scopedChild->document()->domWindow()));
+ slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::DontEnum), toJS(lexicalGlobalObject, scopedChild->document()->domWindow()));
return true;
}
}
@@ -58,9 +55,6 @@
if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, window, ThrowSecurityError))
return false;
- // FIXME: Search the whole frame hierarchy somewhere around here.
- // We need to test the correct priority order.
-
// Allow shortcuts like 'Image1' instead of document.images.Image1
auto* document = window.document();
if (is<HTMLDocument>(document)) {
@@ -74,7 +68,7 @@
namedItem = toJS(lexicalGlobalObject, thisObject->globalObject(), collection);
} else
namedItem = toJS(lexicalGlobalObject, thisObject->globalObject(), htmlDocument.windowNamedItem(*atomicPropertyName));
- slot.setValue(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, namedItem);
+ slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::DontEnum), namedItem);
return true;
}
}
@@ -82,25 +76,27 @@
return false;
}
-void JSDOMWindowProperties::finishCreation(VM& vm)
+void JSDOMWindowProperties::finishCreation(JSGlobalObject& globalObject)
{
+ VM& vm = globalObject.vm();
Base::finishCreation(vm);
ASSERT(inherits(vm, info()));
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+ JSObject::preventExtensions(this, &globalObject);
}
bool JSDOMWindowProperties::getOwnPropertySlot(JSObject* object, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, PropertySlot& slot)
{
+ VM& vm = lexicalGlobalObject->vm();
auto* thisObject = jsCast<JSDOMWindowProperties*>(object);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
if (Base::getOwnPropertySlot(thisObject, lexicalGlobalObject, propertyName, slot))
return true;
- JSValue proto = thisObject->getPrototypeDirect(lexicalGlobalObject->vm());
- if (proto.isObject() && jsCast<JSObject*>(proto)->hasProperty(lexicalGlobalObject, propertyName))
+ JSObject* proto = asObject(thisObject->getPrototypeDirect(vm));
+ if (proto->hasProperty(lexicalGlobalObject, propertyName))
return false;
- auto& vm = lexicalGlobalObject->vm();
-
// FIXME: We should probably add support for JSRemoteDOMWindowBase too.
auto* jsWindow = jsDynamicCast<JSDOMWindowBase*>(vm, thisObject->globalObject());
if (!jsWindow)
@@ -116,6 +112,32 @@
return getOwnPropertySlot(object, lexicalGlobalObject, Identifier::from(vm, index), slot);
}
+bool JSDOMWindowProperties::deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&)
+{
+ return false;
+}
+
+bool JSDOMWindowProperties::deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned)
+{
+ return false;
+}
+
+bool JSDOMWindowProperties::preventExtensions(JSObject*, JSGlobalObject*)
+{
+ return false;
+}
+
+bool JSDOMWindowProperties::isExtensible(JSObject*, JSGlobalObject*)
+{
+ return true;
+}
+
+bool JSDOMWindowProperties::defineOwnProperty(JSObject*, JSGlobalObject* lexicalGlobalObject, PropertyName, const PropertyDescriptor&, bool shouldThrow)
+{
+ auto scope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
+ return typeError(lexicalGlobalObject, scope, shouldThrow, "Defining a property on a WindowProperties object is not allowed."_s);
+}
+
JSC::IsoSubspace* JSDOMWindowProperties::subspaceForImpl(JSC::VM& vm)
{
return &static_cast<JSVMClientData*>(vm.clientData)->domWindowPropertiesSpace();
Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.h (277828 => 277829)
--- trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.h 2021-05-20 22:10:27 UTC (rev 277828)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.h 2021-05-20 22:14:40 UTC (rev 277829)
@@ -46,7 +46,7 @@
static JSDOMWindowProperties* create(JSC::Structure* structure, JSC::JSGlobalObject& globalObject)
{
JSDOMWindowProperties* ptr = new (NotNull, JSC::allocateCell<JSDOMWindowProperties>(globalObject.vm().heap)) JSDOMWindowProperties(structure, globalObject);
- ptr->finishCreation(globalObject.vm());
+ ptr->finishCreation(globalObject);
return ptr;
}
@@ -59,6 +59,11 @@
static bool getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&);
static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::JSGlobalObject*, unsigned propertyName, JSC::PropertySlot&);
+ static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&);
+ static bool deletePropertyByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned propertyName);
+ static bool preventExtensions(JSC::JSObject*, JSC::JSGlobalObject*);
+ static bool isExtensible(JSC::JSObject*, JSC::JSGlobalObject*);
+ static bool defineOwnProperty(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);
private:
JSDOMWindowProperties(JSC::Structure* structure, JSC::JSGlobalObject& globalObject)
@@ -66,7 +71,7 @@
{
}
- void finishCreation(JSC::VM&);
+ void finishCreation(JSC::JSGlobalObject&);
static JSC::IsoSubspace* subspaceForImpl(JSC::VM&);
};
_______________________________________________ webkit-changes mailing list webkit-changes@lists.webkit.org https://lists.webkit.org/mailman/listinfo/webkit-changes