When we cancel a pending/speculative RFH, we call RenderFrameHostManager::DiscardUnusedFrame, which contains a check of whether the RFH being canceled is in a SiteInstance that has other active frames. If so, it tries to leave a proxy in place of the RFH. However, the logic for doing so seems broken:
// If the SiteInstance for the pending RFH is being used by others don't
// delete the RFH. Just swap it out and it can be reused at a later point.
// In --site-per-process, RenderFrameHosts are not kept around and are
// deleted when not used, replaced by RenderFrameProxyHosts.
SiteInstanceImpl* site_instance = render_frame_host->GetSiteInstance();
if (site_instance->HasSite() && site_instance->active_frame_count() > 1) {
// Any currently suspended navigations are no longer needed.
render_frame_host->CancelSuspendedNavigations();
// If a proxy already exists for the |site_instance|, just reuse it instead
// of creating a new one. There is no need to call SwapOut on the
// |render_frame_host|, as this method is only called to discard a pending
// or speculative RenderFrameHost, i.e. one that has never hosted an actual
// document.
RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(site_instance);
if (!proxy) {
proxy = CreateRenderFrameProxyHost(site_instance,
render_frame_host->render_view_host());
}
If there is no existing proxy, CreateRenderFrameProxyHost creates it only on the browser side; there is no call to InitRenderFrameProxy to actually create it in the renderer.
Repro steps to show that not having a proxy breaks script connections when it shouldn't:
1) Navigate to http://csreis.github.io
2) In devtools, execute window.open("http://tests.netsekure.org/empty.html")
3) Go back to first tab, and in devtools, execute window.open("","foo")
4) In the new tab from step 3, navigate to http://tests.netsekure.org/redirect.php via omnibox
5) This will redirect to http://tests.netsekure.com/. Open DevTools, and execute:
window.addEventListener("message",(e) => console.log(e.data))
6) Go back to first tab (csreis.github.io), and navigate to http://tests.netsekure.org/empty.html.
7) From devtools, execute
window.open("","foo").postMessage("asdf","*")
Step (7) should look up the middle tab "foo" (currently showing "http://tests.netsekure.com/") and send it a postMessage, which should be printed on the console of that tab (thanks to handler from step 5).
Without --site-per-process, this works.
With --site-per-process, this doesn't work. The postMessage isn't delivered, presumably because there's no actual proxy created for the "foo" tab in the tests.netsekure.org renderer.
Additionally, the RenderView that is left around in this case is in an inconsistent state, thinking that it's still swapped in and that it has a main frame/widget; this is causing the CreateRenderView crash in https://crbug.com/627400#c21 and probably other issues.
Comment 1 by bugdroid1@chromium.org
, Oct 14 2016