Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Unified Diff: content/browser/frame_host/render_frame_host_manager_browsertest.cc

Issue 1835833002: Fix 3 crashes related to navigations after a process dies. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove TODO Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/frame_host/render_frame_host_manager_browsertest.cc
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index 973f0b5f6fa16044c00660840fd25fb1e58e541f..7f9e98aef5651a524093721be9fe20d5ba632e4d 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -48,6 +48,7 @@
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
+#include "content/test/test_frame_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/request_handler_util.h"
@@ -2357,6 +2358,137 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
shell(), embedded_test_server()->GetURL("b.com", "/title3.html")));
}
+// Ensure that we don't crash the renderer in CreateRenderView if a proxy goes
+// away between swapout and the next navigation. See https://crbug.com/581912.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ CreateRenderViewAfterProcessKillAndClosedProxy) {
+ StartEmbeddedServer();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Give an initial page an unload handler that never completes.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
+ "window.onunload=function(e){ while(1); };\n"));
+
+ // Open a popup in the same process.
+ Shell* new_shell =
+ OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
+ FrameTreeNode* popup_root =
+ static_cast<WebContentsImpl*>(new_shell->web_contents())
+ ->GetFrameTree()
+ ->root();
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+
+ // Navigate the first tab to a different site, and only wait for commit, not
+ // load stop.
+ RenderFrameHostImpl* rfh_a = root->current_frame_host();
+ SiteInstanceImpl* site_instance_a = rfh_a->GetSiteInstance();
+ TestFrameNavigationObserver commit_observer(root);
+ shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ commit_observer.WaitForCommit();
+ rfh_a->ResetSwapOutTimerForTesting();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+ EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
+
+ // The previous RFH should still be pending deletion, as we wait for either
+ // the SwapOut ACK or a timeout.
+ ASSERT_TRUE(root->render_manager()->IsPendingDeletion(rfh_a));
+
+ // Kill the old process.
+ RenderProcessHost* process = rfh_a->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ process->Shutdown(0, false);
+ crash_observer.Wait();
+ EXPECT_FALSE(popup_root->current_frame_host()->IsRenderFrameLive());
+ // |rfh_a| is now deleted, thanks to the bug fix.
+
+ // Close the popup so there is no proxy for a.com in the original tab.
+ new_shell->Close();
+ EXPECT_FALSE(
+ root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
+
+ // Go back in the main frame from b.com to a.com. In https://crbug.com/581912,
+ // the browser process would crash here because there was no main frame
+ // routing ID or proxy in RVHI::CreateRenderView.
+ {
+ TestNavigationObserver back_nav_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_nav_load_observer.Wait();
+ }
+}
+
+// Ensure that we don't create in RenderViewImpl::Init if a proxy is created
alexmos 2016/03/29 18:43:01 nit: word missing after "don't create"?
Charlie Reis 2016/03/29 20:29:02 Heh, s/create/crash/. Thanks for catching it.
+// after swapout and before navigation. See https://crbug.com/544755.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ RenderViewInitAfterNewProxyAndProcessKill) {
+ StartEmbeddedServer();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Give an initial page an unload handler that never completes.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
+ "window.onunload=function(e){ while(1); };\n"));
+
+ // Navigate the tab to a different site, and only wait for commit, not load
+ // stop.
+ RenderFrameHostImpl* rfh_a = root->current_frame_host();
+ SiteInstanceImpl* site_instance_a = rfh_a->GetSiteInstance();
+ TestFrameNavigationObserver commit_observer(root);
+ shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ commit_observer.WaitForCommit();
+ rfh_a->ResetSwapOutTimerForTesting();
+ EXPECT_NE(site_instance_a, shell()->web_contents()->GetSiteInstance());
+
+ // The previous RFH should still be pending deletion, as we wait for either
+ // the SwapOut ACK or a timeout.
+ ASSERT_TRUE(root->render_manager()->IsPendingDeletion(rfh_a));
alexmos 2016/03/29 18:43:02 Is it worth checking that the view is pending dele
Charlie Reis 2016/03/29 20:29:02 Good idea. Done. (I made them EXPECT rather than
+
+ // Open a popup in the new B process.
+ Shell* new_shell =
+ OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+
+ // Navigate the popup to the original site, but don't wait for commit (which
+ // won't happen). This creates a proxy in the original tab, alongside the
+ // RFH and RVH pending deletion.
+ new_shell->LoadURL(embedded_test_server()->GetURL("a.com", "/title2.html"));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
alexmos 2016/03/29 18:43:02 Is this the right thing to use? (As opposed to Are
Charlie Reis 2016/03/29 20:29:02 Actually, I don't remember why I needed to guard t
+ EXPECT_TRUE(
+ root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
+ }
+
+ // Kill the old process.
+ RenderProcessHost* process = rfh_a->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ process->Shutdown(0, false);
+ crash_observer.Wait();
+ // |rfh_a| is now deleted, thanks to the bug fix.
+
+ // Go back in the main frame from b.com to a.com.
+ {
+ TestNavigationObserver back_nav_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_nav_load_observer.Wait();
+ }
+
+ // In https://crbug.com/581912, the renderer process would crash here because
+ // there was a frame, view, and proxy (and is_swapped_out was true).
+ EXPECT_EQ(site_instance_a, root->current_frame_host()->GetSiteInstance());
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_TRUE(new_shell->web_contents()->GetMainFrame()->IsRenderFrameLive());
+}
+
// Ensure that we use the same pending RenderFrameHost if a second navigation to
// its site occurs before it commits. Otherwise the renderer process will have
// two competing pending RenderFrames that both try to swap with the same

Powered by Google App Engine
This is Rietveld 408576698