зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1477923. Make WebIDL callbacks store a global in addition to the object that's used as a callback. r=mccr8
We want to be able to enter the Realm we were in when the callback was created before calling it, but if the callback stores a cross-compartment wrapper we don't really have a good way to find that Realm. So we store it explicitly by storing a global when the callback is created. The changes to the constructor signatures to use JSObject* instead of JS::Handle<JSObject*> are so we can avoid having to root the global for these calls. These changes make two of the constructors ambiguous when nullptr is being passed for the first arg; this patch adds casts to disambiguate.
This commit is contained in:
Родитель
757eed8c02
Коммит
f771d7e529
|
@ -727,11 +727,13 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||||
|
|
||||||
JS::RootingContext* rcx = RootingCx();
|
JS::RootingContext* rcx = RootingCx();
|
||||||
JS::Rooted<JSObject*> object(rcx);
|
JS::Rooted<JSObject*> object(rcx);
|
||||||
|
JS::Rooted<JSObject*> nonCCWObject(rcx);
|
||||||
|
|
||||||
RefPtr<MessageListener> webIDLListener;
|
RefPtr<MessageListener> webIDLListener;
|
||||||
if (!weakListener) {
|
if (!weakListener) {
|
||||||
webIDLListener = listener.mStrongListener;
|
webIDLListener = listener.mStrongListener;
|
||||||
object = webIDLListener->CallbackOrNull();
|
object = webIDLListener->CallbackOrNull();
|
||||||
|
nonCCWObject = webIDLListener->CallbackGlobalOrNull();
|
||||||
} else {
|
} else {
|
||||||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(weakListener);
|
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(weakListener);
|
||||||
if (!wrappedJS) {
|
if (!wrappedJS) {
|
||||||
|
@ -739,6 +741,9 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||||
}
|
}
|
||||||
|
|
||||||
object = wrappedJS->GetJSObject();
|
object = wrappedJS->GetJSObject();
|
||||||
|
// This is not really guaranteed to not be a CCW yet, but hopefully bug
|
||||||
|
// 1478359 will help with that.
|
||||||
|
nonCCWObject = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!object) {
|
if (!object) {
|
||||||
|
@ -749,10 +754,9 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||||
JSContext* cx = aes.cx();
|
JSContext* cx = aes.cx();
|
||||||
|
|
||||||
// We passed the unwrapped object to AutoEntryScript so we now need to
|
// We passed the unwrapped object to AutoEntryScript so we now need to
|
||||||
// enter the (maybe wrapper) object's realm. We will have to revisit this
|
// enter the realm of the non-ccw object that represents the realm of our
|
||||||
// later because CCWs are not associated with a single realm so this
|
// callback.
|
||||||
// doesn't make much sense. See bug 1477923.
|
JSAutoRealm ar(cx, nonCCWObject);
|
||||||
JSAutoRealmAllowCCW ar(cx, object);
|
|
||||||
|
|
||||||
RootedDictionary<ReceiveMessageArgument> argument(cx);
|
RootedDictionary<ReceiveMessageArgument> argument(cx);
|
||||||
|
|
||||||
|
|
|
@ -2360,7 +2360,10 @@ nsGlobalWindowInner::GetInstallTrigger()
|
||||||
rv.SuppressException();
|
rv.SuppressException();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
mInstallTrigger = new InstallTriggerImpl(jsImplObj, this);
|
MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplObj));
|
||||||
|
JS::Rooted<JSObject*> jsImplGlobal(RootingCx(),
|
||||||
|
JS::GetNonCCWObjectGlobal(jsImplObj));
|
||||||
|
mInstallTrigger = new InstallTriggerImpl(jsImplObj, jsImplGlobal, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return do_AddRef(mInstallTrigger);
|
return do_AddRef(mInstallTrigger);
|
||||||
|
@ -7451,7 +7454,10 @@ nsGlobalWindowInner::GetExternal(ErrorResult& aRv)
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
mExternal = new External(jsImplObj, this);
|
MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplObj));
|
||||||
|
JS::Rooted<JSObject*> jsImplGlobal(RootingCx(),
|
||||||
|
JS::GetNonCCWObjectGlobal(jsImplObj));
|
||||||
|
mExternal = new External(jsImplObj, jsImplGlobal, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<External> external = static_cast<External*>(mExternal.get());
|
RefPtr<External> external = static_cast<External*>(mExternal.get());
|
||||||
|
|
|
@ -27,16 +27,18 @@ class CallbackFunction : public CallbackObject
|
||||||
public:
|
public:
|
||||||
// See CallbackObject for an explanation of the arguments.
|
// See CallbackObject for an explanation of the arguments.
|
||||||
explicit CallbackFunction(JSContext* aCx, JS::Handle<JSObject*> aCallable,
|
explicit CallbackFunction(JSContext* aCx, JS::Handle<JSObject*> aCallable,
|
||||||
|
JS::Handle<JSObject*> aCallableGlobal,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
: CallbackObject(aCx, aCallable, aIncumbentGlobal)
|
: CallbackObject(aCx, aCallable, aCallableGlobal, aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// See CallbackObject for an explanation of the arguments.
|
// See CallbackObject for an explanation of the arguments.
|
||||||
explicit CallbackFunction(JS::Handle<JSObject*> aCallable,
|
explicit CallbackFunction(JSObject* aCallable,
|
||||||
JS::Handle<JSObject*> aAsyncStack,
|
JSObject* aCallableGlobal,
|
||||||
|
JSObject* aAsyncStack,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
: CallbackObject(aCallable, aAsyncStack, aIncumbentGlobal)
|
: CallbackObject(aCallable, aCallableGlobal, aAsyncStack, aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +65,10 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
// See CallbackObject for an explanation of the arguments.
|
// See CallbackObject for an explanation of the arguments.
|
||||||
CallbackFunction(JS::Handle<JSObject*> aCallable,
|
CallbackFunction(JSObject* aCallable,
|
||||||
|
JSObject* aCallableGlobal,
|
||||||
const FastCallbackConstructor&)
|
const FastCallbackConstructor&)
|
||||||
: CallbackObject(aCallable, FastCallbackConstructor())
|
: CallbackObject(aCallable, aCallableGlobal, FastCallbackConstructor())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,16 +26,18 @@ class CallbackInterface : public CallbackObject
|
||||||
public:
|
public:
|
||||||
// See CallbackObject for an explanation of the arguments.
|
// See CallbackObject for an explanation of the arguments.
|
||||||
explicit CallbackInterface(JSContext* aCx, JS::Handle<JSObject*> aCallback,
|
explicit CallbackInterface(JSContext* aCx, JS::Handle<JSObject*> aCallback,
|
||||||
|
JS::Handle<JSObject*> aCallbackGlobal,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
: CallbackObject(aCx, aCallback, aIncumbentGlobal)
|
: CallbackObject(aCx, aCallback, aCallbackGlobal, aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// See CallbackObject for an explanation of the arguments.
|
// See CallbackObject for an explanation of the arguments.
|
||||||
explicit CallbackInterface(JS::Handle<JSObject*> aCallback,
|
explicit CallbackInterface(JSObject* aCallback,
|
||||||
JS::Handle<JSObject*> aAsyncStack,
|
JSObject* aCallbackGlobal,
|
||||||
|
JSObject* aAsyncStack,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
: CallbackObject(aCallback, aAsyncStack, aIncumbentGlobal)
|
: CallbackObject(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,9 +46,10 @@ protected:
|
||||||
JS::MutableHandle<JS::Value> aCallable);
|
JS::MutableHandle<JS::Value> aCallable);
|
||||||
|
|
||||||
// See CallbackObject for an explanation of the arguments.
|
// See CallbackObject for an explanation of the arguments.
|
||||||
CallbackInterface(JS::Handle<JSObject*> aCallable,
|
CallbackInterface(JSObject* aCallback,
|
||||||
|
JSObject* aCallbackGlobal,
|
||||||
const FastCallbackConstructor&)
|
const FastCallbackConstructor&)
|
||||||
: CallbackObject(aCallable, FastCallbackConstructor())
|
: CallbackObject(aCallback, aCallbackGlobal, FastCallbackConstructor())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,6 +81,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallbackGlobal)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCreationStack)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCreationStack)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mIncumbentJSGlobal)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mIncumbentJSGlobal)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||||
|
@ -89,6 +90,7 @@ void
|
||||||
CallbackObject::Trace(JSTracer* aTracer)
|
CallbackObject::Trace(JSTracer* aTracer)
|
||||||
{
|
{
|
||||||
JS::TraceEdge(aTracer, &mCallback, "CallbackObject.mCallback");
|
JS::TraceEdge(aTracer, &mCallback, "CallbackObject.mCallback");
|
||||||
|
JS::TraceEdge(aTracer, &mCallbackGlobal, "CallbackObject.mCallbackGlobal");
|
||||||
JS::TraceEdge(aTracer, &mCreationStack, "CallbackObject.mCreationStack");
|
JS::TraceEdge(aTracer, &mCreationStack, "CallbackObject.mCreationStack");
|
||||||
JS::TraceEdge(aTracer, &mIncumbentJSGlobal,
|
JS::TraceEdge(aTracer, &mIncumbentJSGlobal,
|
||||||
"CallbackObject.mIncumbentJSGlobal");
|
"CallbackObject.mIncumbentJSGlobal");
|
||||||
|
@ -239,6 +241,7 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||||
// with the cx from mAutoEntryScript, avoiding the cost of finding another
|
// with the cx from mAutoEntryScript, avoiding the cost of finding another
|
||||||
// JSContext. (Rooted<> does not care about requests or compartments.)
|
// JSContext. (Rooted<> does not care about requests or compartments.)
|
||||||
mRootedCallable.emplace(cx, aCallback->CallbackOrNull());
|
mRootedCallable.emplace(cx, aCallback->CallbackOrNull());
|
||||||
|
mRootedCallableGlobal.emplace(cx, aCallback->CallbackGlobalOrNull());
|
||||||
|
|
||||||
mAsyncStack.emplace(cx, aCallback->GetCreationStack());
|
mAsyncStack.emplace(cx, aCallback->GetCreationStack());
|
||||||
if (*mAsyncStack) {
|
if (*mAsyncStack) {
|
||||||
|
@ -250,7 +253,7 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||||
// Note that if the callback is a wrapper, this will not be the same
|
// Note that if the callback is a wrapper, this will not be the same
|
||||||
// realm that we ended up in with mAutoEntryScript above, because the
|
// realm that we ended up in with mAutoEntryScript above, because the
|
||||||
// entry point is based off of the unwrapped callback (realCallback).
|
// entry point is based off of the unwrapped callback (realCallback).
|
||||||
mAr.emplace(cx, *mRootedCallable);
|
mAr.emplace(cx, *mRootedCallableGlobal);
|
||||||
|
|
||||||
// And now we're ready to go.
|
// And now we're ready to go.
|
||||||
mCx = cx;
|
mCx = cx;
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
// is invoked. aCx can be nullptr, in which case no stack is
|
// is invoked. aCx can be nullptr, in which case no stack is
|
||||||
// captured.
|
// captured.
|
||||||
explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
|
explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
|
||||||
|
JS::Handle<JSObject*> aCallbackGlobal,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
if (aCx && JS::ContextOptionsRef(aCx).asyncStack()) {
|
if (aCx && JS::ContextOptionsRef(aCx).asyncStack()) {
|
||||||
|
@ -63,20 +64,21 @@ public:
|
||||||
if (!JS::CaptureCurrentStack(aCx, &stack)) {
|
if (!JS::CaptureCurrentStack(aCx, &stack)) {
|
||||||
JS_ClearPendingException(aCx);
|
JS_ClearPendingException(aCx);
|
||||||
}
|
}
|
||||||
Init(aCallback, stack, aIncumbentGlobal);
|
Init(aCallback, aCallbackGlobal, stack, aIncumbentGlobal);
|
||||||
} else {
|
} else {
|
||||||
Init(aCallback, nullptr, aIncumbentGlobal);
|
Init(aCallback, aCallbackGlobal, nullptr, aIncumbentGlobal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instead of capturing the current stack to use as an async parent when the
|
// Instead of capturing the current stack to use as an async parent when the
|
||||||
// callback is invoked, the caller can use this overload to pass in a stack
|
// callback is invoked, the caller can use this overload to pass in a stack
|
||||||
// for that purpose.
|
// for that purpose.
|
||||||
explicit CallbackObject(JS::Handle<JSObject*> aCallback,
|
explicit CallbackObject(JSObject* aCallback,
|
||||||
JS::Handle<JSObject*> aAsyncStack,
|
JSObject* aCallbackGlobal,
|
||||||
|
JSObject* aAsyncStack,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
Init(aCallback, aAsyncStack, aIncumbentGlobal);
|
Init(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is guaranteed to be non-null from the time the CallbackObject is
|
// This is guaranteed to be non-null from the time the CallbackObject is
|
||||||
|
@ -93,6 +95,12 @@ public:
|
||||||
return CallbackPreserveColor();
|
return CallbackPreserveColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSObject* CallbackGlobalOrNull() const
|
||||||
|
{
|
||||||
|
mCallbackGlobal.exposeToActiveJS();
|
||||||
|
return mCallbackGlobal;
|
||||||
|
}
|
||||||
|
|
||||||
// Like CallbackOrNull(), but will return a new dead proxy object in the
|
// Like CallbackOrNull(), but will return a new dead proxy object in the
|
||||||
// caller's realm if the callback is null.
|
// caller's realm if the callback is null.
|
||||||
JSObject* Callback(JSContext* aCx);
|
JSObject* Callback(JSContext* aCx);
|
||||||
|
@ -105,6 +113,7 @@ public:
|
||||||
void MarkForCC()
|
void MarkForCC()
|
||||||
{
|
{
|
||||||
mCallback.exposeToActiveJS();
|
mCallback.exposeToActiveJS();
|
||||||
|
mCallbackGlobal.exposeToActiveJS();
|
||||||
mCreationStack.exposeToActiveJS();
|
mCreationStack.exposeToActiveJS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +174,8 @@ protected:
|
||||||
|
|
||||||
explicit CallbackObject(CallbackObject* aCallbackObject)
|
explicit CallbackObject(CallbackObject* aCallbackObject)
|
||||||
{
|
{
|
||||||
Init(aCallbackObject->mCallback, aCallbackObject->mCreationStack,
|
Init(aCallbackObject->mCallback, aCallbackObject->mCallbackGlobal,
|
||||||
|
aCallbackObject->mCreationStack,
|
||||||
aCallbackObject->mIncumbentGlobal);
|
aCallbackObject->mIncumbentGlobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,13 +209,17 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void InitNoHold(JSObject* aCallback, JSObject* aCreationStack,
|
inline void InitNoHold(JSObject* aCallback, JSObject* aCallbackGlobal,
|
||||||
|
JSObject* aCreationStack,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aCallback && !mCallback);
|
MOZ_ASSERT(aCallback && !mCallback);
|
||||||
// Set script objects before we hold, on the off chance that a GC could
|
MOZ_ASSERT(aCallbackGlobal);
|
||||||
// somehow happen in there... (which would be pretty odd, granted).
|
MOZ_DIAGNOSTIC_ASSERT(js::GetObjectCompartment(aCallback) ==
|
||||||
|
js::GetObjectCompartment(aCallbackGlobal));
|
||||||
|
MOZ_ASSERT(JS_IsGlobalObject(aCallbackGlobal));
|
||||||
mCallback = aCallback;
|
mCallback = aCallback;
|
||||||
|
mCallbackGlobal = aCallbackGlobal;
|
||||||
mCreationStack = aCreationStack;
|
mCreationStack = aCreationStack;
|
||||||
if (aIncumbentGlobal) {
|
if (aIncumbentGlobal) {
|
||||||
mIncumbentGlobal = aIncumbentGlobal;
|
mIncumbentGlobal = aIncumbentGlobal;
|
||||||
|
@ -213,16 +227,20 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Init(JSObject* aCallback, JSObject* aCreationStack,
|
inline void Init(JSObject* aCallback, JSObject* aCallbackGlobal,
|
||||||
|
JSObject* aCreationStack,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
{
|
{
|
||||||
InitNoHold(aCallback, aCreationStack, aIncumbentGlobal);
|
// Set script objects before we hold, on the off chance that a GC could
|
||||||
|
// somehow happen in there... (which would be pretty odd, granted).
|
||||||
|
InitNoHold(aCallback, aCallbackGlobal, aCreationStack, aIncumbentGlobal);
|
||||||
mozilla::HoldJSObjects(this);
|
mozilla::HoldJSObjects(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ClearJSReferences()
|
inline void ClearJSReferences()
|
||||||
{
|
{
|
||||||
mCallback = nullptr;
|
mCallback = nullptr;
|
||||||
|
mCallbackGlobal = nullptr;
|
||||||
mCreationStack = nullptr;
|
mCreationStack = nullptr;
|
||||||
mIncumbentJSGlobal = nullptr;
|
mIncumbentJSGlobal = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -262,10 +280,11 @@ protected:
|
||||||
// assumption that we will do that last whenever we decide to actually
|
// assumption that we will do that last whenever we decide to actually
|
||||||
// HoldJSObjects; see FinishSlowJSInitIfMoreThanOneOwner). If you use this,
|
// HoldJSObjects; see FinishSlowJSInitIfMoreThanOneOwner). If you use this,
|
||||||
// you MUST ensure that the object is traced until the HoldJSObjects happens!
|
// you MUST ensure that the object is traced until the HoldJSObjects happens!
|
||||||
CallbackObject(JS::Handle<JSObject*> aCallback,
|
CallbackObject(JSObject* aCallback,
|
||||||
|
JSObject* aCallbackGlobal,
|
||||||
const FastCallbackConstructor&)
|
const FastCallbackConstructor&)
|
||||||
{
|
{
|
||||||
InitNoHold(aCallback, nullptr, nullptr);
|
InitNoHold(aCallback, aCallbackGlobal, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mCallback is not unwrapped, so it can be a cross-compartment-wrapper.
|
// mCallback is not unwrapped, so it can be a cross-compartment-wrapper.
|
||||||
|
@ -273,6 +292,11 @@ protected:
|
||||||
// its members, directly itself, this code won't call f(), or get its members,
|
// its members, directly itself, this code won't call f(), or get its members,
|
||||||
// on the code's behalf.
|
// on the code's behalf.
|
||||||
JS::Heap<JSObject*> mCallback;
|
JS::Heap<JSObject*> mCallback;
|
||||||
|
// mCallbackGlobal is the global that we were in when we created the
|
||||||
|
// callback. In particular, it is guaranteed to be same-compartment with
|
||||||
|
// aCallback. We store it separately, because we have no way to recover the
|
||||||
|
// global if mCallback is a cross-compartment wrapper.
|
||||||
|
JS::Heap<JSObject*> mCallbackGlobal;
|
||||||
JS::Heap<JSObject*> mCreationStack;
|
JS::Heap<JSObject*> mCreationStack;
|
||||||
// Ideally, we'd just hold a reference to the nsIGlobalObject, since that's
|
// Ideally, we'd just hold a reference to the nsIGlobalObject, since that's
|
||||||
// what we need to pass to AutoIncumbentScript. Unfortunately, that doesn't
|
// what we need to pass to AutoIncumbentScript. Unfortunately, that doesn't
|
||||||
|
@ -330,7 +354,9 @@ protected:
|
||||||
Maybe<AutoEntryScript> mAutoEntryScript;
|
Maybe<AutoEntryScript> mAutoEntryScript;
|
||||||
Maybe<AutoIncumbentScript> mAutoIncumbentScript;
|
Maybe<AutoIncumbentScript> mAutoIncumbentScript;
|
||||||
|
|
||||||
Maybe<JS::Rooted<JSObject*> > mRootedCallable;
|
Maybe<JS::Rooted<JSObject*>> mRootedCallable;
|
||||||
|
// The global of mRootedCallable.
|
||||||
|
Maybe<JS::Rooted<JSObject*>> mRootedCallableGlobal;
|
||||||
|
|
||||||
// Members which are used to set the async stack.
|
// Members which are used to set the async stack.
|
||||||
Maybe<JS::Rooted<JSObject*>> mAsyncStack;
|
Maybe<JS::Rooted<JSObject*>> mAsyncStack;
|
||||||
|
|
|
@ -4240,7 +4240,10 @@ class CastableObjectUnwrapper():
|
||||||
$*{exceptionCode}
|
$*{exceptionCode}
|
||||||
}
|
}
|
||||||
JS::Rooted<JSObject*> jsImplSourceObj(cx, &${source}.toObject());
|
JS::Rooted<JSObject*> jsImplSourceObj(cx, &${source}.toObject());
|
||||||
${target} = new ${type}(jsImplSourceObj, contentGlobal);
|
MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplSourceObj),
|
||||||
|
"Don't return JS implementations from other compartments");
|
||||||
|
JS::Rooted<JSObject*> jsImplSourceGlobal(cx, JS::GetNonCCWObjectGlobal(jsImplSourceObj));
|
||||||
|
${target} = new ${type}(jsImplSourceObj, jsImplSourceGlobal, contentGlobal);
|
||||||
} else {
|
} else {
|
||||||
$*{codeOnFailure}
|
$*{codeOnFailure}
|
||||||
}
|
}
|
||||||
|
@ -4297,11 +4300,15 @@ def getCallbackConversionInfo(type, idlObject, isMember, isCallbackReturnValue,
|
||||||
not isOptional)
|
not isOptional)
|
||||||
if useFastCallback:
|
if useFastCallback:
|
||||||
name = "binding_detail::Fast%s" % name
|
name = "binding_detail::Fast%s" % name
|
||||||
argsPre = ""
|
rootArgs = ""
|
||||||
argsPost = ""
|
args = "&${val}.toObject(), JS::CurrentGlobalOrNull(cx)"
|
||||||
else:
|
else:
|
||||||
argsPre = "cx, "
|
rootArgs = dedent(
|
||||||
argsPost = ", GetIncumbentGlobal()"
|
"""
|
||||||
|
JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
|
||||||
|
JS::Rooted<JSObject*> tempGlobalRoot(cx, JS::CurrentGlobalOrNull(cx));
|
||||||
|
""")
|
||||||
|
args = "cx, tempRoot, tempGlobalRoot, GetIncumbentGlobal()"
|
||||||
|
|
||||||
if type.nullable() or isCallbackReturnValue:
|
if type.nullable() or isCallbackReturnValue:
|
||||||
declType = CGGeneric("RefPtr<%s>" % name)
|
declType = CGGeneric("RefPtr<%s>" % name)
|
||||||
|
@ -4316,14 +4323,14 @@ def getCallbackConversionInfo(type, idlObject, isMember, isCallbackReturnValue,
|
||||||
|
|
||||||
conversion = fill(
|
conversion = fill(
|
||||||
"""
|
"""
|
||||||
{ // scope for tempRoot
|
{ // scope for tempRoot and tempGlobalRoot if needed
|
||||||
JS::Rooted<JSObject*> tempRoot(cx, &$${val}.toObject());
|
$*{rootArgs}
|
||||||
$${declName} = new ${name}(${argsPre}tempRoot${argsPost});
|
$${declName} = new ${name}(${args});
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
|
rootArgs=rootArgs,
|
||||||
name=name,
|
name=name,
|
||||||
argsPre=argsPre,
|
args=args)
|
||||||
argsPost=argsPost)
|
|
||||||
return (declType, declArgs, conversion)
|
return (declType, declArgs, conversion)
|
||||||
|
|
||||||
|
|
||||||
|
@ -15066,8 +15073,11 @@ def genConstructorBody(descriptor, initCall=""):
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
// We should be getting the implementation object for the relevant
|
||||||
|
// contract here, which should never be a cross-compartment wrapper.
|
||||||
|
JS::Rooted<JSObject*> jsImplGlobal(cx, JS::GetNonCCWObjectGlobal(jsImplObj));
|
||||||
// Build the C++ implementation.
|
// Build the C++ implementation.
|
||||||
RefPtr<${implClass}> impl = new ${implClass}(jsImplObj, globalHolder);
|
RefPtr<${implClass}> impl = new ${implClass}(jsImplObj, jsImplGlobal, globalHolder);
|
||||||
$*{initCall}
|
$*{initCall}
|
||||||
return impl.forget();
|
return impl.forget();
|
||||||
""",
|
""",
|
||||||
|
@ -15219,14 +15229,14 @@ class CGJSImplClass(CGBindingImplClass):
|
||||||
destructor = ClassDestructor(virtual=False, visibility="private")
|
destructor = ClassDestructor(virtual=False, visibility="private")
|
||||||
|
|
||||||
baseConstructors = [
|
baseConstructors = [
|
||||||
("mImpl(new %s(nullptr, aJSImplObject, /* aIncumbentGlobal = */ nullptr))" %
|
("mImpl(new %s(nullptr, aJSImplObject, aJSImplGlobal, /* aIncumbentGlobal = */ nullptr))" %
|
||||||
jsImplName(descriptor.name)),
|
jsImplName(descriptor.name)),
|
||||||
"mParent(aParent)"]
|
"mParent(aParent)"]
|
||||||
parentInterface = descriptor.interface.parent
|
parentInterface = descriptor.interface.parent
|
||||||
while parentInterface:
|
while parentInterface:
|
||||||
if parentInterface.isJSImplemented():
|
if parentInterface.isJSImplemented():
|
||||||
baseConstructors.insert(
|
baseConstructors.insert(
|
||||||
0, "%s(aJSImplObject, aParent)" % parentClass)
|
0, "%s(aJSImplObject, aJSImplGlobal, aParent)" % parentClass)
|
||||||
break
|
break
|
||||||
parentInterface = parentInterface.parent
|
parentInterface = parentInterface.parent
|
||||||
if not parentInterface and descriptor.interface.parent:
|
if not parentInterface and descriptor.interface.parent:
|
||||||
|
@ -15236,6 +15246,7 @@ class CGJSImplClass(CGBindingImplClass):
|
||||||
|
|
||||||
constructor = ClassConstructor(
|
constructor = ClassConstructor(
|
||||||
[Argument("JS::Handle<JSObject*>", "aJSImplObject"),
|
[Argument("JS::Handle<JSObject*>", "aJSImplObject"),
|
||||||
|
Argument("JS::Handle<JSObject*>", "aJSImplGlobal"),
|
||||||
Argument("nsIGlobalObject*", "aParent")],
|
Argument("nsIGlobalObject*", "aParent")],
|
||||||
visibility="public",
|
visibility="public",
|
||||||
baseConstructors=baseConstructors)
|
baseConstructors=baseConstructors)
|
||||||
|
@ -15331,7 +15342,8 @@ class CGJSImplClass(CGBindingImplClass):
|
||||||
nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
|
nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
|
||||||
MOZ_ASSERT(globalHolder);
|
MOZ_ASSERT(globalHolder);
|
||||||
JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
|
JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
|
||||||
RefPtr<${implName}> impl = new ${implName}(arg, globalHolder);
|
JS::Rooted<JSObject*> argGlobal(cx, JS::CurrentGlobalOrNull(cx));
|
||||||
|
RefPtr<${implName}> impl = new ${implName}(arg, argGlobal, globalHolder);
|
||||||
MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
|
MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
|
||||||
return GetOrCreateDOMReflector(cx, impl, args.rval());
|
return GetOrCreateDOMReflector(cx, impl, args.rval());
|
||||||
""",
|
""",
|
||||||
|
@ -15404,33 +15416,39 @@ class CGCallback(CGClass):
|
||||||
ClassConstructor(
|
ClassConstructor(
|
||||||
[Argument("JSContext*", "aCx"),
|
[Argument("JSContext*", "aCx"),
|
||||||
Argument("JS::Handle<JSObject*>", "aCallback"),
|
Argument("JS::Handle<JSObject*>", "aCallback"),
|
||||||
|
Argument("JS::Handle<JSObject*>", "aCallbackGlobal"),
|
||||||
Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
visibility="public",
|
visibility="public",
|
||||||
explicit=True,
|
explicit=True,
|
||||||
baseConstructors=[
|
baseConstructors=[
|
||||||
"%s(aCx, aCallback, aIncumbentGlobal)" % self.baseName,
|
"%s(aCx, aCallback, aCallbackGlobal, aIncumbentGlobal)" %
|
||||||
|
self.baseName,
|
||||||
],
|
],
|
||||||
body=body),
|
body=body),
|
||||||
ClassConstructor(
|
ClassConstructor(
|
||||||
[Argument("JS::Handle<JSObject*>", "aCallback"),
|
[Argument("JSObject*", "aCallback"),
|
||||||
|
Argument("JSObject*", "aCallbackGlobal"),
|
||||||
Argument("const FastCallbackConstructor&", "")],
|
Argument("const FastCallbackConstructor&", "")],
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
visibility="public",
|
visibility="public",
|
||||||
explicit=True,
|
explicit=True,
|
||||||
baseConstructors=[
|
baseConstructors=[
|
||||||
"%s(aCallback, FastCallbackConstructor())" % self.baseName,
|
"%s(aCallback, aCallbackGlobal, FastCallbackConstructor())" %
|
||||||
|
self.baseName,
|
||||||
],
|
],
|
||||||
body=body),
|
body=body),
|
||||||
ClassConstructor(
|
ClassConstructor(
|
||||||
[Argument("JS::Handle<JSObject*>", "aCallback"),
|
[Argument("JSObject*", "aCallback"),
|
||||||
Argument("JS::Handle<JSObject*>", "aAsyncStack"),
|
Argument("JSObject*", "aCallbackGlobal"),
|
||||||
|
Argument("JSObject*", "aAsyncStack"),
|
||||||
Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
visibility="public",
|
visibility="public",
|
||||||
explicit=True,
|
explicit=True,
|
||||||
baseConstructors=[
|
baseConstructors=[
|
||||||
"%s(aCallback, aAsyncStack, aIncumbentGlobal)" % self.baseName,
|
"%s(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal)" %
|
||||||
|
self.baseName,
|
||||||
],
|
],
|
||||||
body=body)]
|
body=body)]
|
||||||
|
|
||||||
|
@ -15591,12 +15609,13 @@ class CGFastCallback(CGClass):
|
||||||
self._deps = idlObject.getDeps()
|
self._deps = idlObject.getDeps()
|
||||||
baseName = idlObject.identifier.name
|
baseName = idlObject.identifier.name
|
||||||
constructor = ClassConstructor(
|
constructor = ClassConstructor(
|
||||||
[Argument("JS::Handle<JSObject*>", "aCallback")],
|
[Argument("JSObject*", "aCallback"),
|
||||||
|
Argument("JSObject*", "aCallbackGlobal")],
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
visibility="public",
|
visibility="public",
|
||||||
explicit=True,
|
explicit=True,
|
||||||
baseConstructors=[
|
baseConstructors=[
|
||||||
"%s(aCallback, FastCallbackConstructor())" %
|
"%s(aCallback, aCallbackGlobal, FastCallbackConstructor())" %
|
||||||
baseName,
|
baseName,
|
||||||
],
|
],
|
||||||
body="")
|
body="")
|
||||||
|
|
|
@ -17,8 +17,9 @@ class TestCImplementedInterface : public TestJSImplInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestCImplementedInterface(JS::Handle<JSObject*> aJSImpl,
|
TestCImplementedInterface(JS::Handle<JSObject*> aJSImpl,
|
||||||
|
JS::Handle<JSObject*> aJSImplGlobal,
|
||||||
nsIGlobalObject* aParent)
|
nsIGlobalObject* aParent)
|
||||||
: TestJSImplInterface(aJSImpl, aParent)
|
: TestJSImplInterface(aJSImpl, aJSImplGlobal, aParent)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1054,17 +1054,27 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
|
||||||
NS_ENSURE_SUCCESS(result, result);
|
NS_ENSURE_SUCCESS(result, result);
|
||||||
NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
MOZ_ASSERT(js::IsObjectInContextCompartment(handler, cx));
|
||||||
|
JS::Rooted<JSObject*> handlerGlobal(cx, JS::CurrentGlobalOrNull(cx));
|
||||||
|
|
||||||
if (jsEventHandler->EventName() == nsGkAtoms::onerror && win) {
|
if (jsEventHandler->EventName() == nsGkAtoms::onerror && win) {
|
||||||
RefPtr<OnErrorEventHandlerNonNull> handlerCallback =
|
RefPtr<OnErrorEventHandlerNonNull> handlerCallback =
|
||||||
new OnErrorEventHandlerNonNull(nullptr, handler, /* aIncumbentGlobal = */ nullptr);
|
new OnErrorEventHandlerNonNull(static_cast<JSContext*>(nullptr), handler,
|
||||||
|
handlerGlobal,
|
||||||
|
/* aIncumbentGlobal = */ nullptr);
|
||||||
jsEventHandler->SetHandler(handlerCallback);
|
jsEventHandler->SetHandler(handlerCallback);
|
||||||
} else if (jsEventHandler->EventName() == nsGkAtoms::onbeforeunload && win) {
|
} else if (jsEventHandler->EventName() == nsGkAtoms::onbeforeunload && win) {
|
||||||
RefPtr<OnBeforeUnloadEventHandlerNonNull> handlerCallback =
|
RefPtr<OnBeforeUnloadEventHandlerNonNull> handlerCallback =
|
||||||
new OnBeforeUnloadEventHandlerNonNull(nullptr, handler, /* aIncumbentGlobal = */ nullptr);
|
new OnBeforeUnloadEventHandlerNonNull(static_cast<JSContext*>(nullptr),
|
||||||
|
handler,
|
||||||
|
handlerGlobal,
|
||||||
|
/* aIncumbentGlobal = */ nullptr);
|
||||||
jsEventHandler->SetHandler(handlerCallback);
|
jsEventHandler->SetHandler(handlerCallback);
|
||||||
} else {
|
} else {
|
||||||
RefPtr<EventHandlerNonNull> handlerCallback =
|
RefPtr<EventHandlerNonNull> handlerCallback =
|
||||||
new EventHandlerNonNull(nullptr, handler, /* aIncumbentGlobal = */ nullptr);
|
new EventHandlerNonNull(static_cast<JSContext*>(nullptr), handler,
|
||||||
|
handlerGlobal,
|
||||||
|
/* aIncumbentGlobal = */ nullptr);
|
||||||
jsEventHandler->SetHandler(handlerCallback);
|
jsEventHandler->SetHandler(handlerCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,8 +291,9 @@ ToEventListener(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
|
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
|
||||||
|
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||||
RefPtr<EventListener> listener =
|
RefPtr<EventListener> listener =
|
||||||
new EventListener(aCx, obj, GetIncumbentGlobal());
|
new EventListener(aCx, obj, global, GetIncumbentGlobal());
|
||||||
return listener.forget();
|
return listener.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -377,7 +377,9 @@ nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
|
||||||
NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
RefPtr<EventHandlerNonNull> handlerCallback =
|
RefPtr<EventHandlerNonNull> handlerCallback =
|
||||||
new EventHandlerNonNull(nullptr, bound, /* aIncumbentGlobal = */ nullptr);
|
new EventHandlerNonNull(static_cast<JSContext*>(nullptr), bound,
|
||||||
|
scopeObject,
|
||||||
|
/* aIncumbentGlobal = */ nullptr);
|
||||||
|
|
||||||
TypedEventHandler typedHandler(handlerCallback);
|
TypedEventHandler typedHandler(handlerCallback);
|
||||||
|
|
||||||
|
|
|
@ -131,8 +131,9 @@ nsSessionStoreUtils::AddDynamicFrameFilteredListener(EventTarget* aTarget,
|
||||||
NS_ENSURE_TRUE(aTarget, NS_ERROR_NO_INTERFACE);
|
NS_ENSURE_TRUE(aTarget, NS_ERROR_NO_INTERFACE);
|
||||||
|
|
||||||
JS::Rooted<JSObject*> obj(aCx, &aListener.toObject());
|
JS::Rooted<JSObject*> obj(aCx, &aListener.toObject());
|
||||||
|
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||||
RefPtr<EventListener> listener =
|
RefPtr<EventListener> listener =
|
||||||
new EventListener(aCx, obj, GetIncumbentGlobal());
|
new EventListener(aCx, obj, global, GetIncumbentGlobal());
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMEventListener> filter(new DynamicFrameEventFilter(listener));
|
nsCOMPtr<nsIDOMEventListener> filter(new DynamicFrameEventFilter(listener));
|
||||||
|
|
||||||
|
|
|
@ -205,10 +205,12 @@ class PromiseJobRunnable final : public MicroTaskRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PromiseJobRunnable(JS::HandleObject aCallback,
|
PromiseJobRunnable(JS::HandleObject aCallback,
|
||||||
|
JS::HandleObject aCallbackGlobal,
|
||||||
JS::HandleObject aAllocationSite,
|
JS::HandleObject aAllocationSite,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
:mCallback(
|
:mCallback(
|
||||||
new PromiseJobCallback(aCallback, aAllocationSite, aIncumbentGlobal))
|
new PromiseJobCallback(aCallback, aCallbackGlobal, aAllocationSite,
|
||||||
|
aIncumbentGlobal))
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(js::IsFunctionObject(aCallback));
|
MOZ_ASSERT(js::IsFunctionObject(aCallback));
|
||||||
}
|
}
|
||||||
|
@ -266,7 +268,10 @@ CycleCollectedJSContext::EnqueuePromiseJobCallback(JSContext* aCx,
|
||||||
if (aIncumbentGlobal) {
|
if (aIncumbentGlobal) {
|
||||||
global = xpc::NativeGlobal(aIncumbentGlobal);
|
global = xpc::NativeGlobal(aIncumbentGlobal);
|
||||||
}
|
}
|
||||||
RefPtr<MicroTaskRunnable> runnable = new PromiseJobRunnable(aJob, aAllocationSite, global);
|
JS::RootedObject jobGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||||
|
RefPtr<MicroTaskRunnable> runnable = new PromiseJobRunnable(aJob, jobGlobal,
|
||||||
|
aAllocationSite,
|
||||||
|
global);
|
||||||
self->DispatchToMicroTask(runnable.forget());
|
self->DispatchToMicroTask(runnable.forget());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче