Bug 1363963 - Check whether there are expando object attached before trying to retrieve it. r?bholley draft
authorTing-Yu Chou <janus926@gmail.com>
Fri, 26 May 2017 10:04:40 +0800
changeset 587576 88ba65d30bd2a077d863446f651baddec036329f
parent 587432 a8f378825e81daff1279a7d6e940b610912ee6dc
child 631316 03df61454c3d8fea545d4374e14846ff01edcd2e
push id61756
push userbmo:janus926@gmail.com
push dateThu, 01 Jun 2017 09:54:43 +0000
reviewersbholley
bugs1363963
milestone55.0a1
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
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- 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;