Bug 591330 - Make deep nesting prevention code in the HTML5 parser not crash when there are speculations involved. r=jonas, a=blocking2.0-betaN.
authorHenri Sivonen <hsivonen@iki.fi>
Mon, 06 Sep 2010 10:41:26 +0300
changeset 53890 729107825a4803abe6ad7ce9a49a31e1edf3adc6
parent 53889 6dfa6a7c94e04fb7da5d918ce3e4bac32c779bac
child 53891 634290477871d0063a819ecef477708a296bc543
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonas, blocking2.0-betaN
bugs591330
milestone2.0b7pre
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 591330 - Make deep nesting prevention code in the HTML5 parser not crash when there are speculations involved. r=jonas, a=blocking2.0-betaN.
parser/html/javasrc/StateSnapshot.java
parser/html/javasrc/TreeBuilder.java
parser/html/nsAHtml5TreeBuilderState.h
parser/html/nsHtml5StateSnapshot.cpp
parser/html/nsHtml5StateSnapshot.h
parser/html/nsHtml5TreeBuilder.cpp
parser/html/nsHtml5TreeBuilder.h
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/htmlparser/tests/crashtests/591330-1.html
parser/htmlparser/tests/crashtests/crashtests.list
--- a/parser/html/javasrc/StateSnapshot.java
+++ b/parser/html/javasrc/StateSnapshot.java
@@ -28,16 +28,18 @@ public class StateSnapshot<T> implements
     private final StackNode<T>[] stack;
 
     private final StackNode<T>[] listOfActiveFormattingElements;
 
     private final T formPointer;
 
     private final T headPointer;
 
+    private final T deepTreeSurrogateParent;
+
     private final int mode;
 
     private final int originalMode;
     
     private final boolean framesetOk;
 
     private final boolean inForeign;
 
@@ -51,21 +53,22 @@ public class StateSnapshot<T> implements
      * @param formPointer
      * @param quirks 
      * @param needToDropLF 
      * @param foreignFlag 
      * @param originalMode 
      * @param mode 
      */
     StateSnapshot(StackNode<T>[] stack,
-            StackNode<T>[] listOfActiveFormattingElements, T formPointer, T headPointer, int mode, int originalMode, boolean framesetOk, boolean inForeign, boolean needToDropLF, boolean quirks) {
+            StackNode<T>[] listOfActiveFormattingElements, T formPointer, T headPointer, T deepTreeSurrogateParent, int mode, int originalMode, boolean framesetOk, boolean inForeign, boolean needToDropLF, boolean quirks) {
         this.stack = stack;
         this.listOfActiveFormattingElements = listOfActiveFormattingElements;
         this.formPointer = formPointer;
         this.headPointer = headPointer;
+        this.deepTreeSurrogateParent = deepTreeSurrogateParent;
         this.mode = mode;
         this.originalMode = originalMode;
         this.framesetOk = framesetOk;
         this.inForeign = inForeign;
         this.needToDropLF = needToDropLF;
         this.quirks = quirks;
     }
     
@@ -95,16 +98,25 @@ public class StateSnapshot<T> implements
      * 
      * @return the headPointer
      */
     public T getHeadPointer() {
         return headPointer;
     }
 
     /**
+     * Returns the deepTreeSurrogateParent.
+     * 
+     * @return the deepTreeSurrogateParent
+     */
+    public T getDeepTreeSurrogateParent() {
+        return deepTreeSurrogateParent;
+    }
+    
+    /**
      * Returns the mode.
      * 
      * @return the mode
      */
     public int getMode() {
         return mode;
     }
 
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -390,16 +390,21 @@ public abstract class TreeBuilder<T> imp
     private StackNode<T>[] listOfActiveFormattingElements;
 
     private int listPtr = -1;
 
     private T formPointer;
 
     private T headPointer;
 
+    /**
+     * Used to work around Gecko limitations. Not used in Java.
+     */
+    private T deepTreeSurrogateParent;
+
     protected char[] charBuffer;
 
     protected int charBufferLen = 0;
 
     private boolean quirks = false;
 
     // [NOCPP[
 
@@ -502,16 +507,18 @@ public abstract class TreeBuilder<T> imp
         needToDropLF = false;
         originalMode = INITIAL;
         currentPtr = -1;
         listPtr = -1;
         Portability.releaseElement(formPointer);
         formPointer = null;
         Portability.releaseElement(headPointer);
         headPointer = null;
+        Portability.releaseElement(deepTreeSurrogateParent);
+        deepTreeSurrogateParent = null;
         // [NOCPP[
         html4 = false;
         idLocations.clear();
         wantingComments = wantsComments();
         // ]NOCPP]
         start(fragment);
         charBufferLen = 0;
         charBuffer = new char[1024];
@@ -1386,16 +1393,18 @@ public abstract class TreeBuilder<T> imp
     /**
      * @see nu.validator.htmlparser.common.TokenHandler#endTokenization()
      */
     public final void endTokenization() throws SAXException {
         Portability.releaseElement(formPointer);
         formPointer = null;
         Portability.releaseElement(headPointer);
         headPointer = null;
+        Portability.releaseElement(deepTreeSurrogateParent);
+        deepTreeSurrogateParent = null;
         if (stack != null) {
             while (currentPtr > -1) {
                 stack[currentPtr].release();
                 currentPtr--;
             }
             Portability.releaseArray(stack);
             stack = null;
         }
@@ -5352,29 +5361,30 @@ public abstract class TreeBuilder<T> imp
                         null);
                 stackCopy[i] = newNode;
             } else {
                 stackCopy[i] = listCopy[listIndex];
                 stackCopy[i].retain();
             }
         }
         Portability.retainElement(formPointer);
-        return new StateSnapshot<T>(stackCopy, listCopy, formPointer, headPointer, mode, originalMode, framesetOk, inForeign, needToDropLF, quirks);
+        return new StateSnapshot<T>(stackCopy, listCopy, formPointer, headPointer, deepTreeSurrogateParent, mode, originalMode, framesetOk, inForeign, needToDropLF, quirks);
     }
 
     public boolean snapshotMatches(TreeBuilderState<T> snapshot) {
         StackNode<T>[] stackCopy = snapshot.getStack();
         int stackLen = snapshot.getStackLength();
         StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements();
         int listLen = snapshot.getListOfActiveFormattingElementsLength();
 
         if (stackLen != currentPtr + 1
                 || listLen != listPtr + 1
                 || formPointer != snapshot.getFormPointer()
                 || headPointer != snapshot.getHeadPointer()
+                || deepTreeSurrogateParent != snapshot.getDeepTreeSurrogateParent()
                 || mode != snapshot.getMode()
                 || originalMode != snapshot.getOriginalMode()
                 || framesetOk != snapshot.isFramesetOk()
                 || inForeign != snapshot.isInForeign()
                 || needToDropLF != snapshot.isNeedToDropLF()
                 || quirks != snapshot.isQuirks()) { // maybe just assert quirks
             return false;
         }
@@ -5456,16 +5466,19 @@ public abstract class TreeBuilder<T> imp
             }
         }
         Portability.releaseElement(formPointer);
         formPointer = snapshot.getFormPointer();
         Portability.retainElement(formPointer);
         Portability.releaseElement(headPointer);
         headPointer = snapshot.getHeadPointer();
         Portability.retainElement(headPointer);
+        Portability.releaseElement(deepTreeSurrogateParent);
+        deepTreeSurrogateParent = snapshot.getDeepTreeSurrogateParent();
+        Portability.retainElement(deepTreeSurrogateParent);
         mode = snapshot.getMode();
         originalMode = snapshot.getOriginalMode();
         framesetOk = snapshot.isFramesetOk();
         inForeign = snapshot.isInForeign();
         needToDropLF = snapshot.isNeedToDropLF();
         quirks = snapshot.isQuirks();
     }
 
@@ -5490,16 +5503,25 @@ public abstract class TreeBuilder<T> imp
      * 
      * @return the headPointer
      */
     public T getHeadPointer() {
         return headPointer;
     }
     
     /**
+     * Returns the deepTreeSurrogateParent.
+     * 
+     * @return the deepTreeSurrogateParent
+     */
+    public T getDeepTreeSurrogateParent() {
+        return deepTreeSurrogateParent;
+    }
+
+    /**
      * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElements()
      */
     public StackNode<T>[] getListOfActiveFormattingElements() {
         return listOfActiveFormattingElements;
     }
 
     /**
      * @see nu.validator.htmlparser.impl.TreeBuilderState#getStack()
--- a/parser/html/nsAHtml5TreeBuilderState.h
+++ b/parser/html/nsAHtml5TreeBuilderState.h
@@ -53,16 +53,18 @@ class nsAHtml5TreeBuilderState {
     virtual PRInt32 getStackLength() = 0;
 
     virtual PRInt32 getListOfActiveFormattingElementsLength() = 0;
 
     virtual nsIContent** getFormPointer() = 0;
     
     virtual nsIContent** getHeadPointer() = 0;
 
+    virtual nsIContent** getDeepTreeSurrogateParent() = 0;
+
     virtual PRInt32 getMode() = 0;
 
     virtual PRInt32 getOriginalMode() = 0;
 
     virtual PRBool isFramesetOk() = 0;
 
     virtual PRBool isInForeign() = 0;
 
--- a/parser/html/nsHtml5StateSnapshot.cpp
+++ b/parser/html/nsHtml5StateSnapshot.cpp
@@ -54,21 +54,22 @@
 #include "nsHtml5HtmlAttributes.h"
 #include "nsHtml5StackNode.h"
 #include "nsHtml5UTF16Buffer.h"
 #include "nsHtml5Portability.h"
 
 #include "nsHtml5StateSnapshot.h"
 
 
-nsHtml5StateSnapshot::nsHtml5StateSnapshot(jArray<nsHtml5StackNode*,PRInt32> stack, jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements, nsIContent** formPointer, nsIContent** headPointer, PRInt32 mode, PRInt32 originalMode, PRBool framesetOk, PRBool inForeign, PRBool needToDropLF, PRBool quirks)
+nsHtml5StateSnapshot::nsHtml5StateSnapshot(jArray<nsHtml5StackNode*,PRInt32> stack, jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements, nsIContent** formPointer, nsIContent** headPointer, nsIContent** deepTreeSurrogateParent, PRInt32 mode, PRInt32 originalMode, PRBool framesetOk, PRBool inForeign, PRBool needToDropLF, PRBool quirks)
   : stack(stack),
     listOfActiveFormattingElements(listOfActiveFormattingElements),
     formPointer(formPointer),
     headPointer(headPointer),
+    deepTreeSurrogateParent(deepTreeSurrogateParent),
     mode(mode),
     originalMode(originalMode),
     framesetOk(framesetOk),
     inForeign(inForeign),
     needToDropLF(needToDropLF),
     quirks(quirks)
 {
   MOZ_COUNT_CTOR(nsHtml5StateSnapshot);
@@ -93,16 +94,22 @@ nsHtml5StateSnapshot::getFormPointer()
 }
 
 nsIContent** 
 nsHtml5StateSnapshot::getHeadPointer()
 {
   return headPointer;
 }
 
+nsIContent** 
+nsHtml5StateSnapshot::getDeepTreeSurrogateParent()
+{
+  return deepTreeSurrogateParent;
+}
+
 PRInt32 
 nsHtml5StateSnapshot::getMode()
 {
   return mode;
 }
 
 PRInt32 
 nsHtml5StateSnapshot::getOriginalMode()
--- a/parser/html/nsHtml5StateSnapshot.h
+++ b/parser/html/nsHtml5StateSnapshot.h
@@ -61,28 +61,30 @@ class nsHtml5Portability;
 
 class nsHtml5StateSnapshot : public nsAHtml5TreeBuilderState
 {
   private:
     jArray<nsHtml5StackNode*,PRInt32> stack;
     jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements;
     nsIContent** formPointer;
     nsIContent** headPointer;
+    nsIContent** deepTreeSurrogateParent;
     PRInt32 mode;
     PRInt32 originalMode;
     PRBool framesetOk;
     PRBool inForeign;
     PRBool needToDropLF;
     PRBool quirks;
   public:
-    nsHtml5StateSnapshot(jArray<nsHtml5StackNode*,PRInt32> stack, jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements, nsIContent** formPointer, nsIContent** headPointer, PRInt32 mode, PRInt32 originalMode, PRBool framesetOk, PRBool inForeign, PRBool needToDropLF, PRBool quirks);
+    nsHtml5StateSnapshot(jArray<nsHtml5StackNode*,PRInt32> stack, jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements, nsIContent** formPointer, nsIContent** headPointer, nsIContent** deepTreeSurrogateParent, PRInt32 mode, PRInt32 originalMode, PRBool framesetOk, PRBool inForeign, PRBool needToDropLF, PRBool quirks);
     jArray<nsHtml5StackNode*,PRInt32> getStack();
     jArray<nsHtml5StackNode*,PRInt32> getListOfActiveFormattingElements();
     nsIContent** getFormPointer();
     nsIContent** getHeadPointer();
+    nsIContent** getDeepTreeSurrogateParent();
     PRInt32 getMode();
     PRInt32 getOriginalMode();
     PRBool isFramesetOk();
     PRBool isInForeign();
     PRBool isNeedToDropLF();
     PRBool isQuirks();
     PRInt32 getListOfActiveFormattingElementsLength();
     PRInt32 getStackLength();
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -74,16 +74,18 @@ nsHtml5TreeBuilder::startTokenization(ns
   needToDropLF = PR_FALSE;
   originalMode = NS_HTML5TREE_BUILDER_INITIAL;
   currentPtr = -1;
   listPtr = -1;
   ;
   formPointer = nsnull;
   ;
   headPointer = nsnull;
+  ;
+  deepTreeSurrogateParent = nsnull;
   start(fragment);
   charBufferLen = 0;
   charBuffer = jArray<PRUnichar,PRInt32>(1024);
   framesetOk = PR_TRUE;
   if (fragment) {
     nsIContent** elt;
     if (contextNode) {
       elt = contextNode;
@@ -527,16 +529,18 @@ nsHtml5TreeBuilder::eof()
 
 void 
 nsHtml5TreeBuilder::endTokenization()
 {
   ;
   formPointer = nsnull;
   ;
   headPointer = nsnull;
+  ;
+  deepTreeSurrogateParent = nsnull;
   if (stack) {
     while (currentPtr > -1) {
       stack[currentPtr]->release();
       currentPtr--;
     }
     stack.release();
     stack = nsnull;
   }
@@ -3806,27 +3810,27 @@ nsHtml5TreeBuilder::newSnapshot()
       nsHtml5StackNode* newNode = new nsHtml5StackNode(node->group, node->ns, node->name, node->node, node->scoping, node->special, node->fosterParenting, node->popName, nsnull);
       stackCopy[i] = newNode;
     } else {
       stackCopy[i] = listCopy[listIndex];
       stackCopy[i]->retain();
     }
   }
   ;
-  return new nsHtml5StateSnapshot(stackCopy, listCopy, formPointer, headPointer, mode, originalMode, framesetOk, inForeign, needToDropLF, quirks);
+  return new nsHtml5StateSnapshot(stackCopy, listCopy, formPointer, headPointer, deepTreeSurrogateParent, mode, originalMode, framesetOk, inForeign, needToDropLF, quirks);
 }
 
 PRBool 
 nsHtml5TreeBuilder::snapshotMatches(nsAHtml5TreeBuilderState* snapshot)
 {
   jArray<nsHtml5StackNode*,PRInt32> stackCopy = snapshot->getStack();
   PRInt32 stackLen = snapshot->getStackLength();
   jArray<nsHtml5StackNode*,PRInt32> listCopy = snapshot->getListOfActiveFormattingElements();
   PRInt32 listLen = snapshot->getListOfActiveFormattingElementsLength();
-  if (stackLen != currentPtr + 1 || listLen != listPtr + 1 || formPointer != snapshot->getFormPointer() || headPointer != snapshot->getHeadPointer() || mode != snapshot->getMode() || originalMode != snapshot->getOriginalMode() || framesetOk != snapshot->isFramesetOk() || inForeign != snapshot->isInForeign() || needToDropLF != snapshot->isNeedToDropLF() || quirks != snapshot->isQuirks()) {
+  if (stackLen != currentPtr + 1 || listLen != listPtr + 1 || formPointer != snapshot->getFormPointer() || headPointer != snapshot->getHeadPointer() || deepTreeSurrogateParent != snapshot->getDeepTreeSurrogateParent() || mode != snapshot->getMode() || originalMode != snapshot->getOriginalMode() || framesetOk != snapshot->isFramesetOk() || inForeign != snapshot->isInForeign() || needToDropLF != snapshot->isNeedToDropLF() || quirks != snapshot->isQuirks()) {
     return PR_FALSE;
   }
   for (PRInt32 i = listLen - 1; i >= 0; i--) {
     if (!listCopy[i] && !listOfActiveFormattingElements[i]) {
       continue;
     } else if (!listCopy[i] || !listOfActiveFormattingElements[i]) {
       return PR_FALSE;
     }
@@ -3888,16 +3892,19 @@ nsHtml5TreeBuilder::loadState(nsAHtml5Tr
     }
   }
   ;
   formPointer = snapshot->getFormPointer();
   ;
   ;
   headPointer = snapshot->getHeadPointer();
   ;
+  ;
+  deepTreeSurrogateParent = snapshot->getDeepTreeSurrogateParent();
+  ;
   mode = snapshot->getMode();
   originalMode = snapshot->getOriginalMode();
   framesetOk = snapshot->isFramesetOk();
   inForeign = snapshot->isInForeign();
   needToDropLF = snapshot->isNeedToDropLF();
   quirks = snapshot->isQuirks();
 }
 
@@ -3919,16 +3926,22 @@ nsHtml5TreeBuilder::getFormPointer()
 }
 
 nsIContent** 
 nsHtml5TreeBuilder::getHeadPointer()
 {
   return headPointer;
 }
 
+nsIContent** 
+nsHtml5TreeBuilder::getDeepTreeSurrogateParent()
+{
+  return deepTreeSurrogateParent;
+}
+
 jArray<nsHtml5StackNode*,PRInt32> 
 nsHtml5TreeBuilder::getListOfActiveFormattingElements()
 {
   return listOfActiveFormattingElements;
 }
 
 jArray<nsHtml5StackNode*,PRInt32> 
 nsHtml5TreeBuilder::getStack()
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -85,16 +85,17 @@ class nsHtml5TreeBuilder : public nsAHtm
     PRInt32 contextNamespace;
     nsIContent** contextNode;
     jArray<nsHtml5StackNode*,PRInt32> stack;
     PRInt32 currentPtr;
     jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements;
     PRInt32 listPtr;
     nsIContent** formPointer;
     nsIContent** headPointer;
+    nsIContent** deepTreeSurrogateParent;
   protected:
     jArray<PRUnichar,PRInt32> charBuffer;
     PRInt32 charBufferLen;
   private:
     PRBool quirks;
   public:
     void startTokenization(nsHtml5Tokenizer* self);
     void doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, PRBool forceQuirks);
@@ -218,16 +219,17 @@ class nsHtml5TreeBuilder : public nsAHtm
     nsAHtml5TreeBuilderState* newSnapshot();
     PRBool snapshotMatches(nsAHtml5TreeBuilderState* snapshot);
     void loadState(nsAHtml5TreeBuilderState* snapshot, nsHtml5AtomTable* interner);
   private:
     PRInt32 findInArray(nsHtml5StackNode* node, jArray<nsHtml5StackNode*,PRInt32> arr);
   public:
     nsIContent** getFormPointer();
     nsIContent** getHeadPointer();
+    nsIContent** getDeepTreeSurrogateParent();
     jArray<nsHtml5StackNode*,PRInt32> getListOfActiveFormattingElements();
     jArray<nsHtml5StackNode*,PRInt32> getStack();
     PRInt32 getMode();
     PRInt32 getOriginalMode();
     PRBool isFramesetOk();
     PRBool isInForeign();
     PRBool isNeedToDropLF();
     PRBool isQuirks();
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -252,17 +252,17 @@ nsHtml5TreeBuilder::detachFromParent(nsI
   treeOp->Init(eTreeOpDetach, aElement);
 }
 
 void
 nsHtml5TreeBuilder::appendElement(nsIContent** aChild, nsIContent** aParent)
 {
   NS_PRECONDITION(aChild, "Null child");
   NS_PRECONDITION(aParent, "Null parent");
-  if (mDeepTreeSurrogateParent) {
+  if (deepTreeSurrogateParent) {
     return;
   }
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppend, aChild, aParent);
 }
 
 void
@@ -310,17 +310,17 @@ nsHtml5TreeBuilder::appendCharacters(nsI
   NS_PRECONDITION(aParent, "Null parent");
 
   PRUnichar* bufferCopy = new PRUnichar[aLength];
   memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
   
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppendText, bufferCopy, aLength,
-      mDeepTreeSurrogateParent ? mDeepTreeSurrogateParent : aParent);
+      deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendIsindexPrompt(nsIContent** aParent)
 {
   NS_PRECONDITION(aParent, "Null parent");
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
@@ -328,17 +328,17 @@ nsHtml5TreeBuilder::appendIsindexPrompt(
   treeOp->Init(eTreeOpAppendIsindexPrompt, aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendComment(nsIContent** aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
 {
   NS_PRECONDITION(aBuffer, "Null buffer");
   NS_PRECONDITION(aParent, "Null parent");
-  if (mDeepTreeSurrogateParent) {
+  if (deepTreeSurrogateParent) {
     return;
   }
 
   PRUnichar* bufferCopy = new PRUnichar[aLength];
   memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
   
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   NS_ASSERTION(treeOp, "Tree op allocation failed.");
@@ -381,17 +381,17 @@ nsHtml5TreeBuilder::markMalformedIfScrip
   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
 }
 
 void
 nsHtml5TreeBuilder::start(PRBool fragment)
 {
   mCurrentHtmlScriptIsAsyncOrDefer = PR_FALSE;
-  mDeepTreeSurrogateParent = nsnull;
+  deepTreeSurrogateParent = nsnull;
 #ifdef DEBUG
   mActive = PR_TRUE;
 #endif
 }
 
 void
 nsHtml5TreeBuilder::end()
 {
@@ -433,26 +433,26 @@ nsHtml5TreeBuilder::elementPushed(PRInt3
    * element that was seen before a magic tree builder stack threshold was
    * reached and element and comment nodes aren't appended to the DOM at all.
    *
    * However, for security reasons, non-child descendant text nodes inside an
    * SVG script or style element should not become children. Also, non-cell
    * table elements shouldn't be used as surrogate parents for user experience
    * reasons.
    */
-  if (!mDeepTreeSurrogateParent && currentPtr >= NS_HTML5_TREE_DEPTH_LIMIT &&
+  if (!deepTreeSurrogateParent && currentPtr >= NS_HTML5_TREE_DEPTH_LIMIT &&
       !(aName == nsHtml5Atoms::script ||
         aName == nsHtml5Atoms::table ||
         aName == nsHtml5Atoms::thead ||
         aName == nsHtml5Atoms::tfoot ||
         aName == nsHtml5Atoms::tbody ||
         aName == nsHtml5Atoms::tr ||
         aName == nsHtml5Atoms::colgroup ||
         aName == nsHtml5Atoms::style)) {
-    mDeepTreeSurrogateParent = aElement;
+    deepTreeSurrogateParent = aElement;
   }
   if (aNamespace != kNameSpaceID_XHTML) {
     return;
   }
   if (aName == nsHtml5Atoms::body || aName == nsHtml5Atoms::frameset) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
     NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpStartLayout);
@@ -461,18 +461,18 @@ nsHtml5TreeBuilder::elementPushed(PRInt3
 }
 
 void
 nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent** aElement)
 {
   NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
   NS_ASSERTION(aName, "Element doesn't have local name!");
   NS_ASSERTION(aElement, "No element!");
-  if (mDeepTreeSurrogateParent && currentPtr <= NS_HTML5_TREE_DEPTH_LIMIT) {
-    mDeepTreeSurrogateParent = nsnull;
+  if (deepTreeSurrogateParent && currentPtr <= NS_HTML5_TREE_DEPTH_LIMIT) {
+    deepTreeSurrogateParent = nsnull;
   }
   if (aNamespace == kNameSpaceID_MathML) {
     return;
   }
   // we now have only SVG and HTML
   if (aName == nsHtml5Atoms::script) {
     if (mCurrentHtmlScriptIsAsyncOrDefer) {
       NS_ASSERTION(aNamespace == kNameSpaceID_XHTML, 
new file mode 100644
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/591330-1.html
@@ -0,0 +1,284 @@
+<script>
+var sleep = 500; // 0.5 seconds
+var start = Number(new Date());
+while(Number(new Date()) - start < sleep) {
+}
+document.write("<div>"); // make speculation fail
+</script>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+
--- a/parser/htmlparser/tests/crashtests/crashtests.list
+++ b/parser/htmlparser/tests/crashtests/crashtests.list
@@ -39,8 +39,9 @@ load 515278-1.html
 load 515533-1.html
 load 515816-1.html
 load 525229-1.html
 load 522326-1.html
 load 536097-1.html
 load 563514-1.html
 load 574884-1.html
 load 574884-2.html
+load 591330-1.html