diff --git a/dom/bindings/CallbackObject.cpp b/dom/bindings/CallbackObject.cpp index e2a1dc5ba2b4..5e3a80b4e334 100644 --- a/dom/bindings/CallbackObject.cpp +++ b/dom/bindings/CallbackObject.cpp @@ -378,7 +378,7 @@ CallbackObjectHolderBase::ToXPCOMCallback(CallbackObject* aCallback, return nullptr; } - JSAutoRealmAllowCCW ar(cx, callback); + JSAutoRealm ar(cx, aCallback->CallbackGlobalOrNull()); RefPtr wrappedJS; nsresult rv = diff --git a/dom/bindings/CallbackObject.h b/dom/bindings/CallbackObject.h index 43a9601c175a..79b8296a3d4b 100644 --- a/dom/bindings/CallbackObject.h +++ b/dom/bindings/CallbackObject.h @@ -366,7 +366,7 @@ protected: // Put mAr after mAutoEntryScript so that we exit the realm before we // pop the script settings stack. Though in practice we'll often manually // order those two things. - Maybe mAr; + Maybe mAr; // An ErrorResult to possibly re-throw exceptions on and whether // we should re-throw them. diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 91dba2975079..24408dcac0be 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -15290,7 +15290,7 @@ class CGJSImplClass(CGBindingImplClass): } // Now define it on our chrome object - JSAutoRealmAllowCCW ar(aCx, mImpl->CallbackOrNull()); + JSAutoRealm ar(aCx, mImpl->CallbackGlobalOrNull()); if (!JS_WrapObject(aCx, &obj)) { return nullptr; } diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp index e9180cf67c48..908311050aa1 100644 --- a/dom/console/Console.cpp +++ b/dom/console/Console.cpp @@ -1770,8 +1770,9 @@ Console::ProcessCallData(JSContext* aCx, ConsoleCallData* aData, // tempted to do that anywhere else, talk to said module owner first. // aCx and aArguments are in the same compartment. + JS::Rooted targetScope(aCx, xpc::PrivilegedJunkScope()); if (NS_WARN_IF(!PopulateConsoleNotificationInTheTargetScope(aCx, aArguments, - xpc::PrivilegedJunkScope(), + targetScope, &eventValue, aData))) { return; } @@ -1810,15 +1811,14 @@ Console::ProcessCallData(JSContext* aCx, ConsoleCallData* aData, bool Console::PopulateConsoleNotificationInTheTargetScope(JSContext* aCx, const Sequence& aArguments, - JSObject* aTargetScope, + JS::Handle aTargetScope, JS::MutableHandle aEventValue, ConsoleCallData* aData) { MOZ_ASSERT(aCx); MOZ_ASSERT(aData); MOZ_ASSERT(aTargetScope); - - JS::Rooted targetScope(aCx, aTargetScope); + MOZ_ASSERT(JS_IsGlobalObject(aTargetScope)); ConsoleStackEntry frame; if (aData->mTopStackFrame) { @@ -1927,7 +1927,7 @@ Console::PopulateConsoleNotificationInTheTargetScope(JSContext* aCx, aData->mCountValue); } - JSAutoRealmAllowCCW ar2(aCx, targetScope); + JSAutoRealm ar2(aCx, aTargetScope); if (NS_WARN_IF(!ToJSValue(aCx, event, aEventValue))) { return false; @@ -2692,16 +2692,18 @@ Console::NotifyHandler(JSContext* aCx, const Sequence& aArguments, JS::Rooted value(aCx); - JS::Rooted callable(aCx, mConsoleEventNotifier->CallableOrNull()); - if (NS_WARN_IF(!callable)) { + JS::Rooted callableGlobal(aCx, + mConsoleEventNotifier->CallbackGlobalOrNull()); + if (NS_WARN_IF(!callableGlobal)) { return; } // aCx and aArguments are in the same compartment because this method is // called directly when a Console.something() runs. - // mConsoleEventNotifier->Callable() is the scope where value will be sent to. + // mConsoleEventNotifier->CallbackGlobal() is the scope where value will be + // sent to. if (NS_WARN_IF(!PopulateConsoleNotificationInTheTargetScope(aCx, aArguments, - callable, + callableGlobal, &value, aCallData))) { return; diff --git a/dom/console/Console.h b/dom/console/Console.h index 62a586beaa47..8774a7fc3b6d 100644 --- a/dom/console/Console.h +++ b/dom/console/Console.h @@ -239,14 +239,14 @@ private: // - the system-principal scope when we want to dispatch the ConsoleEvent to // nsIConsoleAPIStorage (See the comment in Console.cpp about the use of // xpc::PrivilegedJunkScope() - // - the mConsoleEventNotifier->Callable() scope when we want to notify this + // - the mConsoleEventNotifier->CallableGlobal() when we want to notify this // handler about a new ConsoleEvent. // - It can be the global from the JSContext when RetrieveConsoleEvents is // called. bool PopulateConsoleNotificationInTheTargetScope(JSContext* aCx, const Sequence& aArguments, - JSObject* aTargetScope, + JS::Handle aTargetScope, JS::MutableHandle aValue, ConsoleCallData* aData); diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 98cbe6688bab..21be07941bd8 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -1615,9 +1615,12 @@ EventListenerManager::GetListenerInfo(nsCOMArray* aList) } JS::Rooted callback(RootingCx()); + JS::Rooted callbackGlobal(RootingCx()); if (JSEventHandler* handler = listener.GetJSEventHandler()) { if (handler->GetTypedEventHandler().HasEventHandler()) { - callback = handler->GetTypedEventHandler().Ptr()->CallableOrNull(); + CallbackFunction* callbackFun = handler->GetTypedEventHandler().Ptr(); + callback = callbackFun->CallableOrNull(); + callbackGlobal = callbackFun->CallbackGlobalOrNull(); if (!callback) { // This will be null for cross-compartment event listeners // which have been destroyed. @@ -1625,7 +1628,9 @@ EventListenerManager::GetListenerInfo(nsCOMArray* aList) } } } else if (listener.mListenerType == Listener::eWebIDLListener) { - callback = listener.mListener.GetWebIDLCallback()->CallbackOrNull(); + EventListener* listenerCallback = listener.mListener.GetWebIDLCallback(); + callback = listenerCallback->CallbackOrNull(); + callbackGlobal = listenerCallback->CallbackGlobalOrNull(); if (!callback) { // This will be null for cross-compartment event listeners // which have been destroyed. @@ -1634,7 +1639,7 @@ EventListenerManager::GetListenerInfo(nsCOMArray* aList) } RefPtr info = - new EventListenerInfo(eventType, callback, + new EventListenerInfo(eventType, callback, callbackGlobal, listener.mFlags.mCapture, listener.mFlags.mAllowUntrustedEvents, listener.mFlags.mInSystemGroup); diff --git a/dom/events/EventListenerService.cpp b/dom/events/EventListenerService.cpp index 3d318bef80a8..87b26cb79d28 100644 --- a/dom/events/EventListenerService.cpp +++ b/dom/events/EventListenerService.cpp @@ -82,15 +82,22 @@ EventListenerChange::GetCountOfEventListenerChangesAffectingAccessibility( EventListenerInfo::EventListenerInfo(const nsAString& aType, JS::Handle aScriptedListener, + JS::Handle aScriptedListenerGlobal, bool aCapturing, bool aAllowsUntrusted, bool aInSystemEventGroup) : mType(aType) , mScriptedListener(aScriptedListener) + , mScriptedListenerGlobal(aScriptedListenerGlobal) , mCapturing(aCapturing) , mAllowsUntrusted(aAllowsUntrusted) , mInSystemEventGroup(aInSystemEventGroup) { + if (aScriptedListener) { + MOZ_ASSERT(JS_IsGlobalObject(aScriptedListenerGlobal)); + js::AssertSameCompartment(aScriptedListener, aScriptedListenerGlobal); + } + HoldJSObjects(this); } @@ -106,10 +113,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EventListenerInfo) tmp->mScriptedListener = nullptr; + tmp->mScriptedListenerGlobal = nullptr; NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(EventListenerInfo) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptedListener) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptedListenerGlobal) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventListenerInfo) @@ -152,7 +161,7 @@ NS_IMETHODIMP EventListenerInfo::GetListenerObject(JSContext* aCx, JS::MutableHandle aObject) { - Maybe ar; + Maybe ar; GetJSVal(aCx, ar, aObject); return NS_OK; } @@ -165,12 +174,12 @@ NS_IMPL_ISUPPORTS(EventListenerService, nsIEventListenerService) bool EventListenerInfo::GetJSVal(JSContext* aCx, - Maybe& aAr, + Maybe& aAr, JS::MutableHandle aJSVal) { if (mScriptedListener) { aJSVal.setObject(*mScriptedListener); - aAr.emplace(aCx, mScriptedListener); + aAr.emplace(aCx, mScriptedListenerGlobal); return true; } @@ -184,7 +193,7 @@ EventListenerInfo::ToSource(nsAString& aResult) aResult.SetIsVoid(true); AutoSafeJSContext cx; - Maybe ar; + Maybe ar; JS::Rooted v(cx); if (GetJSVal(cx, ar, &v)) { JSString* str = JS_ValueToSource(cx, v); diff --git a/dom/events/EventListenerService.h b/dom/events/EventListenerService.h index 97cee1db00b3..c33dff7a6f39 100644 --- a/dom/events/EventListenerService.h +++ b/dom/events/EventListenerService.h @@ -49,6 +49,7 @@ class EventListenerInfo final : public nsIEventListenerInfo public: EventListenerInfo(const nsAString& aType, JS::Handle aScriptedListener, + JS::Handle aScriptedListenerGlobal, bool aCapturing, bool aAllowsUntrusted, bool aInSystemEventGroup); @@ -61,11 +62,16 @@ protected: virtual ~EventListenerInfo(); bool GetJSVal(JSContext* aCx, - Maybe& aAr, + Maybe& aAr, JS::MutableHandle aJSVal); nsString mType; JS::Heap mScriptedListener; // May be null. + // mScriptedListener may be a cross-compartment wrapper so we cannot use it + // with JSAutoRealm because CCWs are not associated with a single realm. We + // use this global instead (must be same-compartment with mScriptedListener + // and must be non-null if mScriptedListener is non-null). + JS::Heap mScriptedListenerGlobal; bool mCapturing; bool mAllowsUntrusted; bool mInSystemEventGroup;