commit 7efadbb03cdffa11ebfc2da3113377d2f33b893b Author: Henri Sivonen Date: Mon Nov 3 15:23:26 2014 +0200 Bug 1088635. r=smaug, a=bkerensa Modified content/base/src/nsDocument.cpp diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index cbed38d..3493bce 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -3916,7 +3916,7 @@ nsDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) { if (aKid->IsElement() && GetRootElement()) { - NS_ERROR("Inserting element child when we already have one"); + NS_WARNING("Inserting root element when we already have one"); return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } Modified parser/html/nsHtml5Parser.cpp diff --git a/parser/html/nsHtml5Parser.cpp b/parser/html/nsHtml5Parser.cpp index a485be4..f28adb4 100644 --- a/parser/html/nsHtml5Parser.cpp +++ b/parser/html/nsHtml5Parser.cpp @@ -237,7 +237,8 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer, * WillBuildModel to be called before the document has had its * script global object set. */ - mExecutor->WillBuildModel(eDTDMode_unknown); + rv = mExecutor->WillBuildModel(eDTDMode_unknown); + NS_ENSURE_SUCCESS(rv, rv); } // Return early if the parser has processed EOF @@ -255,7 +256,7 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer, } mDocumentClosed = true; if (!mBlocked && !mInDocumentWrite) { - ParseUntilBlocked(); + return ParseUntilBlocked(); } return NS_OK; } @@ -378,7 +379,8 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer, if (mTreeBuilder->HasScript()) { mTreeBuilder->Flush(); // Move ops to the executor - mExecutor->FlushDocumentWrite(); // run the ops + rv = mExecutor->FlushDocumentWrite(); // run the ops + NS_ENSURE_SUCCESS(rv, rv); // Flushing tree ops can cause all sorts of things. // Return early if the parser got terminated. if (mExecutor->IsComplete()) { @@ -437,7 +439,8 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer, "Buffer wasn't tokenized to completion?"); // Scripting semantics require a forced tree builder flush here mTreeBuilder->Flush(); // Move ops to the executor - mExecutor->FlushDocumentWrite(); // run the ops + rv = mExecutor->FlushDocumentWrite(); // run the ops + NS_ENSURE_SUCCESS(rv, rv); } else if (stackBuffer.hasMore()) { // The buffer wasn't tokenized to completion. Tokenize the untokenized // content in order to preload stuff. This content will be retokenized @@ -594,11 +597,13 @@ nsHtml5Parser::IsScriptCreated() /* End nsIParser */ // not from interface -void +nsresult nsHtml5Parser::ParseUntilBlocked() { - if (mBlocked || mExecutor->IsComplete() || NS_FAILED(mExecutor->IsBroken())) { - return; + nsresult rv = mExecutor->IsBroken(); + NS_ENSURE_SUCCESS(rv, rv); + if (mBlocked || mExecutor->IsComplete()) { + return NS_OK; } NS_ASSERTION(mExecutor->HasStarted(), "Bad life cycle."); NS_ASSERTION(!mInDocumentWrite, @@ -611,7 +616,7 @@ nsHtml5Parser::ParseUntilBlocked() if (mFirstBuffer == mLastBuffer) { if (mExecutor->IsComplete()) { // something like cache manisfests stopped the parse in mid-flight - return; + return NS_OK; } if (mDocumentClosed) { NS_ASSERTION(!GetStreamParser(), @@ -620,8 +625,10 @@ nsHtml5Parser::ParseUntilBlocked() mTreeBuilder->StreamEnded(); mTreeBuilder->Flush(); mExecutor->FlushDocumentWrite(); + // The below call does memory cleanup, so call it even if the + // parser has been marked as broken. mTokenizer->end(); - return; + return NS_OK; } // never release the last buffer. NS_ASSERTION(!mLastBuffer->getStart() && !mLastBuffer->getEnd(), @@ -643,14 +650,14 @@ nsHtml5Parser::ParseUntilBlocked() NS_ASSERTION(mExecutor->IsInFlushLoop(), "How did we come here without being in the flush loop?"); } - return; // no more data for now but expecting more + return NS_OK; // no more data for now but expecting more } mFirstBuffer = mFirstBuffer->next; continue; } if (mBlocked || mExecutor->IsComplete()) { - return; + return NS_OK; } // now we have a non-empty buffer @@ -667,10 +674,11 @@ nsHtml5Parser::ParseUntilBlocked() } if (mTreeBuilder->HasScript()) { mTreeBuilder->Flush(); - mExecutor->FlushDocumentWrite(); + nsresult rv = mExecutor->FlushDocumentWrite(); + NS_ENSURE_SUCCESS(rv, rv); } if (mBlocked) { - return; + return NS_OK; } } continue; Modified parser/html/nsHtml5Parser.h diff --git a/parser/html/nsHtml5Parser.h b/parser/html/nsHtml5Parser.h index aff79c7..e2ef2f8 100644 --- a/parser/html/nsHtml5Parser.h +++ b/parser/html/nsHtml5Parser.h @@ -262,7 +262,7 @@ class nsHtml5Parser : public nsIParser, /** * Parse until pending data is exhausted or a script blocks the parser */ - void ParseUntilBlocked(); + nsresult ParseUntilBlocked(); private: Modified parser/html/nsHtml5StreamParser.cpp diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp index 4790568..7e3917b 100644 --- a/parser/html/nsHtml5StreamParser.cpp +++ b/parser/html/nsHtml5StreamParser.cpp @@ -796,7 +796,7 @@ nsHtml5StreamParser::WriteStreamBytes(const uint8_t* aFromSegment, // NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE. if (!mLastBuffer) { NS_WARNING("mLastBuffer should not be null!"); - MarkAsBroken(); + MarkAsBroken(NS_ERROR_NULL_POINTER); return NS_ERROR_NULL_POINTER; } if (mLastBuffer->getEnd() == NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE) { @@ -902,7 +902,8 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) * WillBuildModel to be called before the document has had its * script global object set. */ - mExecutor->WillBuildModel(eDTDMode_unknown); + rv = mExecutor->WillBuildModel(eDTDMode_unknown); + NS_ENSURE_SUCCESS(rv, rv); nsRefPtr newBuf = nsHtml5OwningUTF16Buffer::FalliblyCreate( @@ -1003,8 +1004,9 @@ nsHtml5StreamParser::DoStopRequest() if (!mUnicodeDecoder) { uint32_t writeCount; - if (NS_FAILED(FinalizeSniffing(nullptr, 0, &writeCount, 0))) { - MarkAsBroken(); + nsresult rv; + if (NS_FAILED(rv = FinalizeSniffing(nullptr, 0, &writeCount, 0))) { + MarkAsBroken(rv); return; } } else if (mFeedChardet) { @@ -1076,7 +1078,7 @@ nsHtml5StreamParser::DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength) rv = SniffStreamBytes(aBuffer, aLength, &writeCount); } if (NS_FAILED(rv)) { - MarkAsBroken(); + MarkAsBroken(rv); return; } NS_ASSERTION(writeCount == aLength, "Wrong number of stream bytes written/sniffed."); @@ -1662,13 +1664,13 @@ nsHtml5StreamParser::TimerFlush() } void -nsHtml5StreamParser::MarkAsBroken() +nsHtml5StreamParser::MarkAsBroken(nsresult aRv) { NS_ASSERTION(IsParserThread(), "Wrong thread!"); mTokenizerMutex.AssertCurrentThreadOwns(); Terminate(); - mTreeBuilder->MarkAsBroken(); + mTreeBuilder->MarkAsBroken(aRv); mozilla::DebugOnly hadOps = mTreeBuilder->Flush(false); NS_ASSERTION(hadOps, "Should have had the markAsBroken op!"); if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) { Modified parser/html/nsHtml5StreamParser.h diff --git a/parser/html/nsHtml5StreamParser.h b/parser/html/nsHtml5StreamParser.h index c7dcbbe..476ef16 100644 --- a/parser/html/nsHtml5StreamParser.h +++ b/parser/html/nsHtml5StreamParser.h @@ -218,7 +218,7 @@ class nsHtml5StreamParser : public nsICharsetDetectionObserver { } #endif - void MarkAsBroken(); + void MarkAsBroken(nsresult aRv); /** * Marks the stream parser as interrupted. If you ever add calls to this Modified parser/html/nsHtml5TreeBuilderCppSupplement.h diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index 4cd5c7c..1e65394 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -949,14 +949,14 @@ nsHtml5TreeBuilder::DropHandles() } void -nsHtml5TreeBuilder::MarkAsBroken() +nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) { if (MOZ_UNLIKELY(mBuilder)) { MOZ_ASSUME_UNREACHABLE("Must not call this with builder."); return; } mOpQueue.Clear(); // Previous ops don't matter anymore - mOpQueue.AppendElement()->Init(eTreeOpMarkAsBroken); + mOpQueue.AppendElement()->Init(aRv); } void Modified parser/html/nsHtml5TreeBuilderHSupplement.h diff --git a/parser/html/nsHtml5TreeBuilderHSupplement.h b/parser/html/nsHtml5TreeBuilderHSupplement.h index a321e80..8d380eb 100644 --- a/parser/html/nsHtml5TreeBuilderHSupplement.h +++ b/parser/html/nsHtml5TreeBuilderHSupplement.h @@ -223,4 +223,4 @@ void errEndWithUnclosedElements(nsIAtom* aName); - void MarkAsBroken(); + void MarkAsBroken(nsresult aRv); Modified parser/html/nsHtml5TreeOpExecutor.cpp diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index ebcafca..6c52e5f 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -411,7 +411,11 @@ nsHtml5TreeOpExecutor::RunFlushLoop() GetParser()->GetStreamParser(); // Now parse content left in the document.write() buffer queue if any. // This may generate tree ops on its own or dequeue a speculation. - GetParser()->ParseUntilBlocked(); + nsresult rv = GetParser()->ParseUntilBlocked(); + if (NS_FAILED(rv)) { + MarkAsBroken(rv); + return; + } } if (mOpQueue.IsEmpty()) { @@ -496,21 +500,24 @@ nsHtml5TreeOpExecutor::RunFlushLoop() } } -void +nsresult nsHtml5TreeOpExecutor::FlushDocumentWrite() { + nsresult rv = IsBroken(); + NS_ENSURE_SUCCESS(rv, rv); + FlushSpeculativeLoads(); // Make sure speculative loads never start after the // corresponding normal loads for the same URLs. if (MOZ_UNLIKELY(!mParser)) { // The parse has ended. mOpQueue.Clear(); // clear in order to be able to assert in destructor - return; + return rv; } if (mFlushState != eNotFlushing) { // XXX Can this happen? In case it can, let's avoid crashing. - return; + return rv; } mFlushState = eInFlush; @@ -545,7 +552,7 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite() } NS_ASSERTION(mFlushState == eInDocUpdate, "Tried to perform tree op outside update batch."); - nsresult rv = iter->Perform(this, &scriptElement); + rv = iter->Perform(this, &scriptElement); if (NS_FAILED(rv)) { MarkAsBroken(rv); break; @@ -560,13 +567,14 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite() if (MOZ_UNLIKELY(!mParser)) { // Ending the doc update caused a call to nsIParser::Terminate(). - return; + return rv; } if (scriptElement) { // must be tail call when mFlushState is eNotFlushing RunScript(scriptElement); } + return rv; } // copied from HTML content sink Modified parser/html/nsHtml5TreeOpExecutor.h diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h index 9617dcb..1f81448 100644 --- a/parser/html/nsHtml5TreeOpExecutor.h +++ b/parser/html/nsHtml5TreeOpExecutor.h @@ -173,7 +173,7 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder, void RunFlushLoop(); - void FlushDocumentWrite(); + nsresult FlushDocumentWrite(); void MaybeSuspend(); Modified parser/html/nsHtml5TreeOperation.cpp diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index 48b71dc..7ad65247 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -214,6 +214,9 @@ nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode, nsIDocument* doc = aBuilder->GetDocument(); uint32_t childCount = doc->GetChildCount(); rv = doc->AppendChildTo(aNode, false); + if (rv == NS_ERROR_DOM_HIERARCHY_REQUEST_ERR) { + return NS_OK; + } NS_ENSURE_SUCCESS(rv, rv); nsNodeUtils::ContentInserted(doc, aNode, childCount); @@ -739,8 +742,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, return NS_OK; } case eTreeOpMarkAsBroken: { - aBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); - return NS_OK; + return mOne.result; } case eTreeOpRunScript: { nsIContent* node = *(mOne.node); Modified parser/html/nsHtml5TreeOperation.h diff --git a/parser/html/nsHtml5TreeOperation.h b/parser/html/nsHtml5TreeOperation.h index 2727733..06d0274 100644 --- a/parser/html/nsHtml5TreeOperation.h +++ b/parser/html/nsHtml5TreeOperation.h @@ -435,6 +435,15 @@ class nsHtml5TreeOperation { mFour.integer = aInt; } + inline void Init(nsresult aRv) + { + NS_PRECONDITION(mOpCode == eTreeOpUninitialized, + "Op code must be uninitialized when initializing."); + NS_PRECONDITION(NS_FAILED(aRv), "Initialized tree op with non-failure."); + mOpCode = eTreeOpMarkAsBroken; + mOne.result = aRv; + } + inline void InitAddClass(nsIContentHandle* aNode, const char16_t* aClass) { NS_PRECONDITION(mOpCode == eTreeOpUninitialized, @@ -487,11 +496,12 @@ class nsHtml5TreeOperation { nsIAtom* atom; nsHtml5HtmlAttributes* attributes; nsHtml5DocumentMode mode; - char16_t* unicharPtr; + char16_t* unicharPtr; char* charPtr; nsHtml5TreeOperationStringPair* stringPair; nsAHtml5TreeBuilderState* state; int32_t integer; + nsresult result; } mOne, mTwo, mThree, mFour; };