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

Issue 706319 link

Starred by 2 users

Issue metadata

Status: Fixed
Owner:
Closed: May 2017
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 1
Type: Bug



Sign in to add a comment

SEGV_MAPERR when calling print() on unload.

Project Member Reported by arthurso...@chromium.org, Mar 29 2017

Issue description

Chromium:	59.0.3055.0 (Developer Build) (64-bit)
Revision:	991596180e69f17e1bc3828061b420821194031d
OS: Linux

What steps will reproduce the problem?
(1) Navigate to <body onUnload="print()"></body>
(2) Go back.

Then, you will see an error on the console:

Received signal 11 SEGV_MAPERR 000000000080
#0 0x2b033ee94aab base::debug::StackTrace::StackTrace()
#1 0x2b033ee937ac base::debug::StackTrace::StackTrace()
#2 0x2b033ee945bf base::debug::(anonymous namespace)::StackDumpSignalHandler()
#3 0x2b033eb00330 <unknown>
#4 0x2b034f770c49 blink::Frame::setIsLoading()
#5 0x2b034f770523 blink::WebRemoteFrameImpl::didStopLoading()
#6 0x2b0344d7edfd content::RenderFrameProxy::OnDidStopLoading()
#7 0x2b0342cab741 _ZN4base20DispatchToMethodImplIPN7content14GpuChildThreadEMS2_FvvERKSt5tupleIJEEJEEEvRKT_T0_OT1_NS_13IndexSequenceIJXspT2_EEEE
#8 0x2b0342cab6b0 _ZN4base16DispatchToMethodIPN7content14GpuChildThreadEMS2_FvvERKSt5tupleIJEEEEvRKT_T0_OT1_
#9 0x2b0344d86caf _ZN3IPC16DispatchToMethodIN7content16RenderFrameProxyEMS2_FvvEvSt5tupleIJEEEEvPT_T0_PT1_RKT2_
#10 0x2b0344d81df3 _ZN3IPC8MessageTI28FrameMsg_DidStopLoading_MetaSt5tupleIJEEvE8DispatchIN7content16RenderFrameProxyES7_vMS7_FvvEEEbPKNS_7MessageEPT_PT0_PT1_T2_
#11 0x2b0344d7dfd8 content::RenderFrameProxy::OnMessageReceived()
#12 0x2b0340cb196b IPC::MessageRouter::RouteMessage()
#13 0x2b0342d6da28 content::ChildThreadImpl::ChildThreadMessageRouter::RouteMessage()
#14 0x2b0340cb18ee IPC::MessageRouter::OnMessageReceived()
#15 0x2b0342d71cc7 content::ChildThreadImpl::OnMessageReceived()
#16 0x2b0340c5c838 IPC::ChannelProxy::Context::OnDispatchMessage()
#17 0x2b0340c6261f _ZN4base8internal13FunctorTraitsIMN3IPC12ChannelProxy7ContextEFvRKNS2_7MessageEEvE6InvokeIRK13scoped_refptrIS4_EJS7_EEEvS9_OT_DpOT0_
#18 0x2b0340c62506 _ZN4base8internal12InvokeHelperILb0EvE8MakeItSoIRKMN3IPC12ChannelProxy7ContextEFvRKNS4_7MessageEEJRK13scoped_refptrIS6_ES9_EEEvOT_DpOT0_
#19 0x2b0340c62493 _ZN4base8internal7InvokerINS0_9BindStateIMN3IPC12ChannelProxy7ContextEFvRKNS3_7MessageEEJ13scoped_refptrIS5_ES6_EEEFvvEE7RunImplIRKSA_RKSt5tupleIJSC_S6_EEJLm0ELm1EEEEvOT_OT0_NS_13IndexSequenceIJXspT1_EEEE
#20 0x2b0340c623ac _ZN4base8internal7InvokerINS0_9BindStateIMN3IPC12ChannelProxy7ContextEFvRKNS3_7MessageEEJ13scoped_refptrIS5_ES6_EEEFvvEE3RunEPNS0_13BindStateBaseE
#21 0x2b033ee9afee _ZNO4base8CallbackIFvvELNS_8internal8CopyModeE0ELNS2_10RepeatModeE0EE3RunEv
#22 0x2b033ee9a72e base::debug::TaskAnnotator::RunTask()
#23 0x2b034eb7ecc6 blink::scheduler::TaskQueueManager::ProcessTaskFromWorkQueue()
#24 0x2b034eb7bdbd blink::scheduler::TaskQueueManager::DoWork()
#25 0x2b034eb86ed4 _ZN4base8internal13FunctorTraitsIMN5blink9scheduler16TaskQueueManagerEFvbEvE6InvokeIRKNS_7WeakPtrIS4_EEJRKbEEEvS6_OT_DpOT0_
#26 0x2b034eb86ddf _ZN4base8internal12InvokeHelperILb1EvE8MakeItSoIRKMN5blink9scheduler16TaskQueueManagerEFvbERKNS_7WeakPtrIS6_EEJRKbEEEvOT_OT0_DpOT1_
#27 0x2b034eb86d53 _ZN4base8internal7InvokerINS0_9BindStateIMN5blink9scheduler16TaskQueueManagerEFvbEJNS_7WeakPtrIS5_EEbEEEFvvEE7RunImplIRKS7_RKSt5tupleIJS9_bEEJLm0ELm1EEEEvOT_OT0_NS_13IndexSequenceIJXspT1_EEEE
#28 0x2b034eb86c6c _ZN4base8internal7InvokerINS0_9BindStateIMN5blink9scheduler16TaskQueueManagerEFvbEJNS_7WeakPtrIS5_EEbEEEFvvEE3RunEPNS0_13BindStateBaseE
#29 0x2b033ee9afee _ZNO4base8CallbackIFvvELNS_8internal8CopyModeE0ELNS2_10RepeatModeE0EE3RunEv
#30 0x2b033ee9a72e base::debug::TaskAnnotator::RunTask()
#31 0x2b033ef2525d base::MessageLoop::RunTask()
#32 0x2b033ef254e4 base::MessageLoop::DeferOrRunPendingTask()
#33 0x2b033ef257d4 base::MessageLoop::DoWork()
#34 0x2b033ef3c8e8 base::MessagePumpDefault::Run()
#35 0x2b033ef24df7 base::MessageLoop::RunHandler()
#36 0x2b033efd049a base::RunLoop::Run()
#37 0x2b0340c9c0e7 IPC::SyncChannel::WaitForReplyWithNestedMessageLoop()
#38 0x2b0340c9c01f IPC::SyncChannel::WaitForReply()
#39 0x2b0340c9b924 IPC::SyncChannel::Send()
#40 0x2b0342d70877 content::ChildThreadImpl::Send()
#41 0x2b0344d917ea content::RenderThreadImpl::Send()
#42 0x2b0344d1768f content::RenderFrameImpl::Send()
#43 0x2b0342d1d642 content::RenderFrameObserver::Send()
#44 0x2b033b5852b8 printing::PrintWebViewHelper::RequestPrintPreview()
#45 0x2b033b584daf printing::PrintWebViewHelper::ScriptedPrint()
#46 0x2b0344d1763b content::RenderViewImpl::printPage()
#48 0x2b034f62a519 blink::ChromeClientImpl::printDelegate()
#49 0x2b035879291d blink::ChromeClient::print()
#50 0x2b0357f4d6ec blink::LocalDOMWindow::print()
#51 0x2b0358ed9219 blink::DOMWindowV8Internal::printMethod()
#52 0x2b0358ed91aa blink::V8Window::printMethodCallback()
#53 0x2b034d79b043 v8::internal::FunctionCallbackArguments::Call()
#54 0x2b034d8eb40f v8::internal::(anonymous namespace)::HandleApiCallHelper<>()
#55 0x2b034d8e9cc7 v8::internal::Builtin_Impl_HandleApiCall()
#56 0x18c5c7684264 <unknown>
  r8: 00007ffeba14ba58  r9: 0000000000000000 r10: 00000000000000ff r11: 0000000003599588
 r12: 0000000000000000 r13: 00007ffeba151128 r14: 00002858e8ef3020 r15: 00002b0358ed9170
  di: 0000000000000000  si: 0000000000000000  bp: 00007ffeba14b880  bx: 00007ffeba1510a0
  dx: 0000000000000000  ax: 0000000000000000  cx: 00002858e9006e20  sp: 00007ffeba14b880
  ip: 00002b034f770c49 efl: 0000000000010246 cgf: 0000000000000033 erf: 0000000000000006
 trp: 000000000000000e msk: 0000000000000000 cr2: 0000000000000080
[end of stack trace]

 
Labels: -Pri-2 Pri-1
I can reproduce it in the release channel.
Google Chrome	57.0.2987.110 (Official Build) (64-bit)
Revision	11f66db67ea1f20d200d6f9add50fc1c345d71f7-refs/branch-heads/2987@{#832}

Leaving this page causes a crash of the whole browser:
data:text/html,<body onunload="print();"></body>

https://crash.corp.google.com/browse?q=ClientID%3D%2741bbb53a6f644f3a900f478331965f2c%27&ignore_case=false&enable_rewrite=true&omit_field_name=&omit_field_value=&omit_field_opt=%3D&stbtiq=&reportid=714ebc1640000000&index=0#0
Owner: thestig@chromium.org
Status: Assigned (was: Untriaged)
Owner: creis@chromium.org
The GetFrame() call at the beginning of WebRemoteFrameImpl::DidStopLoading() returns a nullptr. Looks like that was originally from r187324, but nasko's status currently says away, so punting to creis to take a look.

BTW, RequestPrintPreview() is doing a nested message loop, so beware.

I also tried this in Firefox and it doesn't bother trying to print during onunload. IE/Edge don't seem to understand data: URLs?

Comment 4 by creis@chromium.org, Apr 12 2017

Owner: lfg@chromium.org
Thanks.  lfg@, could you or dcheng@ take a look at this?  FWIW, I'm ok with Firefox's approach of not printing during unload.

thestig@, could you check the revision link in comment 3?  I think it might be pointing to the wrong CL.

Comment 6 by dcheng@chromium.org, Apr 12 2017

Yes, ignoring print() on unload seems reasonable to me, and is something we've talked about doing in the past as well.

Comment 7 by dcheng@chromium.org, Apr 12 2017

Yes, ignoring print() on unload seems reasonable to me, and is something we've talked about doing in the past as well.

Comment 8 by lfg@chromium.org, Apr 26 2017

Status: Started (was: Assigned)
I've looked in to the crash, and it's a renderer crash in a cross-process transfer, which happens inside the printing nested message loop. Since the previous frame never committed the navigation (because we still are in the unload handler), we can't start processing messages from the browser process, because the renderer is in a bad state.

I agree that blocking print() in the unload handlers seems like a reasonable fix, but there are several ways of accomplishing this:

- Using LocalFrame::IsNavigationAllowed(), which relies on the FrameNavigationDisabler (which would allow printing as long as the frame can navigate).
- Using PluginScriptForbiddenScope which is intended to fix similar issues with flash nested message loops (see https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/PluginScriptForbiddenScope.h?l=14).
- Creating a new "PrintForbiddenScope" or similar.

Should we also block printing in the beforeunload handler? I've looked into other browsers behavior, and Firefox does block printing both on the unload and beforeunload handlers. Is that a behavior we want to match? Edge, for instance, allows printing in both handlers (but it doesn't work when it's in the unload handler, the dialog that shows up is broken; it does work when printing from the beforeunload handler).

Comment 9 by lfg@chromium.org, Apr 26 2017

Here's a test that reproduces the issue:

IN_PROC_BROWSER_TEST_F(ChromeSitePerProcessTest, PrintOnUnloadHandler) {
  ui_test_utils::NavigateToURL(
      browser(), GURL(embedded_test_server()->GetURL("a.com", "/title1.html")));

  content::WebContents* active_web_contents =
      browser()->tab_strip_model()->GetActiveWebContents();

  // Create 2 iframes and navigate them to b.com.
  EXPECT_TRUE(ExecuteScript(active_web_contents,
                            "var i = document.createElement('iframe'); i.id = "
                            "'child-0'; document.body.appendChild(i);"));
  EXPECT_TRUE(ExecuteScript(active_web_contents,
                            "var i = document.createElement('iframe'); i.id = "
                            "'child-1'; document.body.appendChild(i);"));
  EXPECT_TRUE(NavigateIframeToURL(
      active_web_contents, "child-0",
      GURL(embedded_test_server()->GetURL("b.com", "/title1.html"))));
  EXPECT_TRUE(NavigateIframeToURL(
      active_web_contents, "child-1",
      GURL(embedded_test_server()->GetURL("b.com", "/title1.html"))));

  content::RenderFrameHost* child_0 =
      ChildFrameAt(active_web_contents->GetMainFrame(), 0);
  content::RenderFrameHost* child_1 =
      ChildFrameAt(active_web_contents->GetMainFrame(), 1);

  // Add an unload handler that calls print() to child-0 iframe.
  EXPECT_TRUE(ExecuteScript(
      child_0, "document.body.onunload = function() { print(); }"));

  // Transfer child-0 to a new process hosting c.com.
  EXPECT_TRUE(NavigateIframeToURL(
      active_web_contents, "child-0",
      GURL(embedded_test_server()->GetURL("c.com", "/title1.html"))));

  // Check that b.com's process is still alive.
  bool renderer_alive = false;
  EXPECT_TRUE(ExecuteScriptAndExtractBool(
      child_1, "window.domAutomationController.send(true);", &renderer_alive));
  EXPECT_TRUE(renderer_alive);
}

Let's just match Firefox's behavior.

That being said, why does the renderer end up in a bad state? Are there other nested message loops that can cause us to end up in this state? If so, simply blocking print() won't fix this. Maybe the IPC handler needs to be fixed to expect nested message loops and defer if necessary?

Comment 11 by lfg@chromium.org, May 26 2017

Status: Fixed (was: Started)
For some reason the bot didn't pick up the change. Fix has landed a couple of days ago:

https://codereview.chromium.org/2863203002/

Sign in to add a comment