Bug 1385272 - Make plaintext serializer not crash when a <tr> is a child of a <tr>. r=Ehsan draft
authorHenri Sivonen <hsivonen@hsivonen.fi>
Mon, 14 Aug 2017 14:24:51 +0300
changeset 646588 98c7d1fe21a7559aa39e5c1b5b696298cfae50d2
parent 645835 72d456d328c7c3c9c0da55a42558ed42bbda7fc1
child 726298 2b04a3881616c37bd867f61b083486c5815c7e88
push id74180
push userbmo:hsivonen@hsivonen.fi
push dateTue, 15 Aug 2017 14:29:27 +0000
reviewersEhsan
bugs1385272
milestone57.0a1
Bug 1385272 - Make plaintext serializer not crash when a <tr> is a child of a <tr>. r=Ehsan MozReview-Commit-ID: CMNIWYX8R07
dom/base/crashtests/1385272-1.html
dom/base/crashtests/crashtests.list
dom/base/nsDocumentEncoder.cpp
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1385272-1.html
@@ -0,0 +1,29 @@
+<html>
+    <head>
+       <script>
+            try { o1 = document.createElement("tr") } catch(e) { }
+            try { o2 = document.createElement("td") } catch(e) { }
+            try { o3 = document.createElement("tr") } catch(e) { }
+            try { o4 = document.createElement("div") } catch(e) { }
+            try { o5 = document.createElement("input") } catch(e) { }
+            try { o6 = document.createElement('map') } catch(e) { }
+            try { o7 = document.createElement('select') } catch(e) { }
+            try { o8 = document.createElement("canvas") } catch(e) { }
+            try { o9 = document.createElement("area") } catch(e) { };
+            try { o1.appendChild(o2) } catch(e) { }
+            try { document.documentElement.appendChild(o3)  } catch(e) { }
+            try { document.documentElement.appendChild(o4)  } catch(e) { }
+            try { document.documentElement.appendChild(o6) } catch(e) { }
+            try { o3.appendChild(o7) } catch(e) { }
+            try { o4.appendChild(o8) } catch(e) { }
+            try { o3.appendChild(o5); } catch(e) { }
+            try { o3.appendChild(o1); } catch(e) { }
+            try { o6.contentEditable = "true" } catch(e) { };
+            try { o6.offsetHeight } catch(e) { };
+            try { o4.appendChild(o9) } catch(e) { };
+            try { o2.insertAdjacentHTML("beforeBegin", "<button id='id0'></button>\n"); } catch(e) { }
+            try { document.replaceChild(document.documentElement, document.documentElement); } catch(e) { }
+            try { document.execCommand("selectall",false,null) } catch(e) { }
+        </script>
+    </head>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -216,8 +216,9 @@ pref(clipboard.autocopy,true) load 13707
 pref(dom.IntersectionObserver.enabled,true) load 1370968.html
 load 1377826.html
 skip-if(stylo&&isDebugBuild&&winWidget) load structured_clone_container_throws.html # Bug 1383845
 HTTP(..) load xhr_abortinprogress.html
 load xhr_empty_datauri.html
 load xhr_html_nullresponse.html
 load 1383478.html
 load 1383780.html
+pref(clipboard.autocopy,true) load 1385272-1.html
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -1013,16 +1013,24 @@ nsDocumentEncoder::Clear()
 }
 
 NS_IMETHODIMP
 nsDocumentEncoder::EncodeToString(nsAString& aOutputString)
 {
   return EncodeToStringWithMaxLength(0, aOutputString);
 }
 
+static bool ParentIsTR(nsIContent* aContent) {
+  mozilla::dom::Element* parent = aContent->GetParentElement();
+  if (!parent) {
+    return false;
+  }
+  return parent->IsHTMLElement(nsGkAtoms::tr);
+}
+
 NS_IMETHODIMP
 nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
                                                nsAString& aOutputString)
 {
   if (!mDocument)
     return NS_ERROR_NOT_INITIALIZED;
 
   AutoReleaseDocumentIfNeeded autoReleaseDocument(this);
@@ -1083,17 +1091,17 @@ nsDocumentEncoder::EncodeToStringWithMax
       if (node != prevNode) {
         nsCOMPtr<nsINode> p;
         if (prevNode) {
           p = do_QueryInterface(prevNode);
           rv = SerializeNodeEnd(p, output);
           NS_ENSURE_SUCCESS(rv, rv);
         }
         nsCOMPtr<nsIContent> content = do_QueryInterface(node);
-        if (content && content->IsHTMLElement(nsGkAtoms::tr)) {
+        if (content && content->IsHTMLElement(nsGkAtoms::tr) && !ParentIsTR(content)) {
           nsINode* n = content;
           if (!prevNode) {
             // Went from a non-<tr> to a <tr>
             mCommonAncestors.Clear();
             nsContentUtils::GetAncestors(n->GetParentNode(), mCommonAncestors);
             rv = SerializeRangeContextStart(mCommonAncestors, output);
             NS_ENSURE_SUCCESS(rv, rv);
             // Don't let SerializeRangeToString serialize the context again