New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 612276 link

Starred by 1 user

Issue metadata

Status: Fixed
Owner:
Closed: May 2016
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 3
Type: Bug



Sign in to add a comment

Race between creating and showing widgets with same routing IDs from OOPIFs in different processes

Project Member Reported by alex...@chromium.org, May 16 2016

Issue description

Currently, WebContentsImpl tracks pending widgets (widgets that are created but not yet shown) in the pending_widget_views_ map, which is keyed by the new widget's routing_id only.  Similarly, pending WebContents are tracked in pending_contents_, also keyed by a single routing_id.  This is prone to a race when two OOPIFs in different processes create new widgets, and the two widgets happen to use the same routing ID, colliding in one of these maps.  It seems that both of these maps should be keyed by (process_id, routing_id).

Here's a short test that illustrates the problem with pending WebContents:

IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
                       TwoSubframesCreateWidgetsSimultaneously) {
  GURL main_url(embedded_test_server()->GetURL(
      "a.com", "/cross_site_iframe_factory.html?a(b,c)"));
  EXPECT_TRUE(NavigateToURL(shell(), main_url));

  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
  FrameTreeNode* child1 = root->child_at(0);
  FrameTreeNode* child2 = root->child_at(1);

  EXPECT_TRUE(ExecuteScript(child1->current_frame_host(),
                            "setTimeout(function() { window.open() }, 0)"));
  EXPECT_TRUE(ExecuteScript(child2->current_frame_host(),
                            "setTimeout(function() { window.open() }, 0)"));
}

This is flaky, but it does hit the problem about 50% of the time for me, resulting in this crash:

[68575:68592:0516/143925:2753909165691:FATAL:resource_scheduler.cc(777)] Check failed: client_map_.empty(). 
#0 0x7f7c981e781e base::debug::StackTrace::StackTrace()
#1 0x7f7c9824a05f logging::LogMessage::~LogMessage()
#2 0x7f7c953efdc9 content::ResourceScheduler::~ResourceScheduler()
#3 0x7f7c953d404b std::default_delete<>::operator()()
#4 0x7f7c953c2e9c std::unique_ptr<>::reset()
#5 0x7f7c953b4422 content::ResourceDispatcherHostImpl::OnShutdown()
#6 0x7f7c9454be50 _ZN4base8internal15RunnableAdapterIMN7content17GpuWatchdogThreadEFvvEE3RunIPS3_JEEEvOT_DpOT0_
#7 0x7f7c953cc609 _ZN4base8internal12InvokeHelperILb0EvNS0_15RunnableAdapterIMN7content26ResourceDispatcherHostImplEFvvEEEE8MakeItSoIJPS4_EEEvS7_DpOT_
#8 0x7f7c953cc5cd _ZN4base8internal7InvokerINS_13IndexSequenceIJLm0EEEENS0_9BindStateINS0_15RunnableAdapterIMN7content26ResourceDispatcherHostImplEFvvEEEFvPS7_EJNS0_17UnretainedWrapperIS7_EEEEENS0_12InvokeHelperILb0EvSA_EEFvvEE3RunEPNS0_13BindStateBaseE
#9 0x7f7c981c79ee base::Callback<>::Run()
#10 0x7f7c981ed26e base::debug::TaskAnnotator::RunTask()
#11 0x7f7c9826781c base::MessageLoop::RunTask()
#12 0x7f7c98267ab8 base::MessageLoop::DeferOrRunPendingTask()
#13 0x7f7c98267d12 base::MessageLoop::DoWork()
#14 0x7f7c98281bfe base::MessagePumpLibevent::Run()
#15 0x7f7c9826720f base::MessageLoop::RunHandler()
#16 0x7f7c9830ffb4 base::RunLoop::Run()
#17 0x7f7c98266284 base::MessageLoop::Run()
#18 0x7f7c983a73a9 base::Thread::Run()
#19 0x7f7c94edac66 content::BrowserThreadImpl::IOThreadRun()
#20 0x7f7c94edb00e content::BrowserThreadImpl::Run()
#21 0x7f7c983a76f9 base::Thread::ThreadMain()
#22 0x7f7c983928ba base::(anonymous namespace)::ThreadFunc()

In the problematic runs, the sequence of calls is:

CreateNewWindow: process_id=4 routing_id=6
CreateNewWindow: process_id=5 routing_id=6
ShowCreatedWindow: routing_id=6
ShowCreatedWindow: routing_id=6

I don't think this is blocking launch, as I believe all operations triggering these new widgets require a user gesture (clicking on a <select> menu, clicking on a link to open a popup, fullscreening Flash), so the probability of this happening in practice is very low.  I'll assign to myself for now, since I already have drafts for a test and half of the fix.
 

Comment 1 by creis@chromium.org, May 16 2016

Cc: nasko@chromium.org
Wow, yes, it's never safe to use a routing ID without the corresponding process ID.  Thanks for catching this!

Are we sure this only affects OOPIF modes?  Not sure if a cross-process window.open (e.g., to a hosted app or CWS) could hit this path as well.
Since these maps are kept per-WebContents, I don't think it's possible to get a conflict unless two widgets are created from different processes which both belong to the same WebContents.  It's not possible to get two processes for the same WebContents outside of OOPIF modes, is it?

Comment 3 by creis@chromium.org, May 16 2016

Ah, good point.  Yes, should be OOPIF-specific.
Project Member

Comment 4 by bugdroid1@chromium.org, May 23 2016

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/c2a8cec37a56e92d29d91b936734cd1e5ee28734

commit c2a8cec37a56e92d29d91b936734cd1e5ee28734
Author: alexmos <alexmos@chromium.org>
Date: Mon May 23 22:19:53 2016

Track pending WebContents and widgets by (process_id, routing_id) pair.

Currently, WebContentsImpl tracks pending widgets (widgets that are
created but not yet shown) in the pending_widget_views_ map, which is
keyed by the new widget's routing_id only.  Similarly, pending
WebContents are tracked in pending_contents_, also keyed by a single
routing_id.  This is prone to a race when two OOPIFs in different
processes (but part of the same WebContents) create new widgets, and
the two widgets happen to use the same routing ID, colliding in one of
these maps.  This CL changes both of these maps to be keyed by
(process_id, routing_id).

BUG= 612276 ,  593522 
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_site_isolation

Review-Url: https://codereview.chromium.org/1986643002
Cr-Commit-Position: refs/heads/master@{#395435}

[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/browser_plugin/browser_plugin_guest.cc
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/frame_host/interstitial_page_impl.cc
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/frame_host/interstitial_page_impl.h
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/renderer_host/render_view_host_delegate.h
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/renderer_host/render_view_host_impl.cc
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/site_per_process_browsertest.cc
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/web_contents/web_contents_impl.cc
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/web_contents/web_contents_impl.h
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/browser/web_contents/web_contents_impl_unittest.cc
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/test/data/site_isolation/page-with-select.html
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/test/test_web_contents.cc
[modify] https://crrev.com/c2a8cec37a56e92d29d91b936734cd1e5ee28734/content/test/test_web_contents.h

Status: Fixed (was: Started)

Sign in to add a comment