fix(window): reject deleting live indexed children

This commit is contained in:
ldm0
2026-11-02 06:01:31 +08:00
parent f8b8c2313e
commit 3354a1a4c0
4 changed files with 55 additions and 3 deletions
@@ -29,9 +29,9 @@ pub(crate) use document::{
pub(crate) use helpers::{current_window_style_viewport, window_host_ptr};
pub(super) use helpers::{window_child_context_handle, window_current_dispatch_scope, window_has_discarded_child_browsing_context};
pub(super) use interceptors::{
window_indexed_property_descriptor, window_indexed_property_enumerator,
window_indexed_property_getter, window_indexed_property_query,
window_named_properties_indexed_property_getter,
window_indexed_property_deleter, window_indexed_property_descriptor,
window_indexed_property_enumerator, window_indexed_property_getter,
window_indexed_property_query, window_named_properties_indexed_property_getter,
window_named_properties_indexed_property_query, window_named_property_getter,
window_named_property_query,
};
@@ -78,6 +78,19 @@ pub(in crate::context_bootstrap) fn window_indexed_property_query<'s>(
v8::Intercepted::kYes
}
pub(in crate::context_bootstrap) fn window_indexed_property_deleter<'s>(
scope: &mut v8::PinScope<'s, '_>,
index: u32,
args: v8::PropertyCallbackArguments<'s>,
mut rv: v8::ReturnValue<'_, v8::Boolean>,
) -> v8::Intercepted {
if window_indexed_child_handle(scope, args.holder(), index).is_none() {
return v8::Intercepted::kNo;
}
rv.set_bool(false);
v8::Intercepted::kYes
}
pub(in crate::context_bootstrap) fn window_indexed_property_enumerator<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::PropertyCallbackArguments<'s>,
@@ -363,6 +363,7 @@ pub(crate) fn install_window_own_template_bindings<'s>(
v8::IndexedPropertyHandlerConfiguration::new()
.getter(window_indexed_property_getter)
.query(window_indexed_property_query)
.deleter(window_indexed_property_deleter)
.enumerator(window_indexed_property_enumerator)
.descriptor(window_indexed_property_descriptor),
);
@@ -4543,3 +4543,41 @@ async fn child_meta_refresh_after_same_document_navigation_uses_child_referrer()
Some(child_url.as_str())
);
}
#[test]
fn main_window_indexed_child_deletion_is_live_and_not_cached() {
let mut vm = new_storage_test_vm("https://window-indexed-delete.test/");
let result = vm
.eval(
r#"
(() => {
const frame = document.createElement('iframe');
frame.srcdoc = '';
let absentDeletesSucceeded = true;
for (let i = 0; i < 1e5; i++) {
absentDeletesSucceeded &&= delete window[0];
}
(document.body || document.documentElement || document).appendChild(frame);
const presentAfterAbsent = delete window[0];
let presentDeletesFailed = true;
for (let i = 0; i < 1e5; i++) {
presentDeletesFailed &&= !delete window[0];
}
frame.remove();
return JSON.stringify({
absentDeletesSucceeded,
presentAfterAbsent,
presentDeletesFailed,
absentAfterPresent: delete window[0]
});
})()
"#,
)
.expect("live Window indexed deletion probe should evaluate");
assert_eq!(
result,
r#"{"absentDeletesSucceeded":true,"presentAfterAbsent":false,"presentDeletesFailed":true,"absentAfterPresent":true}"#
);
}