Bug 561874 - Make the HTML5 parser clip deep trees (similar to the old HTML parser) to avoid crashes in recursive code elsewhere. r=bzbarsky

This commit is contained in:
Henri Sivonen 2010-05-20 12:03:11 +03:00
parent abd1ecb72b
commit 877375af37
5 changed files with 45 additions and 21 deletions

View File

@ -60,8 +60,6 @@ import org.xml.sax.SAXParseException;
public abstract class TreeBuilder<T> implements TokenHandler,
TreeBuilderState<T> {
public static final int STACK_MAX_DEPTH = 200;
// Start dispatch groups
final static int OTHER = 0;
@ -4217,10 +4215,6 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
@SuppressWarnings("unchecked") private void push(StackNode<T> node) throws SAXException {
if (currentPtr == TreeBuilder.STACK_MAX_DEPTH) {
warn("Maximum depth for tree builder stack reached. Modifying document.");
pop();
}
currentPtr++;
if (currentPtr == stack.length) {
StackNode<T>[] newStack = new StackNode[stack.length + 64];
@ -4233,10 +4227,6 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
@SuppressWarnings("unchecked") private void silentPush(StackNode<T> node) throws SAXException {
if (currentPtr == TreeBuilder.STACK_MAX_DEPTH) {
warn("Maximum depth for tree builder stack reached. Modifying document.");
pop();
}
currentPtr++;
if (currentPtr == stack.length) {
StackNode<T>[] newStack = new StackNode[stack.length + 64];

View File

@ -3013,10 +3013,6 @@ nsHtml5TreeBuilder::clearLastListSlot()
void
nsHtml5TreeBuilder::push(nsHtml5StackNode* node)
{
if (currentPtr == NS_HTML5TREE_BUILDER_STACK_MAX_DEPTH) {
pop();
}
currentPtr++;
if (currentPtr == stack.length) {
jArray<nsHtml5StackNode*,PRInt32> newStack = jArray<nsHtml5StackNode*,PRInt32>(stack.length + 64);
@ -3031,10 +3027,6 @@ nsHtml5TreeBuilder::push(nsHtml5StackNode* node)
void
nsHtml5TreeBuilder::silentPush(nsHtml5StackNode* node)
{
if (currentPtr == NS_HTML5TREE_BUILDER_STACK_MAX_DEPTH) {
pop();
}
currentPtr++;
if (currentPtr == stack.length) {
jArray<nsHtml5StackNode*,PRInt32> newStack = jArray<nsHtml5StackNode*,PRInt32>(stack.length + 64);

View File

@ -242,7 +242,6 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState
jArray<const char*,PRInt32> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = nsnull;
#endif
#define NS_HTML5TREE_BUILDER_STACK_MAX_DEPTH 200
#define NS_HTML5TREE_BUILDER_OTHER 0
#define NS_HTML5TREE_BUILDER_A 1
#define NS_HTML5TREE_BUILDER_BASE 2

View File

@ -46,6 +46,8 @@
#include "nsContentUtils.h"
#include "nsNodeUtils.h"
#define NS_HTML5_TREE_DEPTH_LIMIT 200
class nsPresContext;
// this really should be autogenerated...
@ -243,7 +245,9 @@ nsHtml5TreeBuilder::appendElement(nsIContent** aChild, nsIContent** aParent)
{
NS_PRECONDITION(aChild, "Null child");
NS_PRECONDITION(aParent, "Null parent");
if (mDeepTreeSurrogateParent) {
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppend, aChild, aParent);
@ -298,7 +302,8 @@ nsHtml5TreeBuilder::appendCharacters(nsIContent** aParent, PRUnichar* aBuffer, P
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppendText, bufferCopy, aLength, aParent);
treeOp->Init(eTreeOpAppendText, bufferCopy, aLength,
mDeepTreeSurrogateParent ? mDeepTreeSurrogateParent : aParent);
}
void
@ -306,6 +311,9 @@ nsHtml5TreeBuilder::appendComment(nsIContent** aParent, PRUnichar* aBuffer, PRIn
{
NS_PRECONDITION(aBuffer, "Null buffer");
NS_PRECONDITION(aParent, "Null parent");
if (mDeepTreeSurrogateParent) {
return;
}
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
@ -356,6 +364,7 @@ void
nsHtml5TreeBuilder::start(PRBool fragment)
{
mCurrentHtmlScriptIsAsyncOrDefer = PR_FALSE;
mDeepTreeSurrogateParent = nsnull;
#ifdef DEBUG
mActive = PR_TRUE;
#endif
@ -388,6 +397,36 @@ nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace, nsIAtom* aName, nsIContent
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!");
/*
* The frame constructor uses recursive algorithms, so it can't deal with
* arbitrarily deep trees. This is especially a problem on Windows where
* the permitted depth of the runtime stack is rather small.
*
* The following is a protection against author incompetence--not against
* malice. There are other ways to make the DOM deep anyway.
*
* The basic idea is that when the tree builder stack gets too deep,
* append operations no longer append to the node that the HTML parsing
* algorithm says they should but instead text nodes are append to the last
* 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 &&
!(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;
}
if (aNamespace != kNameSpaceID_XHTML) {
return;
}
@ -405,6 +444,9 @@ nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent
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 (aNamespace == kNameSpaceID_MathML) {
return;
}

View File

@ -46,6 +46,7 @@
PRInt32 mHandlesUsed;
nsTArray<nsAutoArrayPtr<nsIContent*> > mOldHandles;
nsHtml5TreeOpStage* mSpeculativeLoadStage;
nsIContent** mDeepTreeSurrogateParent;
PRBool mCurrentHtmlScriptIsAsyncOrDefer;
#ifdef DEBUG
PRBool mActive;