зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
96db2ec818
Коммит
f8118f711d
|
@ -59,8 +59,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
|
||||
|
||||
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
PRInt32 mHandlesUsed;
|
||||
nsTArray<nsAutoArrayPtr<nsIContent*> > mOldHandles;
|
||||
nsHtml5TreeOpStage* mSpeculativeLoadStage;
|
||||
nsIContent** mDeepTreeSurrogateParent;
|
||||
PRBool mCurrentHtmlScriptIsAsyncOrDefer;
|
||||
#ifdef DEBUG
|
||||
PRBool mActive;
|
||||
|
|
Загрузка…
Ссылка в новой задаче