Bug 858642 - Null-check the XBL scope. r=bz, a=akeybl
--- 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);