Bug 1477640 - Make AsyncEventDispatcher(dom::EventTarget* aTarget, dom::Event* aEvent) crash in debug build if aEvent is not safe to be dispatched asynchronously r?smaug
AsyncEventDispatcher(dom::EventTarget* aTarget, dom::Event* aEvent) just stores
aEvent with RefPtr. So, this constructor assumes that aEvent->mEvent is always
allocated by dom::Event or its subclasses. For avoiding some callers use
dom::Event instances which are created with Widget*Event or Internal*Event
in the stack and its DuplicatePrivateData() has never been called, this patch
add MOZ_ASSERT to check if aEvent->mEventIsInternal is true.
MozReview-Commit-ID: FrmUK2pVasu
--- a/dom/events/AsyncEventDispatcher.h
+++ b/dom/events/AsyncEventDispatcher.h
@@ -89,22 +89,31 @@ public:
, mTarget(aTarget)
, mEventMessage(aEventMessage)
, mCanBubble(aCanBubble)
{
mEventType.SetIsVoid(true);
MOZ_ASSERT(mEventMessage != eUnidentifiedEvent);
}
+ /**
+ * aEvent must have been created without Widget*Event and Internal*Event
+ * because this constructor assumes that it's safe to use aEvent
+ * asynchronously (i.e., after all objects allocated in the stack are
+ * destroyed).
+ */
AsyncEventDispatcher(dom::EventTarget* aTarget, dom::Event* aEvent)
: CancelableRunnable("AsyncEventDispatcher")
, mTarget(aTarget)
, mEvent(aEvent)
, mEventMessage(eUnidentifiedEvent)
{
+ MOZ_ASSERT(aEvent->IsSafeToBeDispatchedAsynchronously(),
+ "The DOM event should be created without Widget*Event and Internal*Event "
+ "because if it needs to be safe to be dispatched asynchronously");
}
AsyncEventDispatcher(dom::EventTarget* aTarget, WidgetEvent& aEvent);
NS_IMETHOD Run() override;
nsresult Cancel() override;
nsresult PostDOMEvent();
void RunDOMEventWhenSafe();
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -286,16 +286,24 @@ public:
return mEvent->IsTrusted();
}
bool IsSynthesized() const
{
return mEvent->mFlags.mIsSynthesizedForTests;
}
+ bool IsSafeToBeDispatchedAsynchronously() const
+ {
+ // If mEvent is not created by dom::Event nor its subclasses, its lifetime
+ // is not guaranteed. So, only when mEventIsInternal is true, it's safe
+ // to be dispatched asynchronously.
+ return mEventIsInternal;
+ }
+
double TimeStamp();
EventTarget* GetOriginalTarget() const;
EventTarget* GetExplicitOriginalTarget() const;
EventTarget* GetComposedTarget() const;
/**
* @param aCalledByDefaultHandler Should be true when this is called by