Bug 1643457 - Support ChromeOnly properties on remote proxies. r=mccr8

Differential Revision: https://phabricator.services.mozilla.com/D78360
This commit is contained in:
Peter Van der Beken 2020-06-05 12:45:40 +00:00
parent d8029a3fe7
commit a191be346c
7 changed files with 92 additions and 29 deletions

View File

@ -1456,8 +1456,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
class RemoteLocationProxy
: public RemoteObjectProxy<BrowsingContext::LocationProxy,
Location_Binding::sCrossOriginAttributes,
Location_Binding::sCrossOriginMethods> {
Location_Binding::sCrossOriginProperties> {
public:
typedef RemoteObjectProxy Base;

View File

@ -235,7 +235,7 @@ bool MaybeCrossOriginObjectMixins::CrossOriginSet(
/* static */
bool MaybeCrossOriginObjectMixins::EnsureHolder(
JSContext* cx, JS::Handle<JSObject*> obj, size_t slot,
JSPropertySpec* attributes, JSFunctionSpec* methods,
const CrossOriginProperties& properties,
JS::MutableHandle<JSObject*> holder) {
MOZ_ASSERT(!IsPlatformObjectSameOrigin(cx, obj) || IsRemoteObjectProxy(obj),
"Why are we calling this at all in same-origin cases?");
@ -311,9 +311,14 @@ bool MaybeCrossOriginObjectMixins::EnsureHolder(
// cross-compartment references to all the methods it holds, since those
// methods need to be in our current Realm. It seems better to allocate the
// holder in our current Realm.
bool isChrome = xpc::AccessCheck::isChrome(js::GetContextRealm(cx));
holder.set(JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
if (!holder || !JS_DefineProperties(cx, holder, attributes) ||
!JS_DefineFunctions(cx, holder, methods)) {
if (!holder || !JS_DefineProperties(cx, holder, properties.mAttributes) ||
!JS_DefineFunctions(cx, holder, properties.mMethods) ||
(isChrome && properties.mChromeOnlyAttributes &&
!JS_DefineProperties(cx, holder, properties.mChromeOnlyAttributes)) ||
(isChrome && properties.mChromeOnlyMethods &&
!JS_DefineFunctions(cx, holder, properties.mChromeOnlyMethods))) {
return false;
}

View File

@ -34,6 +34,22 @@
namespace mozilla {
namespace dom {
/**
* "mAttributes" and "mMethods" are the cross-origin attributes and methods we
* care about, which should get defined on holders.
*
* "mChromeOnlyAttributes" and "mChromeOnlyMethods" are the cross-origin
* attributes and methods we care about, which should get defined on holders
* for the chrome realm, in addition to the properties that are in
* "mAttributes" and "mMethods".
*/
struct CrossOriginProperties {
const JSPropertySpec* mAttributes;
const JSFunctionSpec* mMethods;
const JSPropertySpec* mChromeOnlyAttributes;
const JSFunctionSpec* mChromeOnlyMethods;
};
// Methods that MaybeCrossOriginObject wants that do not depend on the "Base"
// template parameter. We can avoid having multiple instantiations of them by
// pulling them out into this helper class.
@ -118,12 +134,11 @@ class MaybeCrossOriginObjectMixins {
* "obj" is the object which has space to store the collection of holders in
* the given slot.
*
* "attributes" and "methods" are the cross-origin attributes and methods we
* care about, which should get defined on holders.
* "properties" are the cross-origin attributes and methods we care about,
* which should get defined on holders.
*/
static bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> obj,
size_t slot, JSPropertySpec* attributes,
JSFunctionSpec* methods,
size_t slot, const CrossOriginProperties& properties,
JS::MutableHandle<JSObject*> holder);
/**

View File

@ -24,8 +24,7 @@ namespace dom {
class RemoteOuterWindowProxy
: public RemoteObjectProxy<BrowsingContext,
Window_Binding::sCrossOriginAttributes,
Window_Binding::sCrossOriginMethods> {
Window_Binding::sCrossOriginProperties> {
public:
typedef RemoteObjectProxy Base;

View File

@ -1081,8 +1081,7 @@ bool nsOuterWindowProxy::EnsureHolder(
JSContext* cx, JS::Handle<JSObject*> proxy,
JS::MutableHandle<JSObject*> holder) const {
return EnsureHolder(cx, proxy, HOLDER_WEAKMAP_SLOT,
Window_Binding::sCrossOriginAttributes,
Window_Binding::sCrossOriginMethods, holder);
Window_Binding::sCrossOriginProperties, holder);
}
size_t nsOuterWindowProxy::objectMoved(JSObject* obj, JSObject* old) const {

View File

@ -4324,7 +4324,9 @@ class CGClearCachedValueMethod(CGAbstractMethod):
class CGCrossOriginProperties(CGThing):
def __init__(self, descriptor):
attrs = []
chromeOnlyAttrs = []
methods = []
chromeOnlyMethods = []
for m in descriptor.interface.members:
if m.isAttr() and (m.getExtendedAttribute("CrossOriginReadable") or
m.getExtendedAttribute("CrossOriginWritable")):
@ -4337,7 +4339,10 @@ class CGCrossOriginProperties(CGThing):
if len(m.bindingAliases) > 0:
raise TypeError("Don't know how to deal with aliases for %s" %
m.identifier.name)
attrs.extend(AttrDefiner.attrData(m, overrideFlags="0"))
if m.getExtendedAttribute("ChromeOnly") is not None:
chromeOnlyAttrs.extend(AttrDefiner.attrData(m, overrideFlags="0"))
else:
attrs.extend(AttrDefiner.attrData(m, overrideFlags="0"))
elif m.isMethod() and m.getExtendedAttribute("CrossOriginCallable"):
if m.isStatic():
raise TypeError("Don't know how to deal with static method %s" %
@ -4348,7 +4353,10 @@ class CGCrossOriginProperties(CGThing):
if len(m.aliases) > 0:
raise TypeError("Don't know how to deal with aliases for %s" %
m.identifier.name)
methods.append(MethodDefiner.methodData(m, descriptor, overrideFlags="JSPROP_READONLY"))
if m.getExtendedAttribute("ChromeOnly") is not None:
chromeOnlyMethods.append(MethodDefiner.methodData(m, descriptor, overrideFlags="JSPROP_READONLY"))
else:
methods.append(MethodDefiner.methodData(m, descriptor, overrideFlags="JSPROP_READONLY"))
if len(attrs) > 0:
self.attributeSpecs, _ = PropertyDefiner.generatePrefableArrayValues(
@ -4363,15 +4371,42 @@ class CGCrossOriginProperties(CGThing):
else:
self.methodSpecs = [' JS_FS_END\n']
if len(chromeOnlyAttrs) > 0:
self.chromeOnlyAttributeSpecs, _ = PropertyDefiner.generatePrefableArrayValues(
chromeOnlyAttrs, descriptor, AttrDefiner.formatSpec, ' JS_PS_END\n',
AttrDefiner.condition, functools.partial(AttrDefiner.specData, crossOriginOnly=True))
else:
self.chromeOnlyAttributeSpecs = []
if len(chromeOnlyMethods) > 0:
self.chromeOnlyMethodSpecs, _ = PropertyDefiner.generatePrefableArrayValues(
chromeOnlyMethods, descriptor, MethodDefiner.formatSpec, ' JS_FS_END\n',
MethodDefiner.condition, MethodDefiner.specData)
else:
self.chromeOnlyMethodSpecs = []
def declare(self):
return fill("""
extern JSPropertySpec sCrossOriginAttributes[${attributesLength}];
extern JSFunctionSpec sCrossOriginMethods[${methodsLength}];
""",
attributesLength=len(self.attributeSpecs),
methodsLength=len(self.methodSpecs))
return dedent("""
extern const CrossOriginProperties sCrossOriginProperties;
""")
def define(self):
def defineChromeOnly(name, specs, specType):
if len(specs) == 0:
return ("", "nullptr")
name = "sChromeOnlyCrossOrigin" + name
define = fill(
"""
static const ${specType} ${name}[] = {
$*{specs}
};
""",
specType=specType,
name=name,
specs=",\n".join(specs))
return (define, name)
chromeOnlyAttributes = defineChromeOnly("Attributes", self.chromeOnlyAttributeSpecs, "JSPropertySpec")
chromeOnlyMethods = defineChromeOnly("Methods", self.chromeOnlyMethodSpecs, "JSFunctionSpec")
return fill(
"""
// We deliberately use brace-elision to make Visual Studio produce better initalization code.
@ -4379,18 +4414,30 @@ class CGCrossOriginProperties(CGThing):
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
#endif
JSPropertySpec sCrossOriginAttributes[] = {
static const JSPropertySpec sCrossOriginAttributes[] = {
$*{attributeSpecs}
};
JSFunctionSpec sCrossOriginMethods[] = {
static const JSFunctionSpec sCrossOriginMethods[] = {
$*{methodSpecs}
};
$*{chromeOnlyAttributeSpecs}
$*{chromeOnlyMethodSpecs}
const CrossOriginProperties sCrossOriginProperties = {
sCrossOriginAttributes,
sCrossOriginMethods,
${chromeOnlyAttributes},
${chromeOnlyMethods}
};
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
""",
attributeSpecs=",\n".join(self.attributeSpecs),
methodSpecs=",\n".join(self.methodSpecs))
methodSpecs=",\n".join(self.methodSpecs),
chromeOnlyAttributeSpecs=chromeOnlyAttributes[0],
chromeOnlyMethodSpecs=chromeOnlyMethods[0],
chromeOnlyAttributes=chromeOnlyAttributes[1],
chromeOnlyMethods=chromeOnlyMethods[1])
class CGCycleCollectionTraverseForOwningUnionMethod(CGAbstractMethod):
@ -13589,7 +13636,7 @@ class CGDOMJSProxyHandler_set(ClassMethod):
class CGDOMJSProxyHandler_EnsureHolder(ClassMethod):
"""
Implementation of set(). We only use this for cross-origin objects.
Implementation of EnsureHolder(). We only use this for cross-origin objects.
"""
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'),
@ -13602,10 +13649,9 @@ class CGDOMJSProxyHandler_EnsureHolder(ClassMethod):
def getBody(self):
return dedent(
"""
// Our holder slot is our last slot.
return EnsureHolder(cx, proxy,
JSCLASS_RESERVED_SLOTS(js::GetObjectClass(proxy)) - 1,
sCrossOriginAttributes, sCrossOriginMethods, holder);
sCrossOriginProperties, holder);
""")

View File

@ -134,7 +134,7 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
* hash map in the JS compartment's private (@see
* xpc::CompartmentPrivate::GetRemoteProxyMap).
*/
template <class Native, JSPropertySpec* P, JSFunctionSpec* F>
template <class Native, const CrossOriginProperties& P>
class RemoteObjectProxy : public RemoteObjectProxyBase {
public:
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final {
@ -160,7 +160,7 @@ class RemoteObjectProxy : public RemoteObjectProxyBase {
bool EnsureHolder(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::MutableHandle<JSObject*> aHolder) const final {
return MaybeCrossOriginObjectMixins::EnsureHolder(
aCx, aProxy, /* slot = */ 0, P, F, aHolder);
aCx, aProxy, /* slot = */ 0, P, aHolder);
}
static const JSClass sClass;