Bug 1324209 - Safely iterate over mIntersectionObservers in nsDocument::NotifyIntersectionObservers. r?mstange draft
authorTobias Schneider <schneider@jancona.com>
Tue, 20 Dec 2016 16:02:57 -0800
changeset 451776 89f693ab899f2c30dd452e9d15fcd7512b95440c
parent 451656 7083c0d30e75fc102c715887af9faec933e936f8
child 540128 60757ff7e57db69566d68fd26d5d00a312b736c3
push id39292
push userbmo:tschneider@mozilla.com
push dateWed, 21 Dec 2016 00:03:28 +0000
reviewersmstange
bugs1324209
milestone53.0a1
Bug 1324209 - Safely iterate over mIntersectionObservers in nsDocument::NotifyIntersectionObservers. r?mstange MozReview-Commit-ID: KxKbhbaS2gA
dom/base/DOMIntersectionObserver.cpp
dom/base/crashtests/1324209.html
dom/base/crashtests/crashtests.list
dom/base/nsDocument.cpp
--- a/dom/base/DOMIntersectionObserver.cpp
+++ b/dom/base/DOMIntersectionObserver.cpp
@@ -202,17 +202,19 @@ DOMIntersectionObserver::Disconnect()
   mConnected = false;
   for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) {
     Element* target = iter.Get()->GetKey();
     target->UnregisterIntersectionObserver(this);
   }
   mObservationTargets.Clear();
   if (mOwner) {
     nsIDocument* document = mOwner->GetExtantDoc();
-    document->RemoveIntersectionObserver(this);
+    if (document) {
+      document->RemoveIntersectionObserver(this);
+    }
   }
 }
 
 void
 DOMIntersectionObserver::TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal)
 {
   aRetVal.SwapElements(mQueuedEntries);
   mQueuedEntries.Clear();
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1324209.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script type="application/javascript">
+
+function crash() {
+	var target1 = document.getElementById("target1");
+	var target2 = document.getElementById("target2");
+	var observer1 = new IntersectionObserver(function (entries) {
+	  console.log(entries);
+	  observer1.disconnect();
+	  observer2.disconnect();
+	});
+	var observer2 = new IntersectionObserver(function (entries) {
+	  console.log(entries); 
+	});
+	observer1.observe(target1);
+	observer2.observe(target2);
+}
+
+</script>
+</head>
+<body onload="crash()">
+	<div id="target1" style="background: red; width: 50px; height: 50px"></div>
+	<div id="target2" style="background: green; width: 50px; height: 50px"></div>
+</body>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -203,8 +203,9 @@ load 1158412.html
 load 1181619.html
 load structured_clone_container_throws.html
 HTTP(..) load xhr_abortinprogress.html
 load xhr_empty_datauri.html
 load xhr_html_nullresponse.html
 load 1230422.html
 load 1251361.html
 load 1304437.html
+pref(dom.IntersectionObserver.enabled,true) load 1324209.html
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12390,17 +12390,18 @@ nsDocument::ScheduleIntersectionObserver
   nsCOMPtr<nsIRunnable> notification = NewRunnableMethod(this,
     &nsDocument::NotifyIntersectionObservers);
   NS_DispatchToCurrentThread(notification);
 }
 
 void
 nsDocument::NotifyIntersectionObservers()
 {
-  for (const auto& observer : mIntersectionObservers) {
+  nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers);
+  for (const auto& observer : observers) {
     observer->Notify();
   }
 }
 
 static bool
 NotifyLayerManagerRecreatedCallback(nsIDocument* aDocument, void* aData)
 {
   aDocument->NotifyLayerManagerRecreated();