Changeset 278585 in webkit


Ignore:
Timestamp:
Jun 7, 2021 6:10:23 PM (14 months ago)
Author:
Alexey Shvayka
Message:

Window should behave like a legacy platform object without indexed setter
https://bugs.webkit.org/show_bug.cgi?id=225894

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

  • 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:

Source/JavaScriptCore:

  • runtime/TypeError.h:

(JSC::typeError):

Source/WebCore:

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:

LayoutTests:

  • 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:
Location:
trunk
Files:
2 added
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r278575 r278585  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Window should behave like a legacy platform object without indexed setter
     4        https://bugs.webkit.org/show_bug.cgi?id=225894
     5
     6        Reviewed by Darin Adler.
     7
     8        * fast/dom/Window/orphaned-frame-access.html:
     9        * fast/frames/iframe-detached-window-still-writable-eval-expected.txt:
     10        * fast/frames/iframe-detached-window-still-writable-eval.html:
     11        * http/tests/security/cross-frame-access-delete-expected.txt:
     12        * http/tests/security/resources/cross-frame-iframe-for-delete-test.html:
     13        * js/dom/dfg-ensure-array-storage-on-window-expected.txt:
     14        * js/dom/indexed-setter-on-global-object-expected.txt:
     15        * js/dom/script-tests/dfg-ensure-array-storage-on-window.js:
     16        * js/dom/script-tests/dfg-ensure-non-array-array-storage-on-window.js:
     17        * js/dom/script-tests/indexed-setter-on-global-object.js:
     18
    1192021-06-07  Wenson Hsieh  <wenson_hsieh@apple.com>
    220
  • trunk/LayoutTests/fast/dom/Window/orphaned-frame-access.html

    r226676 r278585  
    1818    setTimeout(function() {
    1919        document.body.appendChild(document.createTextNode(win.test || 'property: FAIL ... '));
    20         document.body.appendChild(document.createTextNode(win[20] || 'array: FAIL ... '));
     20        document.body.appendChild(document.createTextNode(win[20] === undefined ? 'array: PASS ... ' : 'array: FAIL ... '));
    2121        document.body.appendChild(document.createTextNode(win.Comment ? 'constructor: PASS .... ' : 'constructor: FAIL ... '));
    2222        document.body.appendChild(document.createTextNode(win.postMessage ? 'operation: PASS.' : 'operation: FAIL.'));
  • trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval-expected.txt

    r273901 r278585  
    55
    66PASS () => foo is 2
    7 PASS () => globalThis[0] is 2
     7PASS () => globalThis[0] is undefined
    88PASS iframeContentWindow.foo is 2
    9 PASS iframeContentWindow[0] is 2
     9PASS iframeContentWindow[0] is undefined
    1010PASS successfullyParsed is true
    1111
  • trunk/LayoutTests/fast/frames/iframe-detached-window-still-writable-eval.html

    r273901 r278585  
    1616        globalThis[0]++;
    1717        shouldBe(() => foo, "2");
    18         shouldBe(() => globalThis[0], "2");
     18        shouldBe(() => globalThis[0], "undefined");
    1919    `);
    2020    shouldBe("iframeContentWindow.foo", "2");
    21     shouldBe("iframeContentWindow[0]", "2");
     21    shouldBe("iframeContentWindow[0]", "undefined");
    2222</script>
    2323</body>
  • trunk/LayoutTests/http/tests/security/cross-frame-access-delete-expected.txt

    r231450 r278585  
    2323
    2424PASS: window.existingProperty should be 'test value' and is.
    25 PASS: window[1] should be 'test value' and is.
     25PASS: window[1] should be 'undefined' and is.
    2626PASS: window.history.existingProperty should be 'test value' and is.
    2727PASS: window.history[1] should be 'test value' and is.
  • trunk/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-delete-test.html

    r205200 r278585  
    2727
    2828            shouldBe("window.existingProperty", "'test value'");
    29             shouldBe("window[1]", "'test value'");
     29            shouldBe("window[1]", "undefined");
    3030            shouldBe("window.history.existingProperty", "'test value'");
    3131            shouldBe("window.history[1]", "'test value'");
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r278562 r278585  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Window should behave like a legacy platform object without indexed setter
     4        https://bugs.webkit.org/show_bug.cgi?id=225894
     5
     6        Reviewed by Darin Adler.
     7
     8        * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache-expected.txt: Added.
     9        * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache.html: Added.
     10        * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-expected.txt:
     11        * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict-expected.txt:
     12        * web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html:
     13        * web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html:
     14
    1152021-06-07  Imanol Fernandez  <ifernandez@igalia.com>
    216
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-expected.txt

    r267646 r278585  
    22PASS Indexed properties of the window object (non-strict mode)
    33PASS Ensure indexed properties have the correct configuration
    4 FAIL Indexed properties of the window object (non-strict mode) 1 assert_throws_js: function "() => Object.defineProperty(window, 0, { value: "bar" })" did not throw
    5 FAIL Indexed properties of the window object (non-strict mode) 2 assert_throws_js: function "() => Object.defineProperty(window, 1, { value: "bar" })" did not throw
     4PASS Indexed properties of the window object (non-strict mode) 1
     5PASS Indexed properties of the window object (non-strict mode) 2
     6PASS Borderline numeric key: 2 ** 32 - 2 is an index
     7PASS Borderline numeric key: 2 ** 32 - 1 is not an index
    68PASS Indexed properties of the window object (non-strict mode) 3
    79
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict-expected.txt

    r267646 r278585  
    11
    22PASS Indexed properties of the window object (strict mode)
    3 FAIL Indexed properties of the window object (strict mode) 1 assert_throws_js: function "function () {
    4     window[0] = "foo";
    5   }" did not throw
    6 FAIL Indexed properties of the window object (strict mode) 2 assert_throws_js: function "function () {
    7     window[1] = "foo";
    8   }" did not throw
     3PASS Indexed properties of the window object (strict mode) 1
     4PASS Indexed properties of the window object (strict mode) 2
     5PASS Borderline numeric key: 2 ** 32 - 2 is an index (strict mode)
     6PASS Borderline numeric key: 2 ** 32 - 1 is not an index (strict mode)
    97PASS Indexed properties of the window object (strict mode) 3
    108
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html

    r263856 r278585  
    4545test(function() {
    4646  "use strict";
     47  assert_throws_js(TypeError, () => { window[4294967294] = 1; });
     48  assert_false(Reflect.set(window, 4294967294, 2));
     49  assert_false(Reflect.defineProperty(window, 4294967294, { value: 3 }));
     50  assert_throws_js(TypeError, () => Object.defineProperty(window, 4294967294, { get: () => 4 }));
     51  assert_equals(window[4294967294], undefined);
     52  assert_false(4294967294 in window);
     53  assert_true(delete window[4294967294]);
     54}, "Borderline numeric key: 2 ** 32 - 2 is an index (strict mode)");
     55test(function() {
     56  "use strict";
     57  window[4294967295] = 1;
     58  assert_equals(window[4294967295], 1);
     59  assert_true(Reflect.set(window, 4294967295, 2));
     60  assert_equals(window[4294967295], 2);
     61  assert_true(Reflect.defineProperty(window, 4294967295, { value: 3 }));
     62  assert_equals(window[4294967295], 3);
     63  Object.defineProperty(window, 4294967295, { get: () => 4 });
     64  assert_equals(window[4294967295], 4);
     65  assert_true(delete window[4294967295]);
     66  assert_false(4294967295 in window);
     67}, "Borderline numeric key: 2 ** 32 - 1 is not an index (strict mode)");
     68test(function() {
     69  "use strict";
    4770  var proto = Window.prototype;
    4871  [-1, 0, 1].forEach(function(idx) {
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html

    r263856 r278585  
    4343});
    4444test(function() {
     45  window[4294967294] = 1;
     46  assert_false(Reflect.set(window, 4294967294, 2));
     47  assert_false(Reflect.defineProperty(window, 4294967294, { value: 3 }));
     48  assert_throws_js(TypeError, () => Object.defineProperty(window, 4294967294, { get: () => 4 }));
     49  assert_equals(window[4294967294], undefined);
     50  assert_false(4294967294 in window);
     51  assert_true(delete window[4294967294]);
     52}, "Borderline numeric key: 2 ** 32 - 2 is an index");
     53test(function() {
     54  window[4294967295] = 1;
     55  assert_equals(window[4294967295], 1);
     56  assert_true(Reflect.set(window, 4294967295, 2));
     57  assert_equals(window[4294967295], 2);
     58  assert_true(Reflect.defineProperty(window, 4294967295, { value: 3 }));
     59  assert_equals(window[4294967295], 3);
     60  Object.defineProperty(window, 4294967295, { get: () => 4 });
     61  assert_equals(window[4294967295], 4);
     62  assert_true(delete window[4294967295]);
     63  assert_false(4294967295 in window);
     64}, "Borderline numeric key: 2 ** 32 - 1 is not an index");
     65test(function() {
    4566  var proto = Window.prototype;
    4667  [-1, 0, 1].forEach(function(idx) {
  • trunk/LayoutTests/js/dom/dfg-ensure-array-storage-on-window-expected.txt

    r156066 r278585  
    44
    55
    6 PASS foo(w) is 1
     6PASS foo(w) is NaN
    77PASS successfullyParsed is true
    88
  • trunk/LayoutTests/js/dom/indexed-setter-on-global-object-expected.txt

    r156066 r278585  
    44
    55
    6 PASS thingy is "foo"
     6PASS this.__defineSetter__(42, function() {}) threw exception TypeError: Failed to set an indexed property on Window: Indexed property setter is not supported..
     7PASS this[42] is undefined
    78PASS successfullyParsed is true
    89
  • trunk/LayoutTests/js/dom/script-tests/dfg-ensure-array-storage-on-window.js

    r156066 r278585  
    2424w[0] = 1;
    2525w.length = 1;
    26 shouldBe("foo(w)", "1");
     26shouldBe("foo(w)", "NaN");
  • trunk/LayoutTests/js/dom/script-tests/dfg-ensure-non-array-array-storage-on-window.js

    r156066 r278585  
    5252w[0] = 1;
    5353w.length = 1;
    54 var thingy = false;
    55 w.__defineSetter__(1, function(value) { thingy = value; });
    56 shouldBe("foo(w)", "1");
    57 shouldBe("thingy", "false");
     54shouldThrowErrorName("w.__defineSetter__(1, function() {})", "TypeError");
     55shouldBe("foo(w)", "NaN");
    5856
    5957// At this point we check to make sure that bar doesn't end up either creating array storage for
     
    6361bar(w);
    6462
    65 shouldBe("thingy", "42");
    66 shouldBe("foo(w)", "1");
    6763w.length = 2;
    68 shouldBe("foo(w)", "0/0");
     64shouldBe("w[1]", "");
     65shouldBe("foo(w)", "NaN");
    6966
  • trunk/LayoutTests/js/dom/script-tests/indexed-setter-on-global-object.js

    r156066 r278585  
    33);
    44
    5 var thingy;
    6 
    7 this.__defineSetter__(42, function(value) {
    8     thingy = value;
    9 });
     5shouldThrowErrorName("this.__defineSetter__(42, function() {})", "TypeError");
    106
    117this[42] = "foo";
    128
    13 shouldBe("thingy", "\"foo\"");
     9shouldBe("this[42]", "undefined");
    1410
  • trunk/Source/JavaScriptCore/ChangeLog

    r278578 r278585  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Window should behave like a legacy platform object without indexed setter
     4        https://bugs.webkit.org/show_bug.cgi?id=225894
     5
     6        Reviewed by Darin Adler.
     7
     8        * runtime/TypeError.h:
     9        (JSC::typeError):
     10
    1112021-06-07  Saam Barati  <sbarati@apple.com>
    212
  • trunk/Source/JavaScriptCore/runtime/TypeError.h

    r251425 r278585  
    3131namespace JSC {
    3232
    33 inline bool typeError(JSGlobalObject* globalObject, ThrowScope& scope, bool throwException, ASCIILiteral message)
     33template<typename Message>
     34inline bool typeError(JSGlobalObject* globalObject, ThrowScope& scope, bool throwException, Message message)
    3435{
    3536    if (throwException)
  • trunk/Source/WebCore/ChangeLog

    r278580 r278585  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Window should behave like a legacy platform object without indexed setter
     4        https://bugs.webkit.org/show_bug.cgi?id=225894
     5
     6        Reviewed by Darin Adler.
     7
     8        This change fixes major interop issue by disallowing expando indexed properties on WindowProxy,
     9        raising TypeError only when needed, which aligns WebKit with Blink and Gecko.
     10
     11        While [[DefineOwnProperty]] [1] and [[Delete]] [2] methods of WindowProxy are implemented
     12        precisely per spec, current [[Set]] [3] algorithm seems to allow invoking setters from
     13        the prototype chain. Blink and Gecko implement stricter semantics by failing early rather
     14        than traversing the prototype chain, as does this patch.
     15
     16        To avoid breaking native apps that either add expando indexed properties to WindowProxy, or
     17        more likely read / write indices of sloppy function's |this| value, which accidently happens
     18        to be a WindowProxy, the new behavior is introduced only for web content and newly-built apps.
     19
     20        Since unlike putByIndex(), deletePropertyByIndex() might be invoked with UINT_MAX, which is
     21        not an array index [4], isIndex() check is required. In future, JSC will be fixed to remove
     22        such checks from all indexed overrides.
     23
     24        DeletePropertySlot::disableCaching() is not called because indexed deletes are not currently
     25        repatched, and once they are, cacheability should be inferred from added type info flags.
     26
     27        Also, removes extra jsDOMWindowGetOwnPropertySlotRestrictedAccess() call for indices, which
     28        is missing from the spec [5]; this is unobservable.
     29
     30        [1] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-defineownproperty (step 2.1)
     31        [2] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete (step 2.1)
     32        [3] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set (step 3)
     33        [4] https://tc39.es/ecma262/#array-index
     34        [5] https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty (step 2.5.2)
     35
     36        Tests: imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-delete-no-cache.html
     37               imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties.html
     38               imported/w3c/web-platform-tests/html/browsers/the-window-object/window-indexed-properties-strict.html
     39
     40        * bindings/js/JSDOMExceptionHandling.cpp:
     41        (WebCore::makeUnsupportedIndexedSetterErrorMessage):
     42        * bindings/js/JSDOMExceptionHandling.h:
     43        * bindings/js/JSDOMWindowCustom.cpp:
     44        (WebCore::allowsLegacyExpandoIndexedProperties):
     45        (WebCore::JSDOMWindow::getOwnPropertySlotByIndex): Remove outdated comments.
     46        (WebCore::JSDOMWindow::put):
     47        (WebCore::JSDOMWindow::putByIndex): Release scope when calling Base::putByIndex(), which could throw.
     48        (WebCore::JSDOMWindow::deleteProperty):
     49        (WebCore::JSDOMWindow::deletePropertyByIndex):
     50        (WebCore::JSDOMWindow::defineOwnProperty):
     51        * platform/cocoa/VersionChecks.h:
     52
    1532021-06-07  Chris Dumez  <cdumez@apple.com>
    254
  • trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp

    r276719 r278585  
    281281}
    282282
     283String makeUnsupportedIndexedSetterErrorMessage(const char* interfaceName)
     284{
     285    return makeString("Failed to set an indexed property on ", interfaceName, ": Indexed property setter is not supported.");
     286}
     287
    283288EncodedJSValue throwThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName, const char* functionName)
    284289{
  • trunk/Source/WebCore/bindings/js/JSDOMExceptionHandling.h

    r274832 r278585  
    5656
    5757String makeThisTypeErrorMessage(const char* interfaceName, const char* attributeName);
     58String makeUnsupportedIndexedSetterErrorMessage(const char* interfaceName);
    5859
    5960WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::JSGlobalObject&, JSC::ThrowScope&, const char* interfaceName, const char* functionName);
  • trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp

    r278253 r278585  
    6060#endif
    6161
     62#if PLATFORM(COCOA)
     63#include "VersionChecks.h"
     64#endif
     65
    6266namespace WebCore {
    6367using namespace JSC;
     
    9195}
    9296#endif
     97
     98static ALWAYS_INLINE bool allowsLegacyExpandoIndexedProperties()
     99{
     100#if PLATFORM(COCOA)
     101    // Given that WindowProxy is the default |this| value for sloppy mode functions, it's hard to prove
     102    // that older iOS and macOS apps don't accidentally depend on this behavior, so we keep it for them.
     103    static bool requiresQuirk = !linkedOnOrAfter(SDKVersion::FirstWithoutExpandoIndexedPropertiesOnWindow);
     104    return requiresQuirk;
     105#else
     106    return false;
     107#endif
     108}
    93109
    94110template <DOMWindowType windowType>
     
    219235}
    220236
    221 // Property access sequence is:
    222 // (1) indexed properties,
    223 // (2) regular own properties,
    224 // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
    225237bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, JSGlobalObject* lexicalGlobalObject, unsigned index, PropertySlot& slot)
    226238{
    227     VM& vm = lexicalGlobalObject->vm();
    228239    auto* thisObject = jsCast<JSDOMWindow*>(object);
    229240    auto& window = thisObject->wrapped();
     
    233244    slot.disableCaching();
    234245
    235     // (1) First, indexed properties.
    236246    // These are also allowed cross-origin, so come before the access check.
    237247    if (frame && index < frame->tree().scopedChildCount()) {
     
    240250    }
    241251
    242     // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
    243     String errorMessage;
    244     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*lexicalGlobalObject, window, errorMessage))
    245         return jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Local>(thisObject, window, *lexicalGlobalObject, Identifier::from(vm, index), slot, errorMessage);
    246 
    247     // (2) Regular own properties.
    248     return Base::getOwnPropertySlotByIndex(thisObject, lexicalGlobalObject, index, slot);
     252    if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, window, ThrowSecurityError))
     253        return false;
     254    if (allowsLegacyExpandoIndexedProperties())
     255        return Base::getOwnPropertySlotByIndex(thisObject, lexicalGlobalObject, index, slot);
     256    return false;
    249257}
    250258
     
    286294    }
    287295
     296    if (parseIndex(propertyName) && !allowsLegacyExpandoIndexedProperties())
     297        return typeError(lexicalGlobalObject, scope, slot.isStrictMode(), makeUnsupportedIndexedSetterErrorMessage("Window"));
    288298    RELEASE_AND_RETURN(scope, Base::put(thisObject, lexicalGlobalObject, propertyName, value, slot));
    289299}
     
    301311    }
    302312   
    303     return Base::putByIndex(thisObject, lexicalGlobalObject, index, value, shouldThrow);
     313    if (allowsLegacyExpandoIndexedProperties()) {
     314        if (auto* document = thisObject->wrapped().document())
     315            document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, "Adding expando indexed properties to 'window' was a non-standard behavior that is now removed."_s);
     316        RELEASE_AND_RETURN(scope, Base::putByIndex(thisObject, lexicalGlobalObject, index, value, shouldThrow));
     317    }
     318    return typeError(lexicalGlobalObject, scope, shouldThrow, makeUnsupportedIndexedSetterErrorMessage("Window"));
    304319}
    305320
     
    310325    if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
    311326        return false;
     327    if (std::optional<uint32_t> index = parseIndex(propertyName)) {
     328        if (!allowsLegacyExpandoIndexedProperties())
     329            return index.value() >= thisObject->wrapped().length();
     330    }
    312331    return Base::deleteProperty(thisObject, lexicalGlobalObject, propertyName, slot);
    313332}
     
    319338    if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
    320339        return false;
     340    if (isIndex(propertyName) && !allowsLegacyExpandoIndexedProperties())
     341        return propertyName >= thisObject->wrapped().length();
    321342    return Base::deletePropertyByIndex(thisObject, lexicalGlobalObject, propertyName);
    322343}
     
    410431bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::JSGlobalObject* lexicalGlobalObject, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
    411432{
     433    VM& vm = lexicalGlobalObject->vm();
     434    auto scope = DECLARE_THROW_SCOPE(vm);
     435
    412436    JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
    413437    // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
    414438    if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
    415439        return false;
    416 
    417     auto& builtinNames = static_cast<JSVMClientData*>(lexicalGlobalObject->vm().clientData)->builtinNames();
     440    if (parseIndex(propertyName) && !allowsLegacyExpandoIndexedProperties())
     441        return typeError(lexicalGlobalObject, scope, shouldThrow, makeUnsupportedIndexedSetterErrorMessage("Window"));
     442    scope.release();
     443
     444    auto& builtinNames = static_cast<JSVMClientData*>(vm.clientData)->builtinNames();
    418445    if (propertyName == builtinNames.documentPublicName() || propertyName == builtinNames.windowPublicName())
    419446        return JSObject::defineOwnProperty(thisObject, lexicalGlobalObject, propertyName, descriptor, shouldThrow);
  • trunk/Source/WebCore/platform/cocoa/VersionChecks.h

    r276164 r278585  
    7474    FirstWithBlankViewOnJSPrompt = DYLD_IOS_VERSION_14_5,
    7575    FirstWithApplicationCacheDisabledByDefault = DYLD_IOS_VERSION_15_0,
     76    FirstWithoutExpandoIndexedPropertiesOnWindow = DYLD_IOS_VERSION_15_0,
    7677#elif PLATFORM(MAC)
    7778    FirstWithNetworkCache = DYLD_MACOSX_VERSION_10_11,
     
    9798    FirstWithBlankViewOnJSPrompt = DYLD_MACOSX_VERSION_11_3,
    9899    FirstWithApplicationCacheDisabledByDefault = DYLD_MACOSX_VERSION_12_00,
     100    FirstWithoutExpandoIndexedPropertiesOnWindow = DYLD_MACOSX_VERSION_12_00,
    99101#endif
    100102};
Note: See TracChangeset for help on using the changeset viewer.