Bug 975419 - Trace the Incumbent Global from a CallbackObject (but check it too, just to be safe). r=bz,mccr8

This commit is contained in:
Bobby Holley 2014-03-03 08:53:42 -08:00
parent a52c7e5aa2
commit b627ef0672
2 changed files with 32 additions and 9 deletions

View File

@ -35,7 +35,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(CallbackObject)
NS_IMPL_CYCLE_COLLECTION_CLASS(CallbackObject)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackObject)
tmp->DropCallback();
tmp->DropJSObjects();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncumbentGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject)
@ -44,6 +44,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mIncumbentJSGlobal)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
@ -122,8 +123,17 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
mAutoEntryScript.construct(globalObject, mIsMainThread, cx);
mAutoEntryScript.ref().SetWebIDLCallerPrincipal(webIDLCallerPrincipal);
if (aCallback->IncumbentGlobalOrNull()) {
mAutoIncumbentScript.construct(aCallback->IncumbentGlobalOrNull());
nsIGlobalObject* incumbent = aCallback->IncumbentGlobalOrNull();
if (incumbent) {
// The callback object traces its incumbent JS global, so in general it
// should be alive here. However, it's possible that we could run afoul
// of the same IPC global weirdness described above, wherein the
// nsIGlobalObject has severed its reference to the JS global. Let's just
// be safe here, so that nobody has to waste a day debugging gaia-ui tests.
if (!incumbent->GetGlobalJSObject()) {
return;
}
mAutoIncumbentScript.construct(incumbent);
}
// Unmark the callable (by invoking Callback() and not the CallbackPreserveColor()

View File

@ -57,7 +57,7 @@ public:
virtual ~CallbackObject()
{
DropCallback();
DropJSObjects();
}
JS::Handle<JSObject*> Callback() const
@ -121,28 +121,41 @@ private:
inline void Init(JSObject* aCallback, nsIGlobalObject* aIncumbentGlobal)
{
MOZ_ASSERT(aCallback && !mCallback);
// Set mCallback before we hold, on the off chance that a GC could somehow
// happen in there... (which would be pretty odd, granted).
// Set script objects before we hold, on the off chance that a GC could
// somehow happen in there... (which would be pretty odd, granted).
mCallback = aCallback;
if (aIncumbentGlobal) {
mIncumbentGlobal = aIncumbentGlobal;
mIncumbentJSGlobal = aIncumbentGlobal->GetGlobalJSObject();
}
mozilla::HoldJSObjects(this);
mIncumbentGlobal = aIncumbentGlobal;
}
CallbackObject(const CallbackObject&) MOZ_DELETE;
CallbackObject& operator =(const CallbackObject&) MOZ_DELETE;
protected:
void DropCallback()
void DropJSObjects()
{
MOZ_ASSERT_IF(mIncumbentJSGlobal, mCallback);
if (mCallback) {
mCallback = nullptr;
mIncumbentJSGlobal = nullptr;
mozilla::DropJSObjects(this);
}
}
JS::Heap<JSObject*> mCallback;
// Ideally, we'd just hold a reference to the nsIGlobalObject, since that's
// what we need to pass to AutoIncumbentScript. Unfortunately, that doesn't
// hold the actual JS global alive. So we maintain an additional pointer to
// the JS global itself so that we can trace it.
//
// At some point we should consider trying to make native globals hold their
// scripted global alive, at which point we can get rid of the duplication
// here.
nsCOMPtr<nsIGlobalObject> mIncumbentGlobal;
JS::TenuredHeap<JSObject*> mIncumbentJSGlobal;
class MOZ_STACK_CLASS CallSetup
{