Bug 1405176 - Bail out DoURILoad if the docshell is being async destructed draft
authorThomas Nguyen <tnguyen@mozilla.com>
Wed, 25 Oct 2017 18:37:19 +0800
changeset 686662 a53712ce86842db41e58b5eada7f015c5524c470
parent 686540 64bab5cbb9b63808d04babfbcfba3175fd99f69d
child 737422 940c1ea04788a4953aaf6073a9937ecc78f22c67
push id86241
push userbmo:tnguyen@mozilla.com
push dateThu, 26 Oct 2017 07:19:23 +0000
bugs1405176
milestone58.0a1
Bug 1405176 - Bail out DoURILoad if the docshell is being async destructed MozReview-Commit-ID: KjUdCn6KkOu
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
dom/base/nsFrameLoader.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -814,16 +814,17 @@ nsDocShell::nsDocShell()
   , mWindowDraggingAllowed(false)
   , mInFrameSwap(false)
   , mInheritPrivateBrowsingId(true)
   , mCanExecuteScripts(false)
   , mFiredUnloadEvent(false)
   , mEODForCurrentDocument(false)
   , mURIResultedInDocument(false)
   , mIsBeingDestroyed(false)
+  , mInAsyncDestroy(false)
   , mIsExecutingOnLoadHandler(false)
   , mIsPrintingOrPP(false)
   , mSavingOldViewer(false)
   , mDynamicallyCreated(false)
   , mAffectPrivateSessionLifetime(true)
   , mInvisible(false)
   , mHasLoadedNonBlankURI(false)
   , mBlankTiming(false)
@@ -11024,17 +11025,17 @@ nsDocShell::DoURILoad(nsIURI* aURI,
                       bool aIsNewWindowTarget,
                       bool aBypassClassifier,
                       bool aForceAllowCookies,
                       const nsAString& aSrcdoc,
                       nsIURI* aBaseURI,
                       nsContentPolicyType aContentPolicyType)
 {
   // Double-check that we're still around to load this URI.
-  if (mIsBeingDestroyed) {
+  if (mIsBeingDestroyed || mInAsyncDestroy) {
     // Return NS_OK despite not doing anything to avoid throwing exceptions from
     // nsLocation::SetHref if the unload handler of the existing page tears us
     // down.
     return NS_OK;
   }
 
   nsresult rv;
   nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -346,16 +346,21 @@ public:
    *
    * This method steals the data from the passed-in array.
    */
   void SetAncestorOuterWindowIDs(nsTArray<uint64_t>&& aAncestorOuterWindowIDs)
   {
     mAncestorOuterWindowIDs = mozilla::Move(aAncestorOuterWindowIDs);
   }
 
+  void SetInAsyncDestroy(bool aInAsyncDestroy)
+  {
+    mInAsyncDestroy = aInAsyncDestroy;
+  }
+
 private:
   bool CanSetOriginAttributes();
 
 public:
   const mozilla::OriginAttributes&
   GetOriginAttributes()
   {
     return mOriginAttributes;
@@ -1068,16 +1073,17 @@ protected:
   // this flag is for bug #21358. a docshell may load many urls
   // which don't result in new documents being created (i.e. a new
   // content viewer) we want to make sure we don't call a on load
   // event more than once for a given content viewer.
   bool mEODForCurrentDocument : 1;
   bool mURIResultedInDocument : 1;
 
   bool mIsBeingDestroyed : 1;
+  bool mInAsyncDestroy : 1;
 
   bool mIsExecutingOnLoadHandler : 1;
 
   // Indicates that a DocShell in this "docshell tree" is printing
   bool mIsPrintingOrPP : 1;
 
   // Indicates to CreateContentViewer() that it is safe to cache the old
   // presentation of the page, and to SetupNewViewer() that the old viewer
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2232,16 +2232,24 @@ nsFrameLoader::StartDestroy()
           groupedSHistory->CloseInactiveFrameLoaderOwners();
         }));
     }
   }
 
   nsCOMPtr<nsIRunnable> destroyRunnable = new nsFrameLoaderDestroyRunnable(this);
   if (mNeedsAsyncDestroy || !doc ||
       NS_FAILED(doc->FinalizeFrameLoader(this, destroyRunnable))) {
+    // We are going to defer destroying the docshell until we return to the
+    // event loop. Let docShell knows about that to bail out loading if we are in
+    // the middle of a load.
+    RefPtr<nsDocShell> docshell = static_cast<nsDocShell*>(GetExistingDocShell());
+    if (docshell) {
+      docshell->SetInAsyncDestroy(true);
+    }
+
     NS_DispatchToCurrentThread(destroyRunnable);
   }
 }
 
 nsresult
 nsFrameLoaderDestroyRunnable::Run()
 {
   switch (mPhase) {