Do not reuse a RenderViewHost that is in an inconsistent state.

When a COOP browsing context group swap happens we remove proxies
that were previously created. This can leave the associated
RenderViewHostImpl in an inconsistent state while the associated
frame is unloading. If we attempt to reuse this RenderViewHostImpl
in between the unload and a new navigation the renderer will crash
with a remote frame having already been registered. When we clear
out the RenderFrameProxyHosts we now mark the RenderViewHostImpl
as not supporting reuse and remove it from being registered with
the FrameTree which is queried when looking for matching
RenderViewHostImpls to reuse.

BUG=1145266

Change-Id: Ic30bc9d9dab297441fb6e4515cb632e63deafc99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3905787
Reviewed-by: Alex Moshchuk <[email protected]>
Commit-Queue: Dave Tapuska <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1050822}
diff --git a/content/browser/renderer_host/frame_tree_browsertest.cc b/content/browser/renderer_host/frame_tree_browsertest.cc
index d2a12fc8..40234b6 100644
--- a/content/browser/renderer_host/frame_tree_browsertest.cc
+++ b/content/browser/renderer_host/frame_tree_browsertest.cc
@@ -33,6 +33,7 @@
 #include "net/base/features.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
+#include "net/test/embedded_test_server/default_handlers.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "services/network/public/cpp/web_sandbox_flags.h"
@@ -1392,6 +1393,55 @@
   EXPECT_FALSE(root->HasTransientUserActivation());
 }
 
+class BrowserContextGroupSwapFrameTreeBrowserTest : public ContentBrowserTest {
+ public:
+  BrowserContextGroupSwapFrameTreeBrowserTest()
+      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    IsolateAllSitesForTesting(command_line);
+  }
+
+  void SetUpOnMainThread() override {
+    ContentBrowserTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
+    https_server_.ServeFilesFromSourceDirectory(GetTestDataFilePath());
+    https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+    net::test_server::RegisterDefaultHandlers(&https_server_);
+    ASSERT_TRUE(https_server_.Start());
+  }
+
+  net::EmbeddedTestServer* https_server() { return &https_server_; }
+
+ public:
+  net::EmbeddedTestServer https_server_;
+};
+
+// Force a race between when the RenderViewHostImpl's main frame is running
+// the unload handlers and when a new navigation occurs that tries to
+// reuse a RenderViewHostImpl.
+IN_PROC_BROWSER_TEST_F(BrowserContextGroupSwapFrameTreeBrowserTest,
+                       NavigateAndGoBack) {
+  GURL main_url(https_server()->GetURL("a.test", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  auto* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents());
+  web_contents->GetPrimaryMainFrame()->DoNotDeleteForTesting();
+  DisableBFCacheForRFHForTesting(
+      web_contents->GetPrimaryFrameTree().root()->current_frame_host());
+
+  // Load a page with COOP set to force the browsing context group swap
+  // and clears out old proxies.
+  GURL new_main_url(https_server()->GetURL(
+      "b.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"));
+
+  EXPECT_TRUE(NavigateToURL(shell(), new_main_url));
+
+  TestNavigationObserver back_load_observer(web_contents);
+  web_contents->GetController().GoBack();
+  back_load_observer.Wait();
+}
+
 // FrameTreeBrowserTest variant where we isolate http://*.is, Iceland's top
 // level domain. This is an analogue to isolating extensions, which we can use
 // inside content_browsertests, where extensions don't exist. Iceland, like an