Bug 1363963 - Check whether there are expando object attached before trying to retrieve it. r?bholley
In most cases no expando object has ever been attached, we don't need to do a
lot of things and realize it in the last minute.
MozReview-Commit-ID: 5u9ivZQj5L8
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1110,72 +1110,81 @@ XrayTraits::expandoObjectMatchesConsumer
// The exclusive global should always be wrapped in the target's compartment.
MOZ_ASSERT(!exclusiveGlobal || js::IsObjectInContextCompartment(exclusiveGlobal, cx));
MOZ_ASSERT(!owner || js::IsObjectInContextCompartment(owner, cx));
return owner == exclusiveGlobal;
}
bool
-XrayTraits::getExpandoObjectInternal(JSContext* cx, HandleObject target,
+XrayTraits::getExpandoObjectInternal(JSContext* cx, JSObject* expandoChain,
nsIPrincipal* origin,
JSObject* exclusiveGlobalArg,
MutableHandleObject expandoObject)
{
MOZ_ASSERT(!JS_IsExceptionPending(cx));
expandoObject.set(nullptr);
// The expando object lives in the compartment of the target, so all our
// work needs to happen there.
RootedObject exclusiveGlobal(cx, exclusiveGlobalArg);
- JSAutoCompartment ac(cx, target);
+ RootedObject head(cx, expandoChain);
+ JSAutoCompartment ac(cx, head);
if (!JS_WrapObject(cx, &exclusiveGlobal))
return false;
// Iterate through the chain, looking for a same-origin object.
- RootedObject head(cx, getExpandoChain(target));
while (head) {
if (expandoObjectMatchesConsumer(cx, head, origin, exclusiveGlobal)) {
expandoObject.set(head);
return true;
}
head = JS_GetReservedSlot(head, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
}
// Not found.
return true;
}
bool
XrayTraits::getExpandoObject(JSContext* cx, HandleObject target, HandleObject consumer,
MutableHandleObject expandoObject)
{
+ // Return early if no expando object has ever been attached, which is
+ // usually the case.
+ JSObject* chain = getExpandoChain(target);
+ if (!chain)
+ return true;
+
JSObject* consumerGlobal = js::GetGlobalForObjectCrossCompartment(consumer);
bool isSandbox = !strcmp(js::GetObjectJSClass(consumerGlobal)->name, "Sandbox");
- return getExpandoObjectInternal(cx, target, ObjectPrincipal(consumer),
+ return getExpandoObjectInternal(cx, chain, ObjectPrincipal(consumer),
isSandbox ? consumerGlobal : nullptr,
expandoObject);
}
JSObject*
XrayTraits::attachExpandoObject(JSContext* cx, HandleObject target,
nsIPrincipal* origin, HandleObject exclusiveGlobal)
{
// Make sure the compartments are sane.
MOZ_ASSERT(js::IsObjectInContextCompartment(target, cx));
MOZ_ASSERT(!exclusiveGlobal || js::IsObjectInContextCompartment(exclusiveGlobal, cx));
// No duplicates allowed.
#ifdef DEBUG
{
- RootedObject existingExpandoObject(cx);
- if (getExpandoObjectInternal(cx, target, origin, exclusiveGlobal, &existingExpandoObject))
- MOZ_ASSERT(!existingExpandoObject);
- else
- JS_ClearPendingException(cx);
+ JSObject* chain = getExpandoChain(target);
+ if (chain) {
+ RootedObject existingExpandoObject(cx);
+ if (getExpandoObjectInternal(cx, chain, origin, exclusiveGlobal, &existingExpandoObject))
+ MOZ_ASSERT(!existingExpandoObject);
+ else
+ JS_ClearPendingException(cx);
+ }
}
#endif
// Create the expando object.
const JSClass* expandoClass = getExpandoClass(cx, target);
MOZ_ASSERT(!strcmp(expandoClass->name, "XrayExpandoObject"));
RootedObject expandoObject(cx,
JS_NewObjectWithGivenProto(cx, expandoClass, nullptr));
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -122,17 +122,17 @@ protected:
// Get the JSClass we should use for our expando object.
virtual const JSClass* getExpandoClass(JSContext* cx,
JS::HandleObject target) const;
private:
bool expandoObjectMatchesConsumer(JSContext* cx, JS::HandleObject expandoObject,
nsIPrincipal* consumerOrigin,
JS::HandleObject exclusiveGlobal);
- bool getExpandoObjectInternal(JSContext* cx, JS::HandleObject target,
+ bool getExpandoObjectInternal(JSContext* cx, JSObject* expandoChain,
nsIPrincipal* origin, JSObject* exclusiveGlobal,
JS::MutableHandleObject expandoObject);
JSObject* attachExpandoObject(JSContext* cx, JS::HandleObject target,
nsIPrincipal* origin,
JS::HandleObject exclusiveGlobal);
XrayTraits(XrayTraits&) = delete;
const XrayTraits& operator=(XrayTraits&) = delete;