Bug 1315837 - Fix crash in mozilla::dom::Element::UpdateIntersectionObservation. r=mrbkap
authorTobias Schneider <tschneider@mozilla.com>
Wed, 09 Nov 2016 09:10:00 -0500
changeset 349001 63cafb0c2f0ff94ef9a9b99fad972566b6847cb2
parent 349000 ae039aa6accf827582bf6d3fbee5760d5950e88e
child 349002 b9867579cf623cd1396fee24d18179a149399e92
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1315837
milestone52.0a1
Bug 1315837 - Fix crash in mozilla::dom::Element::UpdateIntersectionObservation. r=mrbkap
dom/base/DOMIntersectionObserver.cpp
dom/base/DOMIntersectionObserver.h
dom/base/nsNodeUtils.cpp
--- a/dom/base/DOMIntersectionObserver.cpp
+++ b/dom/base/DOMIntersectionObserver.cpp
@@ -154,25 +154,33 @@ DOMIntersectionObserver::Observe(Element
   aTarget.RegisterIntersectionObserver(this);
   mObservationTargets.PutEntry(&aTarget);
   Connect();
 }
 
 void
 DOMIntersectionObserver::Unobserve(Element& aTarget)
 {
-  if (!mObservationTargets.Contains(&aTarget)) {
-    return;
+  if (UnlinkTarget(aTarget)) {
+    aTarget.UnregisterIntersectionObserver(this);
   }
-  if (mObservationTargets.Count() == 1) {
-    Disconnect();
-    return;
-  }
-  aTarget.UnregisterIntersectionObserver(this);
-  mObservationTargets.RemoveEntry(&aTarget);
+}
+
+bool
+DOMIntersectionObserver::UnlinkTarget(Element& aTarget)
+{
+    if (!mObservationTargets.Contains(&aTarget)) {
+        return false;
+    }
+    if (mObservationTargets.Count() == 1) {
+        Disconnect();
+        return false;
+    }
+    mObservationTargets.RemoveEntry(&aTarget);
+    return true;
 }
 
 void
 DOMIntersectionObserver::Connect()
 {
   if (mConnected) {
     return;
   }
@@ -187,18 +195,20 @@ DOMIntersectionObserver::Disconnect()
   if (!mConnected) {
     return;
   }
   for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) {
     Element* target = iter.Get()->GetKey();
     target->UnregisterIntersectionObserver(this);
   }
   mObservationTargets.Clear();
-  nsIDocument* document = mOwner->GetExtantDoc();
-  document->RemoveIntersectionObserver(this);
+  if (mOwner) {
+    nsIDocument* document = mOwner->GetExtantDoc();
+    document->RemoveIntersectionObserver(this);
+  }
   mConnected = false;
 }
 
 void
 DOMIntersectionObserver::TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal)
 {
   aRetVal.SwapElements(mQueuedEntries);
   mQueuedEntries.Clear();
--- a/dom/base/DOMIntersectionObserver.h
+++ b/dom/base/DOMIntersectionObserver.h
@@ -137,17 +137,19 @@ public:
     return mRoot;
   }
 
   void GetRootMargin(mozilla::dom::DOMString& aRetVal);
   void GetThresholds(nsTArray<double>& aRetVal);
   void Observe(Element& aTarget);
   void Unobserve(Element& aTarget);
 
+  bool UnlinkTarget(Element& aTarget);
   void Disconnect();
+
   void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
 
   mozilla::dom::IntersectionCallback* IntersectionCallback() { return mCallback; }
 
   bool SetRootMargin(const nsAString& aString);
 
   void Update(nsIDocument* aDocument, DOMHighResTimeStamp time);
   void Notify();
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -292,16 +292,25 @@ nsNodeUtils::LastRelease(nsINode* aNode)
   nsINode::nsSlots* slots = aNode->GetExistingSlots();
   if (slots) {
     if (!slots->mMutationObservers.IsEmpty()) {
       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
                                          nsIMutationObserver,
                                          NodeWillBeDestroyed, (aNode));
     }
 
+    if (aNode->IsElement()) {
+      Element* elem = aNode->AsElement();
+      FragmentOrElement::nsDOMSlots* domSlots =
+        static_cast<FragmentOrElement::nsDOMSlots*>(slots);
+      for (auto& reg : domSlots->mRegisteredIntersectionObservers) {
+        reg.observer->UnlinkTarget(*elem);
+      }
+    }
+
     delete slots;
     aNode->mSlots = nullptr;
   }
 
   // Kill properties first since that may run external code, so we want to
   // be in as complete state as possible at that time.
   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     // Delete all properties before tearing down the document. Some of the