Bug 1326194 - Properly unlink observed targets. m=mrbkap r=mrbkap
authorTobias Schneider <schneider@jancona.com>
Thu, 19 Jan 2017 14:51:09 -0800
changeset 377486 cdce2c9a89c4c0e84b6675aed9814b03a3bc51af
parent 377485 79e4c3c3f793ecd3e7fdd35c96a55eb1fe406838
child 377487 e393454e52860f106d5a28d1877382393d3213d1
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1326194
milestone53.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 1326194 - Properly unlink observed targets. m=mrbkap r=mrbkap MozReview-Commit-ID: EWk3kcoIteE
dom/base/crashtests/1326194-1.html
dom/base/crashtests/1326194-2.html
dom/base/crashtests/crashtests.list
dom/base/nsNodeUtils.cpp
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1326194-1.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script type="application/javascript">
+
+// Crashes if 'target' doesn't get properly unlinked in nsNodeUtils::LastRelease
+
+function crash() {
+	var target = document.getElementById('target');
+	var io = new IntersectionObserver(function () { }, { });
+	io.observe(target);
+	document.body.removeChild(target);
+}
+
+</script>
+</head>
+<body onload="crash()">
+	<div id="target" style="background: red; width: 50px; height: 50px"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1326194-2.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script type="application/javascript">
+
+// Crashes if 'target' doesn't get properly unlinked in FragmentOrElement::Unlink
+
+function crash() {
+	var target = document.createElement('div');
+	// By setting a custom prop we create a cycle between JS and C++ that requires the CC to break.
+	target.foo = 'bar';
+	var io = new IntersectionObserver(function () { }, { });
+	io.observe(target);
+}
+
+</script>
+</head>
+<body onload="crash()">
+</body>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -204,8 +204,10 @@ 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
+pref(dom.IntersectionObserver.enabled,true) load 1326194-1.html
+pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -292,16 +292,26 @@ 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 iter = domSlots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
+        DOMIntersectionObserver* observer = iter.Key();
+        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