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
This commit is contained in:
bors-servo 2021-07-09 10:01:38 -04:00 committed by GitHub
commit 94b613fbda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 52 additions and 77 deletions

View file

@ -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,

View file

@ -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}.",

View file

@ -1,19 +1,4 @@
[event-global-extra.window.html]
[window.event for constructors from another global: EventTarget]
expected: FAIL
[window.event for constructors from another global: XMLHttpRequest]
expected: FAIL
[window.event and element from another document]
expected: FAIL
[window.event and moving an element post-dispatch]
expected: FAIL
[window.event should not be affected by nodes moving post-dispatch]
expected: FAIL
[Listener from a different global]
expected: FAIL

View file

@ -2,7 +2,6 @@
type: testharness
[single-byte-decoder.html?document]
expected: TIMEOUT
[ISO-8859-4: iso_8859-4:1988 (document.characterSet and document.inputEncoding)]
expected: FAIL
@ -30,9 +29,6 @@
[ISO-8859-8: iso_8859-8:1988 (document.characterSet and document.inputEncoding)]
expected: FAIL
[KOI8-R: cskoi8r (document.characterSet and document.inputEncoding)]
expected: TIMEOUT
[single-byte-decoder.html?XMLHttpRequest]
[ISO-8859-2: iso_8859-2:1987 (XMLHttpRequest)]

View file

@ -5,15 +5,3 @@
[Test javascript URL string return values in direct and indirect (target) frame contexts. 9]
expected: FAIL
[Test javascript URL string return values in direct and indirect (target) frame contexts. 5]
expected: FAIL
[Test javascript URL string return values in direct and indirect (target) frame contexts. 6]
expected: FAIL
[Test javascript URL string return values in direct and indirect (target) frame contexts. 7]
expected: FAIL
[Test javascript URL string return values in direct and indirect (target) frame contexts. 8]
expected: FAIL

View file

@ -1,2 +0,0 @@
[cross-origin-objects-on-new-window.html]
expected: TIMEOUT

View file

@ -1,4 +0,0 @@
[sandbox-disallow-same-origin.html]
[Access to sandbox iframe is disallowed]
expected: FAIL

View file

@ -1,5 +1,4 @@
[creating_browsing_context_test_01.html]
expected: TIMEOUT
[first argument: absolute url]
expected: TIMEOUT
expected: FAIL

View file

@ -1,5 +1,5 @@
[iframe_sandbox_popups_escaping-2.html]
expected: TIMEOUT
expected: CRASH
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: TIMEOUT

View file

@ -1,6 +1,6 @@
[iframe_sandbox_popups_nonescaping-1.html]
type: testharness
expected: TIMEOUT
expected: CRASH
[Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN

View file

@ -1,6 +1,5 @@
[htmlanchorelement_noopener.html]
type: testharness
expected: TIMEOUT
[Check that targeting of rel=noopener with a given name ignores an existing window with that name]
expected: NOTRUN
@ -14,5 +13,5 @@
expected: FAIL
[Check that rel=noopener with target=_self does a normal load]
expected: NOTRUN
expected: FAIL

View file

@ -1,6 +0,0 @@
[084.html]
type: testharness
expected: ERROR
[ scheduler: event listener defined by script in a removed IFRAME]
expected: FAIL

View file

@ -1,4 +0,0 @@
[url-entry-document.window.html]
[document.open() changes document's URL to the entry settings object's responsible document's (through timeouts)]
expected: FAIL

View file

@ -1,6 +1,3 @@
[window-onerror-with-cross-frame-event-listeners-1.html]
type: testharness
bug: https://github.com/servo/servo/issues/3311
[The error event from an event listener should fire on that listener's global]
expected: FAIL

View file

@ -1,6 +1,3 @@
[window-onerror-with-cross-frame-event-listeners-4.html]
type: testharness
bug: https://github.com/servo/servo/issues/3311
[The error event from an event listener should fire on that listener's global]
expected: FAIL

View file

@ -1,5 +1,4 @@
[entry-different-function-realm.html]
expected: ERROR
[Start function]
expected: TIMEOUT
expected: FAIL

View file

@ -1,5 +0,0 @@
[incumbent.html]
expected: TIMEOUT
[Start function]
expected: TIMEOUT

View file

@ -1,4 +0,0 @@
[cross-origin-objects.html]
[Only whitelisted properties are accessible cross-origin]
expected: FAIL