Bug 1350049: Handle nsParser being finalized before resuming. r=hsivonen
authorKris Maglione <maglione.k@gmail.com>
Tue, 28 Mar 2017 15:24:26 -0700
changeset 350582 99726da227dd
parent 350581 a381650bea90
child 350583 f62917e98036
push id31578
push usercbook@mozilla.com
push dateFri, 31 Mar 2017 12:43:10 +0000
treeherdermozilla-central@b82d0e0dc533 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs1350049
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1350049: Handle nsParser being finalized before resuming. r=hsivonen This is a hybrid of the previous two approaches. The nsParser weak reference sometimes stays alive after it's been detached from the document, after which attempting to remove it throws. This stores a reference to the original parser, and checks that it's still the current parser when it comes time to resume. MozReview-Commit-ID: 1JSi2FmPxt0
dom/base/nsDocument.cpp
parser/htmlparser/nsParser.cpp
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10549,16 +10549,17 @@ public:
 
   explicit UnblockParsingPromiseHandler(nsIDocument* aDocument, Promise* aPromise)
     : mPromise(aPromise)
   {
     nsCOMPtr<nsIParser> parser = aDocument->CreatorParserOrNull();
     if (parser) {
       parser->BlockParser();
       mParser = do_GetWeakReference(parser);
+      mDocument = aDocument;
     }
   }
 
   void
   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
   {
     MaybeUnblockParser();
 
@@ -10578,27 +10579,33 @@ protected:
   {
     MaybeUnblockParser();
   }
 
 private:
   void MaybeUnblockParser() {
     nsCOMPtr<nsIParser> parser = do_QueryReferent(mParser);
     if (parser) {
-      parser->UnblockParser();
-      parser->ContinueInterruptedParsingAsync();
-      mParser = nullptr;
-    }
+      MOZ_ASSERT(mDocument);
+      nsCOMPtr<nsIParser> docParser = mDocument->CreatorParserOrNull();
+      if (parser == docParser) {
+        parser->UnblockParser();
+        parser->ContinueInterruptedParsingAsync();
+      }
+    }
+    mParser = nullptr;
+    mDocument = nullptr;
   }
 
   nsWeakPtr mParser;
   RefPtr<Promise> mPromise;
+  RefPtr<nsIDocument> mDocument;
 };
 
-NS_IMPL_CYCLE_COLLECTION(UnblockParsingPromiseHandler, mPromise)
+NS_IMPL_CYCLE_COLLECTION(UnblockParsingPromiseHandler, mDocument, mPromise)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UnblockParsingPromiseHandler)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(UnblockParsingPromiseHandler)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(UnblockParsingPromiseHandler)
 
--- a/parser/htmlparser/nsParser.cpp
+++ b/parser/htmlparser/nsParser.cpp
@@ -677,17 +677,20 @@ nsParser::UnblockParser()
   if (MOZ_LIKELY(mBlocked > 0)) {
     mBlocked--;
   }
 }
 
 NS_IMETHODIMP_(void)
 nsParser::ContinueInterruptedParsingAsync()
 {
-  mSink->ContinueInterruptedParsingAsync();
+  MOZ_ASSERT(mSink);
+  if (MOZ_LIKELY(mSink)) {
+    mSink->ContinueInterruptedParsingAsync();
+  }
 }
 
 /**
  * Call this to query whether the parser is enabled or not.
  */
 NS_IMETHODIMP_(bool)
 nsParser::IsParserEnabled()
 {