Bug 858642 - Null-check the XBL scope. r=bz, a=akeybl
authorBobby Holley <bobbyholley@gmail.com>
Fri, 05 Apr 2013 12:04:09 -0700
changeset 133355 8cc6a4733c83328bc4b0a39605c39ff4ebade138
parent 133354 a2bec550eb9f88d5755dd7acc620f8a831e5a16c
child 133356 fc4552abab5b70a3539f0fee1e0980668c49a4f3
push id3615
push userryanvm@gmail.com
push dateThu, 11 Apr 2013 13:08:46 +0000
treeherdermozilla-aurora@e7b49daa6e28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, akeybl
bugs858642
milestone22.0a2
Bug 858642 - Null-check the XBL scope. r=bz, a=akeybl
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLProtoImpl.cpp
content/xbl/src/nsXBLProtoImplField.cpp
content/xbl/src/nsXBLProtoImplMethod.cpp
content/xbl/src/nsXBLProtoImplProperty.cpp
content/xbl/src/nsXBLPrototypeHandler.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/xpcpublic.h
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -1424,16 +1424,17 @@ nsXBLBinding::LookupMember(JSContext* aC
     return false;
   }
 
   // Get the scope of mBoundElement and the associated XBL scope. We should only
   // be calling into this machinery if we're running in a separate XBL scope.
   JSObject* boundScope =
     js::GetGlobalForObjectCrossCompartment(mBoundElement->GetWrapper());
   JSObject* xblScope = xpc::GetXBLScope(aCx, boundScope);
+  NS_ENSURE_TRUE(xblScope, false);
   MOZ_ASSERT(boundScope != xblScope);
 
   // Enter the xbl scope and invoke the internal version.
   {
     JSAutoCompartment ac(aCx, xblScope);
     JS::RootedId id(aCx, aId);
     if (!JS_WrapId(aCx, id.address()) ||
         !LookupMemberInternal(aCx, name, id, aDesc, xblScope))
--- a/content/xbl/src/nsXBLProtoImpl.cpp
+++ b/content/xbl/src/nsXBLProtoImpl.cpp
@@ -97,16 +97,17 @@ nsXBLProtoImpl::InstallImplementation(ns
        curr = curr->GetNext())
     curr->InstallMember(cx, targetClassObject);
 
   // If we're using a separate XBL scope, make a safe copy of the target class
   // object in the XBL scope that we can use for Xray lookups. We don't need
   // the field accessors, so do this before installing them.
   JSObject* globalObject = JS_GetGlobalForObject(cx, targetClassObject);
   JSObject* scopeObject = xpc::GetXBLScope(cx, globalObject);
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
   if (scopeObject != globalObject) {
     JSAutoCompartment ac2(cx, scopeObject);
 
     // Create the object. This is just a property holder, so it doesn't need
     // any special JSClass.
     JSObject *shadowProto = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
                                                        scopeObject);
     NS_ENSURE_TRUE(shadowProto, NS_ERROR_OUT_OF_MEMORY);
--- a/content/xbl/src/nsXBLProtoImplField.cpp
+++ b/content/xbl/src/nsXBLProtoImplField.cpp
@@ -297,16 +297,17 @@ FieldSetter(JSContext *cx, unsigned argc
 
 nsresult
 nsXBLProtoImplField::InstallAccessors(JSContext* aCx,
                                       JSObject* aTargetClassObject)
 {
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
   JSObject* globalObject = JS_GetGlobalForObject(aCx, aTargetClassObject);
   JSObject* scopeObject = xpc::GetXBLScope(aCx, globalObject);
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   // Don't install it if the field is empty; see also InstallField which also must
   // implement the not-empty requirement.
   if (IsEmpty()) {
     return NS_OK;
   }
 
   // Install a getter/setter pair which will resolve the field onto the actual
@@ -408,16 +409,17 @@ nsXBLProtoImplField::InstallField(nsIScr
   // compile the literal string
   nsCOMPtr<nsIScriptContext> context = aContext;
 
   JSAutoRequest ar(cx);
 
   // First, enter the xbl scope, wrap the node, and use that as the scope for
   // the evaluation.
   JSObject* scopeObject = xpc::GetXBLScope(cx, aBoundNode);
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
   JSAutoCompartment ac(cx, scopeObject);
   JS::Value result = JSVAL_NULL;
 
   JSObject* wrappedNode = aBoundNode;
   if (!JS_WrapObject(cx, &wrappedNode))
       return NS_ERROR_OUT_OF_MEMORY;
 
   JS::CompileOptions options(cx);
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -99,16 +99,17 @@ nsXBLProtoImplMethod::InstallMember(JSCo
                                     JSObject* aTargetClassObject)
 {
   NS_PRECONDITION(IsCompiled(),
                   "Should not be installing an uncompiled method");
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
 
   JSObject* globalObject = JS_GetGlobalForObject(aCx, aTargetClassObject);
   JSObject* scopeObject = xpc::GetXBLScope(aCx, globalObject);
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   // now we want to reevaluate our property using aContext and the script object for this window...
   if (mJSMethodObject) {
     nsDependentString name(mName);
 
     // First, make the function in the compartment of the scope object.
     JSAutoCompartment ac(aCx, scopeObject);
     JSObject * method = ::JS_CloneFunctionObject(aCx, mJSMethodObject, scopeObject);
@@ -305,16 +306,17 @@ nsXBLProtoImplAnonymousMethod::Execute(n
   // Make sure to do this before entering the compartment, since pushing Push()
   // may call JS_SaveFrameChain(), which puts us back in an unentered state.
   nsCxPusher pusher;
   NS_ENSURE_STATE(pusher.Push(aBoundElement));
   MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
 
   JSObject* thisObject = JSVAL_TO_OBJECT(v);
   JSObject* scopeObject = xpc::GetXBLScope(cx, globalObject);
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, scopeObject);
   if (!JS_WrapObject(cx, &thisObject))
       return NS_ERROR_OUT_OF_MEMORY;
 
   // Clone the function object, using thisObject as the parent so "this" is in
   // the scope chain of the resulting function (for backwards compat to the
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -142,16 +142,17 @@ nsresult
 nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
                                       JSObject* aTargetClassObject)
 {
   NS_PRECONDITION(mIsCompiled,
                   "Should not be installing an uncompiled property");
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
   JSObject * globalObject = JS_GetGlobalForObject(aCx, aTargetClassObject);
   JSObject * scopeObject = xpc::GetXBLScope(aCx, globalObject);
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   // now we want to reevaluate our property using aContext and the script object for this window...
   if (mJSGetterObject || mJSSetterObject) {
     JSObject * getter = nullptr;
 
     // First, enter the compartment of the scope object and clone the functions.
     JSAutoCompartment ac(aCx, scopeObject);
     if (mJSGetterObject)
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -290,16 +290,17 @@ nsXBLPrototypeHandler::ExecuteHandler(ns
   JS::Rooted<JSObject*> handler(cx);
 
   rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, &handler);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSAutoRequest ar(cx);
   JS::Rooted<JSObject*> globalObject(cx, boundGlobal->GetGlobalJSObject());
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScope(cx, globalObject));
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   // Bind it to the bound element. Note that if we're using a separate XBL scope,
   // we'll actually be binding the event handler to a cross-compartment wrapper
   // to the bound element's reflector.
 
   // First, enter our XBL scope. This is where the generic handler should have
   // been compiled, above.
   JSAutoCompartment ac(cx, scopeObject);
@@ -370,16 +371,17 @@ nsXBLPrototypeHandler::EnsureEventHandle
   }
 
   // Ensure that we have something to compile
   nsDependentString handlerText(mHandlerText);
   NS_ENSURE_TRUE(!handlerText.IsEmpty(), NS_ERROR_FAILURE);
 
   JS::Rooted<JSObject*> globalObject(cx, aGlobal->GetGlobalJSObject());
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScope(cx, globalObject));
+  NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   nsAutoCString bindingURI;
   mPrototypeBinding->DocURI()->GetSpec(bindingURI);
 
   uint32_t argCount;
   const char **argNames;
   nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, &argCount,
                                    &argNames);
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -263,16 +263,17 @@ XPCWrappedNativeScope::EnsureXBLScope(JS
     return mXBLScope;
 }
 
 namespace xpc {
 JSObject *GetXBLScope(JSContext *cx, JSObject *contentScope)
 {
     JSAutoCompartment ac(cx, contentScope);
     JSObject *scope = EnsureCompartmentPrivate(contentScope)->scope->EnsureXBLScope(cx);
+    NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
     scope = js::UnwrapObject(scope);
     xpc_UnmarkGrayObject(scope);
     return scope;
 }
 
 bool AllowXBLScope(JSCompartment *c)
 {
   XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -44,16 +44,20 @@ TransplantObjectWithWrapper(JSContext *c
                             JSObject *origobj, JSObject *origwrapper,
                             JSObject *targetobj, JSObject *targetwrapper);
 
 // Return a raw XBL scope object corresponding to contentScope, which must
 // be an object whose global is a DOM window.
 //
 // The return value is not wrapped into cx->compartment, so be sure to enter
 // its compartment before doing anything meaningful.
+//
+// Also note that XBL scopes are lazily created, so the return-value should be
+// null-checked unless the caller can ensure that the scope must already
+// exist.
 JSObject *
 GetXBLScope(JSContext *cx, JSObject *contentScope);
 
 // Returns whether XBL scopes have been explicitly disabled for code running
 // in this compartment. See the comment around mAllowXBLScope.
 bool
 AllowXBLScope(JSCompartment *c);