diff --git a/content/base/src/nsScriptLoader.cpp b/content/base/src/nsScriptLoader.cpp index 76d6bbe9d99f..edd0c4b16418 100644 --- a/content/base/src/nsScriptLoader.cpp +++ b/content/base/src/nsScriptLoader.cpp @@ -999,7 +999,7 @@ nsScriptLoader::GetScriptGlobalObject() void nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest, - JS::Handle scopeChain, + JS::Handle aScopeChain, JS::CompileOptions *aOptions) { // It's very important to use aRequest->mURI, not the final URI of the channel @@ -1008,13 +1008,28 @@ nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest, aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo); aOptions->setVersion(JSVersion(aRequest->mJSVersion)); - aOptions->setCompileAndGo(JS_IsGlobalObject(scopeChain)); + aOptions->setCompileAndGo(JS_IsGlobalObject(aScopeChain)); if (aRequest->mHasSourceMapURL) { aOptions->setSourceMapURL(aRequest->mSourceMapURL.get()); } if (aRequest->mOriginPrincipal) { aOptions->setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal)); } + + AutoJSContext cx; + JS::Rooted elementVal(cx); + MOZ_ASSERT(aRequest->mElement); + // XXXbz this is super-fragile, because the code that _uses_ the + // JS::CompileOptions is nowhere near us, but we have to coordinate + // compartments with it... and in particular, it will compile in the + // compartment of aScopeChain, so we want to wrap into that compartment as + // well. + if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aScopeChain, + aRequest->mElement, &elementVal, + /* aAllowWrapping = */ true))) { + MOZ_ASSERT(elementVal.isObject()); + aOptions->setElement(&elementVal.toObject()); + } } nsresult diff --git a/content/base/src/nsScriptLoader.h b/content/base/src/nsScriptLoader.h index 5d39ab7375d3..c6f8ca85bc31 100644 --- a/content/base/src/nsScriptLoader.h +++ b/content/base/src/nsScriptLoader.h @@ -282,7 +282,7 @@ private: already_AddRefed GetScriptGlobalObject(); void FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest, - JS::Handle scopeChain, + JS::Handle aScopeChain, JS::CompileOptions *aOptions); nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest, diff --git a/dom/events/nsEventListenerManager.cpp b/dom/events/nsEventListenerManager.cpp index 40a95c842ab8..5572398fdbb8 100644 --- a/dom/events/nsEventListenerManager.cpp +++ b/dom/events/nsEventListenerManager.cpp @@ -37,6 +37,8 @@ #include "nsIContentSecurityPolicy.h" #include "xpcpublic.h" #include "nsSandboxFlags.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/BindingUtils.h" using namespace mozilla; using namespace mozilla::dom; @@ -789,24 +791,28 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS AutoPushJSContext cx(context->GetNativeContext()); JS::Rooted handler(cx); + JS::Rooted scope(cx, listener->GetEventScope()); + + nsIAtom* attrName = aListenerStruct->mTypeAtom; + if (aListenerStruct->mHandlerIsString) { // OK, we didn't find an existing compiled event handler. Flag us // as not a string so we don't keep trying to compile strings // which can't be compiled aListenerStruct->mHandlerIsString = false; - // mTarget may not be an nsIContent if it's a window and we're + // mTarget may not be an Element if it's a window and we're // getting an inline event listener forwarded from or // or or the like. // XXX I don't like that we have to reference content from // here. The alternative is to store the event handler string on // the nsIJSEventListener itself, and that still doesn't address // the arg names issue. - nsCOMPtr content = do_QueryInterface(mTarget); + nsCOMPtr element = do_QueryInterface(mTarget); + MOZ_ASSERT(element || aBody, "Where will we get our body?"); nsAutoString handlerBody; const nsAString* body = aBody; - if (content && !aBody) { - nsIAtom* attrName = aListenerStruct->mTypeAtom; + if (!aBody) { if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGLoad) attrName = nsGkAtoms::onload; else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGUnload) @@ -828,29 +834,24 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS else if (aListenerStruct->mTypeAtom == nsGkAtoms::onendEvent) attrName = nsGkAtoms::onend; - content->GetAttr(kNameSpaceID_None, attrName, handlerBody); + element->GetAttr(kNameSpaceID_None, attrName, handlerBody); body = &handlerBody; + aElement = element; } uint32_t lineNo = 0; nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener")); - if (doc) { - nsIURI *uri = doc->GetDocumentURI(); - if (uri) { - uri->GetSpec(url); - lineNo = 1; - } + MOZ_ASSERT(body); + MOZ_ASSERT(aElement); + nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI(); + if (uri) { + uri->GetSpec(url); + lineNo = 1; } uint32_t argCount; const char **argNames; - // If no content, then just use kNameSpaceID_None for the - // namespace ID. In practice, it doesn't matter since SVG is - // the only thing with weird arg names and SVG doesn't map event - // listeners to the window. - nsContentUtils::GetEventArgNames(content ? - content->GetNameSpaceID() : - kNameSpaceID_None, + nsContentUtils::GetEventArgNames(aElement->GetNameSpaceID(), aListenerStruct->mTypeAtom, &argCount, &argNames); @@ -859,6 +860,25 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS options.setFileAndLine(url.get(), lineNo) .setVersion(SCRIPTVERSION_DEFAULT); + JS::Rooted targetVal(cx); + // Go ahead and wrap into the current compartment of cx directly. + JS::Rooted wrapScope(cx, JS::CurrentGlobalOrNull(cx)); + if (WrapNewBindingObject(cx, wrapScope, aElement, &targetVal)) { + MOZ_ASSERT(targetVal.isObject()); + + nsDependentAtomString str(attrName); + // Most of our names are short enough that we don't even have to malloc + // the JS string stuff, so don't worry about playing games with + // refcounting XPCOM stringbuffers. + JS::Rooted jsStr(cx, JS_NewUCStringCopyN(cx, + str.BeginReading(), + str.Length())); + NS_ENSURE_TRUE(jsStr, NS_ERROR_OUT_OF_MEMORY); + + options.setElement(&targetVal.toObject()) + .setElementAttributeName(jsStr); + } + JS::Rooted handlerFun(cx); result = nsJSUtils::CompileFunction(cx, JS::NullPtr(), options, nsAtomCString(aListenerStruct->mTypeAtom), @@ -872,7 +892,6 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS nsCOMPtr win = do_QueryInterface(mTarget); // Bind it JS::Rooted boundHandler(cx); - JS::Rooted scope(cx, listener->GetEventScope()); context->BindCompiledEventHandler(mTarget, scope, handler, &boundHandler); aListenerStruct = nullptr; // Note - We pass null for aIncumbentGlobal below. We could also pass the