aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorbors-servo <servo-ops@mozilla.com>2021-07-09 10:01:38 -0400
committerGitHub <noreply@github.com>2021-07-09 10:01:38 -0400
commit94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38 (patch)
tree307c398278ee7d72b39224e7d48b97d100f83a52 /components/script/dom
parent42d7892d88d8e97ca20aa3557b2f03f739f17b89 (diff)
parent7cda260fcb0b7e1de7457f1b03a2e3b613fc1052 (diff)
downloadservo-94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38.tar.gz
servo-94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38.zip
Auto merge of #28536 - yvt:fix-one-compartment, r=jdm
Create only one compartment for each script thread (agent) Documents in the same [agent][1] can share and exchange JS and DOM objects freely, so putting them in separate compartments would require almost every instance of `Dom` to be capable of handling cross-compartment references. [1]: https://html.spec.whatwg.org/multipage/webappapis.html#integration-with-the-javascript-agent-formalism --- - [x] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) --- - [ ] There are tests for these changes OR - [x] These changes do not require tests because I think there's already a wide test coverage for same-origin-domain JS object passing, albeit this requires Servo to be built with `--debug-mozjs` for the errors to be (reliably) observable
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/interface.rs42
-rw-r--r--components/script/dom/windowproxy.rs12
2 files changed, 47 insertions, 7 deletions
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs
index 1085a137428..82303f800ba 100644
--- a/components/script/dom/bindings/interface.rs
+++ b/components/script/dom/bindings/interface.rs
@@ -16,6 +16,10 @@ use js::glue::UncheckedUnwrapObject;
use js::jsapi::GetWellKnownSymbol;
use js::jsapi::HandleObject as RawHandleObject;
use js::jsapi::{jsid, JSClass, JSClassOps};
+use js::jsapi::{
+ Compartment, CompartmentSpecifier, IsSharableCompartment, IsSystemCompartment,
+ JS_IterateCompartments, JS::CompartmentIterResult,
+};
use js::jsapi::{JSAutoRealm, JSContext, JSFunctionSpec, JSObject, JSFUN_CONSTRUCTOR};
use js::jsapi::{JSPropertySpec, JSString, JSTracer, JS_AtomizeAndPinString};
use js::jsapi::{JS_GetFunctionObject, JS_NewFunction, JS_NewGlobalObject};
@@ -139,6 +143,7 @@ pub unsafe fn create_global_object(
options.creationOptions_.traceGlobal_ = Some(trace);
options.creationOptions_.sharedMemoryAndAtomics_ = false;
options.creationOptions_.streams_ = true;
+ select_compartment(cx, &mut options);
rval.set(JS_NewGlobalObject(
*cx,
@@ -162,6 +167,43 @@ pub unsafe fn create_global_object(
JS_FireOnNewGlobalObject(*cx, rval.handle());
}
+/// Choose the compartment to create a new global object in.
+fn select_compartment(cx: SafeJSContext, options: &mut RealmOptions) {
+ type Data = *mut Compartment;
+ unsafe extern "C" fn callback(
+ _cx: *mut JSContext,
+ data: *mut libc::c_void,
+ compartment: *mut Compartment,
+ ) -> CompartmentIterResult {
+ let data = data as *mut Data;
+
+ if !IsSharableCompartment(compartment) || IsSystemCompartment(compartment) {
+ return CompartmentIterResult::KeepGoing;
+ }
+
+ // Choose any sharable, non-system compartment in this context to allow
+ // same-agent documents to share JS and DOM objects.
+ *data = compartment;
+ CompartmentIterResult::Stop
+ }
+
+ let mut compartment: Data = ptr::null_mut();
+ unsafe {
+ JS_IterateCompartments(
+ *cx,
+ (&mut compartment) as *mut Data as *mut libc::c_void,
+ Some(callback),
+ );
+ }
+
+ if compartment.is_null() {
+ options.creationOptions_.compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
+ } else {
+ options.creationOptions_.compSpec_ = CompartmentSpecifier::ExistingCompartment;
+ options.creationOptions_.__bindgen_anon_1.comp_ = compartment;
+ }
+}
+
/// Create and define the interface object of a callback interface.
pub fn create_callback_interface_object(
cx: SafeJSContext,
diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs
index e37e561af06..0f92e4b3367 100644
--- a/components/script/dom/windowproxy.rs
+++ b/components/script/dom/windowproxy.rs
@@ -637,13 +637,11 @@ impl WindowProxy {
// The old window proxy no longer owns this browsing context.
SetProxyReservedSlot(old_js_proxy.get(), 0, &PrivateValue(ptr::null_mut()));
- // Brain transpant the window proxy.
- // We need to do this, because the Window and WindowProxy
- // objects need to be in the same realm.
- // JS_TransplantObject does this by copying the contents
- // of the old window proxy to the new window proxy, then
- // making the old window proxy a cross-realm wrapper
- // pointing to the new window proxy.
+ // Brain transpant the window proxy. Brain transplantation is
+ // usually done to move a window proxy between compartments, but
+ // that's not what we are doing here. We need to do this just
+ // because we want to replace the wrapper's `ProxyTraps`, but we
+ // don't want to update its identity.
rooted!(in(*cx) let new_js_proxy = NewWindowProxy(*cx, window_jsobject, handler));
debug!(
"Transplanting proxy from {:p} to {:p}.",