Bug 525229 - Crash [@ nsHtml5PendingNotification::nsHtml5PendingNotification] when document.writing an external script followed by start tag. r=bnewman, a=beltzner.

This commit is contained in:
Henri Sivonen 2009-10-30 13:47:17 +02:00
parent 406d7b2d89
commit 7bad8f1c22
5 changed files with 103 additions and 44 deletions

View File

@ -602,6 +602,8 @@ nsHtml5Parser::ParseUntilBlocked()
if (mStreamParser &&
mReturnToStreamParserPermitted &&
!mExecutor->IsScriptExecuting()) {
mTreeBuilder->flushCharacters();
mTreeBuilder->Flush();
mReturnToStreamParserPermitted = PR_FALSE;
mStreamParser->ContinueAfterScripts(mTokenizer,
mTreeBuilder,

View File

@ -866,7 +866,10 @@ nsHtml5StreamParser::ContinueAfterScripts(nsHtml5Tokenizer* aTokenizer,
mSpeculations.Clear(); // potentially a huge number of destructors
// run here synchronously on the main thread...
mTreeBuilder->flushCharacters(); // empty the pending buffer
mTreeBuilder->ClearOps(); // now get rid of the failed ops
mTreeBuilder->SetOpSink(mExecutor->GetStage());
mExecutor->StartReadingFromStage();
mSpeculating = PR_FALSE;

View File

@ -140,10 +140,15 @@ nsIContent**
nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes)
{
NS_PRECONDITION(aAttributes, "Got null attributes.");
NS_PRECONDITION(aName, "Got null name.");
NS_PRECONDITION(aNamespace == kNameSpaceID_XHTML ||
aNamespace == kNameSpaceID_SVG ||
aNamespace == kNameSpaceID_MathML,
"Bogus namespace.");
nsIContent** content = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(aNamespace, aName, aAttributes, content);
// Start wall of code for speculative loading and line numbers
@ -158,7 +163,7 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
}
} else if (nsHtml5Atoms::script == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
@ -190,7 +195,7 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
}
} else if (nsHtml5Atoms::style == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
}
break;
@ -202,7 +207,7 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
}
} else if (nsHtml5Atoms::script == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
@ -215,7 +220,7 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
}
} else if (nsHtml5Atoms::style == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
@ -231,11 +236,11 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
// No speculative loader--just line numbers
if (nsHtml5Atoms::style == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
} else if (nsHtml5Atoms::script == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
}
}
@ -251,7 +256,7 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
nsIContent** content = createElement(aNamespace, aName, aAttributes);
if (aFormElement) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
}
return content;
@ -262,7 +267,7 @@ nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttribute
{
nsIContent** content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes);
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppendToDocument, content);
return content;
}
@ -270,126 +275,154 @@ nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttribute
void
nsHtml5TreeBuilder::detachFromParent(nsIContent** aElement)
{
NS_PRECONDITION(aElement, "Null element");
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpDetach, aElement);
}
void
nsHtml5TreeBuilder::appendElement(nsIContent** aChild, nsIContent** aParent)
{
NS_PRECONDITION(aChild, "Null child");
NS_PRECONDITION(aParent, "Null parent");
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppend, aChild, aParent);
}
void
nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContent** aOldParent, nsIContent** aNewParent)
{
NS_PRECONDITION(aOldParent, "Null old parent");
NS_PRECONDITION(aNewParent, "Null new parent");
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent);
}
void
nsHtml5TreeBuilder::insertFosterParentedCharacters(PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength, nsIContent** aTable, nsIContent** aStackParent)
{
NS_PRECONDITION(aBuffer, "Null buffer");
NS_PRECONDITION(aTable, "Null table");
NS_PRECONDITION(aStackParent, "Null stack parent");
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** text = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpCreateTextNode, bufferCopy, aLength, text);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpFosterParent, text, aStackParent, aTable);
}
void
nsHtml5TreeBuilder::insertFosterParentedChild(nsIContent** aChild, nsIContent** aTable, nsIContent** aStackParent)
{
NS_PRECONDITION(aChild, "Null child");
NS_PRECONDITION(aTable, "Null table");
NS_PRECONDITION(aStackParent, "Null stack parent");
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable);
}
void
nsHtml5TreeBuilder::appendCharacters(nsIContent** aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
{
NS_PRECONDITION(aBuffer, "Null buffer");
NS_PRECONDITION(aParent, "Null parent");
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** text = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpCreateTextNode, bufferCopy, aLength, text);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppend, text, aParent);
}
void
nsHtml5TreeBuilder::appendComment(nsIContent** aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
{
NS_PRECONDITION(aBuffer, "Null buffer");
NS_PRECONDITION(aParent, "Null parent");
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** comment = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpCreateComment, bufferCopy, aLength, comment);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppend, comment, aParent);
}
void
nsHtml5TreeBuilder::appendCommentToDocument(PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
{
NS_PRECONDITION(aBuffer, "Null buffer");
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** comment = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpCreateComment, bufferCopy, aLength, comment);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppendToDocument, comment);
}
void
nsHtml5TreeBuilder::addAttributesToElement(nsIContent** aElement, nsHtml5HtmlAttributes* aAttributes)
{
NS_PRECONDITION(aElement, "Null element");
NS_PRECONDITION(aAttributes, "Null attributes");
if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(aElement, aAttributes);
}
void
nsHtml5TreeBuilder::markMalformedIfScript(nsIContent** elt)
nsHtml5TreeBuilder::markMalformedIfScript(nsIContent** aElement)
{
NS_PRECONDITION(aElement, "Null element");
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpMarkMalformedIfScript, elt);
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
}
void
nsHtml5TreeBuilder::start(PRBool fragment)
{
// XXX check that timer creation didn't fail in constructor
#ifdef DEBUG
mActive = PR_TRUE;
#endif
@ -407,14 +440,16 @@ nsHtml5TreeBuilder::end()
void
nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId)
{
NS_PRECONDITION(aName, "Null name");
nsIContent** content = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(aName, *aPublicId, *aSystemId, content);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppendToDocument, content);
// nsXMLContentSink can flush here, but what's the point?
// It can also interrupt here, but we can't.
@ -430,7 +465,7 @@ nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace, nsIAtom* aName, nsIContent
if (aNamespace == kNameSpaceID_XHTML) {
if (aName == nsHtml5Atoms::html) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpProcessOfflineManifest, aElement);
return;
}
@ -450,19 +485,19 @@ nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent
if (aName == nsHtml5Atoms::script) {
requestSuspension();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->InitScript(aElement);
return;
}
if (aName == nsHtml5Atoms::title) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpDoneAddingChildren, aElement);
return;
}
if (aName == nsHtml5Atoms::style || (aNamespace == kNameSpaceID_XHTML && aName == nsHtml5Atoms::link)) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
return;
}
@ -500,33 +535,33 @@ nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent
aName == nsHtml5Atoms::object ||
aName == nsHtml5Atoms::applet) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpDoneAddingChildren, aElement);
return;
}
if (aName == nsHtml5Atoms::input ||
aName == nsHtml5Atoms::button) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpDoneCreatingElement, aElement);
return;
}
if (aName == nsHtml5Atoms::base) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpProcessBase, aElement);
return;
}
if (aName == nsHtml5Atoms::meta) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpProcessMeta, aElement);
return;
}
if (aName == nsHtml5Atoms::head) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpStartLayout, nsnull);
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpStartLayout);
return;
}
return;
@ -555,6 +590,9 @@ nsHtml5TreeBuilder::AllocateContentHandle()
mHandles = new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH];
mHandlesUsed = 0;
}
#ifdef DEBUG
mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD;
#endif
return &mHandles[mHandlesUsed++];
}
@ -584,7 +622,7 @@ void
nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset)
{
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetDocumentCharset, aCharset);
}
@ -598,7 +636,7 @@ nsHtml5TreeBuilder::StreamEnded()
// innerHTML content.
if (!fragment) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpStreamEnded);
}
}
@ -607,7 +645,7 @@ void
nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString& aCharset)
{
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpNeedsCharsetSwitchTo, aCharset);
}
@ -635,6 +673,6 @@ void
nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m)
{
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(m);
}

View File

@ -68,6 +68,10 @@
void SetOpSink(nsAHtml5TreeOpSink* aOpSink) {
mOpSink = aOpSink;
}
void ClearOps() {
mOpQueue.Clear();
}
void SetSpeculativeLoaderWithDocument(nsIDocument* aDocument);

View File

@ -117,6 +117,7 @@ class nsHtml5TreeOperation {
inline void Init(eHtml5TreeOperation aOpCode, nsIContent** aNode) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
mOpCode = aOpCode;
mOne.node = aNode;
}
@ -126,6 +127,8 @@ class nsHtml5TreeOperation {
nsIContent** aParent) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
NS_PRECONDITION(aParent, "Initialized tree op with null parent.");
mOpCode = aOpCode;
mOne.node = aNode;
mTwo.node = aParent;
@ -137,6 +140,9 @@ class nsHtml5TreeOperation {
nsIContent** aTable) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
NS_PRECONDITION(aParent, "Initialized tree op with null parent.");
NS_PRECONDITION(aTable, "Initialized tree op with null table.");
mOpCode = aOpCode;
mOne.node = aNode;
mTwo.node = aParent;
@ -153,6 +159,7 @@ class nsHtml5TreeOperation {
inline void InitScript(nsIContent** aNode) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
mOpCode = eTreeOpRunScript;
mOne.node = aNode;
mTwo.state = nsnull;
@ -164,6 +171,8 @@ class nsHtml5TreeOperation {
nsIContent** aTarget) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aName, "Initialized tree op with null name.");
NS_PRECONDITION(aTarget, "Initialized tree op with null target node.");
mOpCode = eTreeOpCreateElement;
mInt = aNamespace;
mOne.node = aTarget;
@ -181,6 +190,7 @@ class nsHtml5TreeOperation {
nsIContent** aTarget) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer.");
mOpCode = aOpCode;
mOne.node = aTarget;
mTwo.unicharPtr = aBuffer;
@ -191,6 +201,7 @@ class nsHtml5TreeOperation {
nsHtml5HtmlAttributes* aAttributes) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aElement, "Initialized tree op with null element.");
mOpCode = eTreeOpAddAttributes;
mOne.node = aElement;
mTwo.attributes = aAttributes;
@ -228,7 +239,7 @@ class nsHtml5TreeOperation {
PRInt32 aInt) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
mOpCode = aOpCode;
mOne.node = aNode;
mInt = aInt;
@ -241,6 +252,7 @@ class nsHtml5TreeOperation {
inline void SetSnapshot(nsAHtml5TreeBuilderState* aSnapshot, PRInt32 aLine) {
NS_ASSERTION(IsRunScript(),
"Setting a snapshot for a tree operation other than eTreeOpRunScript!");
NS_PRECONDITION(aSnapshot, "Initialized tree op with null snapshot.");
mTwo.state = aSnapshot;
mInt = aLine;
}