Bug 537557 - Thread-unsafe refcounting in the HTML5 parser when chardet enabled. r=bnewman.

This commit is contained in:
Henri Sivonen
2010-01-12 15:15:10 +02:00
parent c604b0a9cb
commit 2c50e9c1d6
3 changed files with 49 additions and 25 deletions

View File

@@ -43,7 +43,6 @@
#include "nsServiceManagerUtils.h"
#include "nsEncoderDecoderUtils.h"
#include "nsContentUtils.h"
#include "nsICharsetDetector.h"
#include "nsHtml5Tokenizer.h"
#include "nsIHttpChannel.h"
#include "nsHtml5Parser.h"
@@ -93,6 +92,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHtml5StreamParser)
tmp->mExecutorFlusher = nsnull;
tmp->mExecutor = nsnull;
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChardet)
tmp->mTreeBuilder->DropSpeculativeLoader();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -108,7 +108,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHtml5StreamParser)
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExecutorFlusher->mExecutor");
cb.NoteXPCOMChild(static_cast<nsIContentSink*> (tmp->mExecutor));
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
// hack: count self if held by mChardet
if (tmp->mChardet) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
"mChardet->mObserver");
cb.NoteXPCOMChild(static_cast<nsIStreamListener*>(tmp));
}
// hack: count the strongly owned edge wrapped in the speculative loader
if (tmp->mDocument) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
@@ -154,6 +160,22 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
#endif
mTokenizer->setInterner(&mAtomTable);
mTokenizer->setEncodingDeclarationHandler(this);
// Chardet instantiation adapted from nsDOMFile.
// Chardet is initialized here even if it turns out to be useless
// to make the chardet refcount its observer (nsHtml5StreamParser)
// on the main thread.
const nsAdoptingString& detectorName =
nsContentUtils::GetLocalizedStringPref("intl.charset.detector");
if (!detectorName.IsEmpty()) {
nsCAutoString detectorContractID;
detectorContractID.AssignLiteral(NS_CHARSET_DETECTOR_CONTRACTID_BASE);
AppendUTF16toUTF8(detectorName, detectorContractID);
if (mChardet = do_CreateInstance(detectorContractID.get())) {
(void) mChardet->Init(this);
}
}
// There's a zeroing operator new for everything else
}
@@ -274,31 +296,21 @@ nsHtml5StreamParser::FinalizeSniffing(const PRUint8* aFromSegment, // can be nul
if (mCharsetSource >= kCharsetFromHintPrevDoc) {
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment, aCount, aWriteCount);
}
// maybe try chardet now; instantiation copied from nsDOMFile
const nsAdoptingString& detectorName = nsContentUtils::GetLocalizedStringPref("intl.charset.detector");
if (!detectorName.IsEmpty()) {
nsCAutoString detectorContractID;
detectorContractID.AssignLiteral(NS_CHARSET_DETECTOR_CONTRACTID_BASE);
AppendUTF16toUTF8(detectorName, detectorContractID);
nsCOMPtr<nsICharsetDetector> detector = do_CreateInstance(detectorContractID.get());
if (detector) {
nsresult rv = detector->Init(this);
// maybe try chardet now;
if (mChardet) {
nsresult rv;
PRBool dontFeed = PR_FALSE;
if (mSniffingBuffer) {
rv = mChardet->DoIt((const char*)mSniffingBuffer.get(), mSniffingLength, &dontFeed);
NS_ENSURE_SUCCESS(rv, rv);
PRBool dontFeed = PR_FALSE;
if (mSniffingBuffer) {
rv = detector->DoIt((const char*)mSniffingBuffer.get(), mSniffingLength, &dontFeed);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!dontFeed && aFromSegment) {
rv = detector->DoIt((const char*)aFromSegment, aCountToSniffingLimit, &dontFeed);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = detector->Done();
NS_ENSURE_SUCCESS(rv, rv);
// fall thru; callback may have changed charset
} else {
NS_ERROR("Could not instantiate charset detector.");
}
if (!dontFeed && aFromSegment) {
rv = mChardet->DoIt((const char*)aFromSegment, aCountToSniffingLimit, &dontFeed);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = mChardet->Done();
NS_ENSURE_SUCCESS(rv, rv);
// fall thru; callback may have changed charset
}
if (mCharsetSource == kCharsetUninitialized) {
// Hopefully this case is never needed, but dealing with it anyway