Index: content/browser/frame_host/render_frame_host_manager_unittest.cc |
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc |
index b03471edd1eddc8504b2ec7409ed745e296c2258..c7180431dcd30354712723899dbae7886c42c061 100644 |
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc |
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc |
@@ -148,6 +148,29 @@ class RenderViewHostDeletedObserver : public WebContentsObserver { |
DISALLOW_COPY_AND_ASSIGN(RenderViewHostDeletedObserver); |
}; |
+// This observer keeps track of the last created RenderFrameHost to allow tests |
+// to ensure that no RenderFrameHost objects are created when not expected. |
+class RenderFrameHostCreatedObserver : public WebContentsObserver { |
+ public: |
+ RenderFrameHostCreatedObserver(WebContents* web_contents) |
+ : WebContentsObserver(web_contents), |
+ created_(false) { |
+ } |
+ |
+ virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) override { |
+ created_ = true; |
+ } |
+ |
+ bool created() { |
+ return created_; |
+ } |
+ |
+ private: |
+ bool created_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver); |
+}; |
+ |
// This observer keeps track of the last deleted RenderFrameHost to avoid |
// accessing it and causing use-after-free condition. |
class RenderFrameHostDeletedObserver : public WebContentsObserver { |
@@ -178,7 +201,6 @@ class RenderFrameHostDeletedObserver : public WebContentsObserver { |
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver); |
}; |
- |
// This observer is used to check whether IPC messages are being filtered for |
// swapped out RenderFrameHost objects. It observes the plugin crash and favicon |
// update events, which the FilterMessagesWhileSwappedOut test simulates being |
@@ -567,6 +589,47 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) { |
EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID)); |
} |
+// Ensure that frames aren't added to the frame tree, if the message is coming |
+// from a process different than the parent frame's current RenderFrameHost |
+// process. Otherwise it is possible to have collisions of routing ids, as they |
+// are scoped per process. See https://crbug.com/415059. |
+TEST_F(RenderFrameHostManagerTest, DropCreateChildFrameWhileSwappedOut) { |
+ const GURL kUrl1("http://foo.com"); |
+ const GURL kUrl2("http://www.google.com/"); |
+ |
+ // Navigate to the first site. |
+ NavigateActiveAndCommit(kUrl1); |
+ TestRenderFrameHost* initial_rfh = contents()->GetMainFrame(); |
+ { |
+ RenderFrameHostCreatedObserver observer(contents()); |
+ initial_rfh->OnCreateChildFrame( |
+ initial_rfh->GetProcess()->GetNextRoutingID(), std::string()); |
+ EXPECT_TRUE(observer.created()); |
+ } |
+ |
+ // Create one more frame in the same SiteInstance where initial_rfh |
+ // exists so that initial_rfh doesn't get deleted on navigation to another |
+ // site. |
+ initial_rfh->GetSiteInstance()->increment_active_frame_count(); |
+ |
+ // Navigate to a cross-site URL. |
+ NavigateActiveAndCommit(kUrl2); |
+ EXPECT_TRUE(initial_rfh->is_swapped_out()); |
+ |
+ TestRenderFrameHost* dest_rfh = contents()->GetMainFrame(); |
+ ASSERT_TRUE(dest_rfh); |
+ EXPECT_NE(initial_rfh, dest_rfh); |
+ |
+ { |
+ // Since the old RFH is now swapped out, it shouldn't process any messages |
+ // to create child frames. |
+ RenderFrameHostCreatedObserver observer(contents()); |
+ initial_rfh->OnCreateChildFrame( |
+ initial_rfh->GetProcess()->GetNextRoutingID(), std::string()); |
+ EXPECT_FALSE(observer.created()); |
+ } |
+} |
+ |
TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) { |
TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost(); |
TestRenderWidgetHostView* swapped_out_rwhv = |