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 draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 24 Jul 2018 14:51:32 +0900
changeset 821901 8ed4cffa67a937969835e002b04ae0875e481957
parent 821900 2569a77233168ef94a1bfb38379391f871a5a8b2
push id117214
push usermasayuki@d-toybox.com
push dateTue, 24 Jul 2018 07:25:21 +0000
reviewerssmaug
bugs1477640
milestone63.0a1
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
dom/events/AsyncEventDispatcher.h
dom/events/Event.h
--- 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