diff --git a/moli-benchmark/wpt-cross-current/failed-cases.txt b/moli-benchmark/wpt-cross-current/failed-cases.txt index 3849307eaa..58344fe010 100644 --- a/moli-benchmark/wpt-cross-current/failed-cases.txt +++ b/moli-benchmark/wpt-cross-current/failed-cases.txt @@ -2924,7 +2924,6 @@ html/browsers/the-window-object/window-indexed-properties-strict.html html/browsers/the-window-object/window-indexed-properties.html html/browsers/the-window-object/window-open-noopener.html?indexed html/browsers/the-window-object/window-open-noreferrer.html -html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-same-origin.html html/browsers/windows/browsing-context-names/choose-default-001.html html/browsers/windows/browsing-context.html html/browsers/windows/document-domain-removed-iframe.html diff --git a/moli-benchmark/wpt-cross-current/passed-cases.txt b/moli-benchmark/wpt-cross-current/passed-cases.txt index 2e131b70ec..72c5f44883 100644 --- a/moli-benchmark/wpt-cross-current/passed-cases.txt +++ b/moli-benchmark/wpt-cross-current/passed-cases.txt @@ -5248,6 +5248,7 @@ html/browsers/the-window-object/window-open-noopener.html?_top html/browsers/the-window-object/window-prototype-chain.html html/browsers/the-windowproxy-exotic-object/windowproxy-define-own-property-unforgeable-same-origin.html html/browsers/the-windowproxy-exotic-object/windowproxy-prevent-extensions.html +html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-same-origin.html html/browsers/windows/browsing-context-names/choose-_blank-001.html html/browsers/windows/browsing-context-names/choose-default-002.html html/browsers/windows/browsing-context-window.html diff --git a/moli-renderer-v8/src/context_bootstrap/assets/global.rs b/moli-renderer-v8/src/context_bootstrap/assets/global.rs index fa8b63f167..275ed0e684 100644 --- a/moli-renderer-v8/src/context_bootstrap/assets/global.rs +++ b/moli-renderer-v8/src/context_bootstrap/assets/global.rs @@ -42,6 +42,14 @@ impl ContextBootstrapAssets { .id_by_name("Window") .ok_or_else(|| anyhow!("missing constructor template metadata `Window`"))?; let window_template = registry.get_or_build_template(scope, window_id)?; + // WindowProxy's [[SetPrototypeOf]] only succeeds when the requested + // prototype is already its current prototype. Set the invariant on + // Window's instance template before deriving the same- and + // cross-origin global templates so it remains attached to V8's global + // proxy rather than only to the inner global object. + window_template + .instance_template(scope) + .set_immutable_proto(); // A cross-origin WindowProxy shell must retain Window's V8 wrapper // identity so that detaching and reusing it for the committed child // realm discards the facade's temporary own properties. It must not, diff --git a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs index b72d484819..d10c1cd8a1 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs @@ -8827,6 +8827,72 @@ fn window_named_properties_respect_later_prototype_properties_and_descriptor_fla ); } +#[test] +fn main_and_child_window_proxies_have_immutable_prototypes() { + let mut vm = new_storage_test_vm("https://window-proxy-prototype.test/"); + + let result = vm + .eval( + r#" + (() => { + "use strict"; + const frame = document.createElement("iframe"); + (document.body || document.documentElement || document).appendChild(frame); + + const probe = target => { + const original = Object.getPrototypeOf(target); + const replacement = {}; + const outcome = callback => { + try { + callback(); + return "returned"; + } catch (error) { + return error && error.name; + } + }; + + const objectDifferent = outcome(() => { + Object.setPrototypeOf(target, replacement); + }); + const dunderDifferent = outcome(() => { + target.__proto__ = replacement; + }); + const reflectDifferent = Reflect.setPrototypeOf(target, replacement); + const unchanged = Object.getPrototypeOf(target) === original; + const objectSame = Object.setPrototypeOf(target, original) === target; + const dunderSame = outcome(() => { + target.__proto__ = original; + }); + const reflectSame = Reflect.setPrototypeOf(target, original); + + return { + objectDifferent, + dunderDifferent, + reflectDifferent, + unchanged, + objectSame, + dunderSame, + reflectSame, + }; + }; + + const observations = { + main: probe(window), + child: probe(frame.contentWindow), + }; + frame.remove(); + return JSON.stringify(observations); + })() + "#, + ) + .expect("WindowProxy immutable prototype probe should evaluate"); + + assert_eq!( + result, + r#"{"main":{"objectDifferent":"TypeError","dunderDifferent":"TypeError","reflectDifferent":false,"unchanged":true,"objectSame":true,"dunderSame":"returned","reflectSame":true},"child":{"objectDifferent":"TypeError","dunderDifferent":"TypeError","reflectDifferent":false,"unchanged":true,"objectSame":true,"dunderSame":"returned","reflectSame":true}}"# + ); +} + #[test] fn window_internal_child_context_identity_is_not_read_from_web_properties() { let mut vm = new_storage_test_vm("https://window-private-identity.test/");