Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an inCompartments config option for bindings #23459

Merged
merged 4 commits into from Jun 2, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::globalscope::GlobalScope;
use js::jsapi::{GetCurrentRealmOrNull, JSAutoRealm};
use js::jsapi::{GetCurrentRealmOrNull, JSAutoRealm, JSContext};

pub struct AlreadyInCompartment(());

@@ -15,6 +15,13 @@ impl AlreadyInCompartment {
}
AlreadyInCompartment(())
}

pub fn assert_for_cx(cx: *mut JSContext) -> AlreadyInCompartment {
unsafe {
assert!(!GetCurrentRealmOrNull(cx).is_null());
}
AlreadyInCompartment(())
}
}

#[derive(Clone, Copy)]
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::compartments::{AlreadyInCompartment, InCompartment};
use crate::compartments::InCompartment;
use crate::dom::baseaudiocontext::{BaseAudioContext, BaseAudioContextOptions};
use crate::dom::bindings::codegen::Bindings::AudioContextBinding;
use crate::dom::bindings::codegen::Bindings::AudioContextBinding::{
@@ -108,13 +108,9 @@ impl AudioContextMethods for AudioContext {
}

// https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspend
fn Suspend(&self) -> Rc<Promise> {
fn Suspend(&self, comp: InCompartment) -> Rc<Promise> {
// Step 1.
let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
let promise = Promise::new_in_current_compartment(
&self.global(),
InCompartment::Already(&in_compartment_proof),
);
let promise = Promise::new_in_current_compartment(&self.global(), comp);

// Step 2.
if self.context.control_thread_state() == ProcessingState::Closed {
@@ -173,13 +169,9 @@ impl AudioContextMethods for AudioContext {
}

// https://webaudio.github.io/web-audio-api/#dom-audiocontext-close
fn Close(&self) -> Rc<Promise> {
fn Close(&self, comp: InCompartment) -> Rc<Promise> {
// Step 1.
let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
let promise = Promise::new_in_current_compartment(
&self.global(),
InCompartment::Already(&in_compartment_proof),
);
let promise = Promise::new_in_current_compartment(&self.global(), comp);

// Step 2.
if self.context.control_thread_state() == ProcessingState::Closed {
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::compartments::{AlreadyInCompartment, InCompartment};
use crate::compartments::InCompartment;
use crate::dom::analysernode::AnalyserNode;
use crate::dom::audiobuffer::AudioBuffer;
use crate::dom::audiobuffersourcenode::AudioBufferSourceNode;
@@ -274,13 +274,9 @@ impl BaseAudioContextMethods for BaseAudioContext {
}

/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-resume
fn Resume(&self) -> Rc<Promise> {
fn Resume(&self, comp: InCompartment) -> Rc<Promise> {
// Step 1.
let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
let promise = Promise::new_in_current_compartment(
&self.global(),
InCompartment::Already(&in_compartment_proof),
);
let promise = Promise::new_in_current_compartment(&self.global(), comp);

// Step 2.
if self.audio_context_impl.state() == ProcessingState::Closed {
@@ -424,13 +420,10 @@ impl BaseAudioContextMethods for BaseAudioContext {
audio_data: CustomAutoRooterGuard<ArrayBuffer>,
decode_success_callback: Option<Rc<DecodeSuccessCallback>>,
decode_error_callback: Option<Rc<DecodeErrorCallback>>,
comp: InCompartment,
) -> Rc<Promise> {
// Step 1.
let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
let promise = Promise::new_in_current_compartment(
&self.global(),
InCompartment::Already(&in_compartment_proof),
);
let promise = Promise::new_in_current_compartment(&self.global(), comp);
let global = self.global();
let window = global.as_window();

@@ -31,7 +31,9 @@ DOMInterfaces = {
},

#FIXME(jdm): This should be 'register': False, but then we don't generate enum types
'TestBinding': {},
'TestBinding': {
'inCompartments': ['PromiseAttribute', 'PromiseNativeHandler'],
},

'URL': {
'weakReferenceable': True,
@@ -40,6 +42,95 @@ DOMInterfaces = {
'WindowProxy' : {
'path': 'crate::dom::windowproxy::WindowProxy',
'register': False,
},

'Window': {
'inCompartments': ['Fetch'],
},

'WorkerGlobalScope': {
'inCompartments': ['Fetch'],
},

'CustomElementRegistry': {
'inCompartments': ['WhenDefined'],
},

'AudioContext': {
'inCompartments': ['Suspend', 'Close'],
},

'NavigationPreloadManager': {
'inCompartments': ['Enable', 'Disable', 'SetHeaderValue', 'GetState'],
},

'HTMLMediaElement': {
'inCompartments': ['Play'],
},

'BluetoothRemoteGATTDescriptor': {
'inCompartments': ['ReadValue', 'WriteValue'],
},

'OfflineAudioContext': {
'inCompartments': ['StartRendering'],
},

'BluetoothRemoteGATTServer': {
'inCompartments': ['Connect'],
},

'ServiceWorkerContainer': {
'inCompartments': ['Register'],
},

'Navigator': {
'inCompartments': ['GetVRDisplays'],
},

'MediaDevices': {
'inCompartments': ['GetUserMedia'],
},

'XRSession': {
'inCompartments': ['UpdateRenderState', 'RequestReferenceSpace'],
},

'Bluetooth': {
'inCompartments': ['RequestDevice', 'GetAvailability'],
},

'BaseAudioContext': {
'inCompartments': ['Resume', 'DecodeAudioData'],
},

'RTCPeerConnection': {
'inCompartments': ['AddIceCandidate', 'CreateOffer', 'CreateAnswer', 'SetLocalDescription', 'SetRemoteDescription'],
},

'BluetoothRemoteGATTCharacteristic': {
'inCompartments': ['ReadValue', 'WriteValue', 'StartNotifications', 'StopNotifications'],
},

'VRDisplay': {
'inCompartments': ['RequestPresent', 'ExitPresent'],
},

'Worklet': {
'inCompartments': ['AddModule'],
},

'TestWorklet': {
'inCompartments': ['AddModule'],
},

'BluetoothDevice': {
'inCompartments': ['WatchAdvertisements'],
},

'XR': {
'inCompartments': ['SupportsSessionMode', 'RequestSession'],
}


}
@@ -3316,6 +3316,8 @@ def __init__(self, errorResult, arguments, argsPre, returnType,

if "cx" not in argsPre and needsCx:
args.prepend(CGGeneric("cx"))
if nativeMethodName in descriptor.inCompartmentMethods:
args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))"))

# Build up our actual call
self.cgRoot = CGList([], "\n")
@@ -5625,13 +5627,16 @@ class CGInterfaceTrait(CGThing):
def __init__(self, descriptor):
CGThing.__init__(self)

def attribute_arguments(needCx, argument=None):
def attribute_arguments(needCx, argument=None, inCompartment=False):
if needCx:
yield "cx", "*mut JSContext"

if argument:
yield "value", argument_type(descriptor, argument)

if inCompartment:
yield "_comp", "InCompartment"

def members():
for m in descriptor.interface.members:
if (m.isMethod() and not m.isStatic() and
@@ -5640,14 +5645,18 @@ def members():
name = CGSpecializedMethod.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m)
for idx, (rettype, arguments) in enumerate(m.signatures()):
arguments = method_arguments(descriptor, rettype, arguments)
arguments = method_arguments(descriptor, rettype, arguments,
inCompartment=name in descriptor.inCompartmentMethods)
rettype = return_type(descriptor, rettype, infallible)
yield name + ('_' * idx), arguments, rettype
elif m.isAttr() and not m.isStatic():
name = CGSpecializedGetter.makeNativeName(descriptor, m)
infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True)
yield (name,
attribute_arguments(typeNeedsCx(m.type, True)),
attribute_arguments(
typeNeedsCx(m.type, True),
inCompartment=name in descriptor.inCompartmentMethods
),
return_type(descriptor, m.type, infallible))

if not m.readonly:
@@ -5657,7 +5666,13 @@ def members():
rettype = "()"
else:
rettype = "ErrorResult"
yield name, attribute_arguments(typeNeedsCx(m.type, False), m.type), rettype
yield (name,
attribute_arguments(
typeNeedsCx(m.type, False),
m.type,
inCompartment=name in descriptor.inCompartmentMethods
),
rettype)

if descriptor.proxy:
for name, operation in descriptor.operations.iteritems():
@@ -5671,7 +5686,8 @@ def members():
if operation.isGetter():
if not rettype.nullable():
rettype = IDLNullableType(rettype.location, rettype)
arguments = method_arguments(descriptor, rettype, arguments)
arguments = method_arguments(descriptor, rettype, arguments,
inCompartment=name in descriptor.inCompartmentMethods)

# If this interface 'supports named properties', then we
# should be able to access 'supported property names'
@@ -5681,7 +5697,8 @@ def members():
if operation.isNamed():
yield "SupportedPropertyNames", [], "Vec<DOMString>"
else:
arguments = method_arguments(descriptor, rettype, arguments)
arguments = method_arguments(descriptor, rettype, arguments,
inCompartment=name in descriptor.inCompartmentMethods)
rettype = return_type(descriptor, rettype, infallible)
yield name, arguments, rettype

@@ -5975,6 +5992,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'crate::dom::windowproxy::WindowProxy',
'crate::dom::globalscope::GlobalScope',
'crate::mem::malloc_size_of_including_raw_self',
'crate::compartments::InCompartment',
'crate::compartments::AlreadyInCompartment',
'libc',
'servo_config::pref',
'servo_config::prefs',
@@ -6676,7 +6695,7 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var
return declType.define()


def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None):
def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, inCompartment=False):
if needCx(returnType, arguments, passJSBits):
yield "cx", "*mut JSContext"

@@ -6688,6 +6707,9 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True,
if trailing:
yield trailing

if inCompartment:
yield "_comp", "InCompartment"


def return_type(descriptorProvider, rettype, infallible):
result = getRetvalDeclarationForType(rettype, descriptorProvider)
@@ -223,6 +223,7 @@ def __init__(self, config, interface, desc):
self.concreteType = typeName
self.register = desc.get('register', True)
self.path = desc.get('path', pathDefault)
self.inCompartmentMethods = [name for name in desc.get('inCompartments', [])]
self.bindingPath = 'crate::dom::bindings::codegen::Bindings::%s' % ('::'.join([ifaceName + 'Binding'] * 2))
self.outerObjectHook = desc.get('outerObjectHook', 'None')
self.proxy = False
@@ -535,12 +535,8 @@ impl From<BluetoothError> for Error {

impl BluetoothMethods for Bluetooth {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
fn RequestDevice(&self, option: &RequestDeviceOptions) -> Rc<Promise> {
let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
let p = Promise::new_in_current_compartment(
&self.global(),
InCompartment::Already(&in_compartment_proof),
);
fn RequestDevice(&self, option: &RequestDeviceOptions, comp: InCompartment) -> Rc<Promise> {
let p = Promise::new_in_current_compartment(&self.global(), comp);
// Step 1.
if (option.filters.is_some() && option.acceptAllDevices) ||
(option.filters.is_none() && !option.acceptAllDevices)
@@ -557,12 +553,8 @@ impl BluetoothMethods for Bluetooth {
}

// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-getavailability
fn GetAvailability(&self) -> Rc<Promise> {
let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
let p = Promise::new_in_current_compartment(
&self.global(),
InCompartment::Already(&in_compartment_proof),
);
fn GetAvailability(&self, comp: InCompartment) -> Rc<Promise> {
let p = Promise::new_in_current_compartment(&self.global(), comp);
// Step 1. We did not override the method
// Step 2 - 3. in handle_response
let sender = response_async(&p, self);
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::compartments::{AlreadyInCompartment, InCompartment};
use crate::compartments::InCompartment;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::BluetoothDeviceBinding;
use crate::dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
@@ -278,12 +278,8 @@ impl BluetoothDeviceMethods for BluetoothDevice {
}

// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchadvertisements
fn WatchAdvertisements(&self) -> Rc<Promise> {
let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
let p = Promise::new_in_current_compartment(
&self.global(),
InCompartment::Already(&in_compartment_proof),
);
fn WatchAdvertisements(&self, comp: InCompartment) -> Rc<Promise> {
let p = Promise::new_in_current_compartment(&self.global(), comp);
let sender = response_async(&p, self);
// TODO: Step 1.
// Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.