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
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 24 Jul 2018 14:51:32 +0900
changeset 428016 f2a5ae30413b0bb9dbe827b3446025e633cf51db
parent 428015 5c1bb5087c9daa0cf29e5848e2cd8e87ecf14458
child 428017 51abf3731a71737a336d196b2f004f18b49edff9
push id34324
push usernbeleuzu@mozilla.com
push dateTue, 24 Jul 2018 22:19:28 +0000
treeherdermozilla-central@dd386b5b9fa7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1477640
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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