Bug 1031303 - mContext can be null when nsGlobalWindow::SetNewDocument is called, r=jst a=sylvestre
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 31 Jul 2014 23:15:57 +0300
changeset 217544 71a901b41f4c85d63f8d8fbf314d2e2cce4da39e
parent 217543 0313315936fea1154fa5a3912a23a9a5bfe03827
child 217545 e935e84f4dcc205de82edaa35dc3ac295f3a64df
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst, sylvestre
bugs1031303
milestone33.0a2
Bug 1031303 - mContext can be null when nsGlobalWindow::SetNewDocument is called, r=jst a=sylvestre
docshell/base/nsDocShell.cpp
dom/base/nsGlobalWindow.cpp
layout/base/nsDocumentViewer.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6611,16 +6611,17 @@ NS_IMETHODIMP
 nsDocShell::Embed(nsIContentViewer * aContentViewer,
                   const char *aCommand, nsISupports * aExtraInfo)
 {
     // Save the LayoutHistoryState of the previous document, before
     // setting up new document
     PersistLayoutHistoryState();
 
     nsresult rv = SetupNewViewer(aContentViewer);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     // If we are loading a wyciwyg url from history, change the base URI for 
     // the document to the original http url that created the document.write().
     // This makes sure that all relative urls in a document.written page loaded
     // via history work properly.
     if (mCurrentURI &&
        (mLoadType & LOAD_CMD_HISTORY ||
         mLoadType == LOAD_RELOAD_NORMAL ||
@@ -7308,16 +7309,18 @@ nsDocShell::EnsureContentViewer()
             if (parentElement) {
                 baseURI = parentElement->GetBaseURI();
             }
         }
     }
 
     nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
 
+    NS_ENSURE_STATE(mContentViewer);
+
     if (NS_SUCCEEDED(rv)) {
         nsCOMPtr<nsIDocument> doc(GetDocument());
         NS_ASSERTION(doc,
                      "Should have doc if CreateAboutBlankContentViewer "
                      "succeeded!");
 
         doc->SetIsInitialDocument(true);
     }
@@ -7336,16 +7339,17 @@ nsDocShell::CreateAboutBlankContentViewe
 
   /* mCreatingDocument should never be true at this point. However, it's
      a theoretical possibility. We want to know about it and make it stop,
      and this sounds like a job for an assertion. */
   NS_ASSERTION(!mCreatingDocument, "infinite(?) loop creating document averted");
   if (mCreatingDocument)
     return NS_ERROR_FAILURE;
 
+  AutoRestore<bool> creatingDocument(mCreatingDocument);
   mCreatingDocument = true;
 
   // mContentViewer->PermitUnload may release |this| docshell.
   nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
   
   // Make sure timing is created.  But first record whether we had it
   // already, so we don't clobber the timing for an in-progress load.
   bool hadTiming = mTiming;
@@ -7424,24 +7428,24 @@ nsDocShell::CreateAboutBlankContentViewe
 
       // create a content viewer for us and the new document
       docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
                     blankDoc, "view", getter_AddRefs(viewer));
 
       // hook 'em up
       if (viewer) {
         viewer->SetContainer(this);
-        Embed(viewer, "", 0);
+        rv = Embed(viewer, "", 0);
+        NS_ENSURE_SUCCESS(rv, rv);
 
         SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0);
         rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
       }
     }
   }
-  mCreatingDocument = false;
 
   // The transient about:blank viewer doesn't have a session history entry.
   SetHistoryEntry(&mOSHE, nullptr);
 
   // Clear out our mTiming like we would in EndPageLoad, if we didn't
   // have one before entering this function.
   if (!hadTiming) {
     mTiming = nullptr;
@@ -8653,17 +8657,17 @@ nsDocShell::SetupNewViewer(nsIContentVie
     NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
 
     nsIntRect bounds(x, y, cx, cy);
 
     mContentViewer->SetNavigationTiming(mTiming);
 
     if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
         mContentViewer = nullptr;
-        NS_ERROR("ContentViewer Initialization failed");
+        NS_WARNING("ContentViewer Initialization failed");
         return NS_ERROR_FAILURE;
     }
 
     // If we have old state to copy, set the old state onto the new content
     // viewer
     if (newMUDV) {
         NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset),
                           NS_ERROR_FAILURE);
@@ -8699,16 +8703,17 @@ nsDocShell::SetupNewViewer(nsIContentVie
     // viewer still set to hidden.
 
     return NS_OK;
 }
 
 nsresult
 nsDocShell::SetDocCurrentStateObj(nsISHEntry *shEntry)
 {
+    NS_ENSURE_STATE(mContentViewer);
     nsCOMPtr<nsIDocument> document = GetDocument();
     NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
 
     nsCOMPtr<nsIStructuredCloneContainer> scContainer;
     if (shEntry) {
         nsresult rv = shEntry->GetStateData(getter_AddRefs(scContainer));
         NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2328,16 +2328,19 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     }
 
     return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
                                                     aForceReuseInnerWindow);
   }
 
   NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
 
+  // Bail out early if we're in process of closing down the window.
+  NS_ENSURE_STATE(!mCleanedUp);
+
   if (IsFrozen()) {
     // This outer is now getting its first inner, thaw the outer now
     // that it's ready and is getting an inner window.
 
     Thaw();
   }
 
   NS_ASSERTION(!GetCurrentInnerWindow() ||
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -895,17 +895,21 @@ nsDocumentViewer::InitInternal(nsIWidget
 
     nsCOMPtr<nsPIDOMWindow> window;
     requestor->GetInterface(NS_GET_IID(nsPIDOMWindow),
                             getter_AddRefs(window));
 
     if (window) {
       nsCOMPtr<nsIDocument> curDoc = window->GetExtantDoc();
       if (aForceSetNewDocument || curDoc != mDocument) {
-        window->SetNewDocument(mDocument, aState, false);
+        rv = window->SetNewDocument(mDocument, aState, false);
+        if (NS_FAILED(rv)) {
+          Destroy();
+          return rv;
+        }
         nsJSContext::LoadStart();
       }
     }
   }
 
   if (aDoCreation && mPresContext) {
     // The ViewManager and Root View was created above (in
     // MakeWindow())...
@@ -1797,57 +1801,63 @@ nsDocumentViewer::SetDocumentInternal(ns
   // Set new container
   aDocument->SetContainer(mContainer);
 
   if (mDocument != aDocument) {
     if (mDocument->IsStaticDocument()) {
       mDocument->SetScriptGlobalObject(nullptr);
       mDocument->Destroy();
     }
-    // Replace the old document with the new one. Do this only when
-    // the new document really is a new document.
-    mDocument = aDocument;
-
-    // Set the script global object on the new document
-    nsCOMPtr<nsPIDOMWindow> window =
-      mContainer ? mContainer->GetWindow() : nullptr;
-    if (window) {
-      window->SetNewDocument(aDocument, nullptr, aForceReuseInnerWindow);
-    }
 
     // Clear the list of old child docshells. Child docshells for the new
     // document will be constructed as frames are created.
     if (!aDocument->IsStaticDocument()) {
       nsCOMPtr<nsIDocShell> node(mContainer);
       if (node) {
         int32_t count;
         node->GetChildCount(&count);
         for (int32_t i = 0; i < count; ++i) {
           nsCOMPtr<nsIDocShellTreeItem> child;
           node->GetChildAt(0, getter_AddRefs(child));
           node->RemoveChild(child);
         }
       }
     }
+
+    // Replace the old document with the new one. Do this only when
+    // the new document really is a new document.
+    mDocument = aDocument;
+
+    // Set the script global object on the new document
+    nsCOMPtr<nsPIDOMWindow> window =
+      mContainer ? mContainer->GetWindow() : nullptr;
+    if (window) {
+      nsresult rv = window->SetNewDocument(aDocument, nullptr,
+                                           aForceReuseInnerWindow);
+      if (NS_FAILED(rv)) {
+        Destroy();
+        return rv;
+      }
+    }
   }
 
   nsresult rv = SyncParentSubDocMap();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Replace the current pres shell with a new shell for the new document
 
   if (mPresShell) {
     DestroyPresShell();
   }
 
   if (mPresContext) {
     DestroyPresContext();
 
     mWindow = nullptr;
-    InitInternal(mParentWidget, nullptr, mBounds, true, true, false);
+    rv = InitInternal(mParentWidget, nullptr, mBounds, true, true, false);
   }
 
   return rv;
 }
 
 nsIPresShell*
 nsDocumentViewer::GetPresShell()
 {
@@ -4386,17 +4396,18 @@ NS_IMETHODIMP nsDocumentViewer::SetPageM
     mPresContext = CreatePresContext(mDocument,
         nsPresContext::eContext_PageLayout, FindContainerView());
     NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);
     mPresContext->SetPaginatedScrolling(true);
     mPresContext->SetPrintSettings(aPrintSettings);
     nsresult rv = mPresContext->Init(mDeviceContext);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  InitInternal(mParentWidget, nullptr, mBounds, true, false);
+  NS_ENSURE_SUCCESS(InitInternal(mParentWidget, nullptr, mBounds, true, false),
+                    NS_ERROR_FAILURE);
 
   Show();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetHistoryEntry(nsISHEntry **aHistoryEntry)
 {