Closed Bug 1440262 Opened 3 years ago Closed 3 years ago

setTimeout/setInterval stop working if you refresh a page with onbeforeunload in an iframe

Categories

(Core :: DOM: Core & HTML, defect, P2)

58 Branch
defect

Tracking

()

RESOLVED FIXED
mozilla61
Tracking Status
firefox59 --- wontfix
firefox60 --- wontfix
firefox61 --- fixed

People

(Reporter: yann.flory, Assigned: farre)

Details

Attachments

(2 files)

User Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0
Build ID: 20180208175058

Steps to reproduce:

Create a HTML page containing an iframe using "unbeforeunload" like in this document: https://cryptpad.fr/code/#/1/view/CM07AbsX7yX-4RcDX8VkJA/dlLY4ww0ASkFc7gL1u4WtpDYYQm56OxGf6c8-K8xPws/
Focus the iframe with a click and press F5. When the onbeforeunload modal appears, press F5 again.


Actual results:

setInterval and setTimeout stop working in the tab, even if you reload again, and on any site you visit


Expected results:

setInterval and setTimeout should still work after a page reload
User Agent 	Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Build ID 	20180226230123

Hi yflory,

I've created a page with your specifications and after each refresh I can see a "timeout  setTimout.html:10" line in the Browser Console(Ctrl+Shift+J), followed by many "interval setTimout.html:7" lines.

How do I know if setInterval and setTimeout have stopped working?

I've got the same behavior on Windows 10, Mac 10.12 and Arch Linux.
Flags: needinfo?(yann.flory)
I can reproduce the issue with Firefox 58 on Ubuntu 16.04 and Mac.
I've hosted an example at this page:
http://ansuz.science:8000/parent.html

To reproduce, I have to make sure the iframe is focused by clicking on the top-left rectangle.
Then I hit F5 and the "onbeforeunload" modal appears. The issue appears only when I hit F5 again while this modal is displayed ("This page is asking you to confirm that you want to leave - data you have entered may not be saved.").

When the page is reloaded, I don't see 'timeout' anymore in the console, and it also fails if I try to use setTimeout directly in the same tab: setTimeout(function () { console.log('test'); })
Flags: needinfo?(yann.flory)
@yflory, sorry I haven't managed to get around to this yet. It seems the page is unreachable now.

Could you please host it again so that I can try to reproduce this issue? Also, could you please check and see if this issue is also reproducible on the latest Nightly build (https://nightly.mozilla.org) ?
Flags: needinfo?(yann.flory)
Sorry, the server was down, it's fixed now: http://ansuz.science:8000/parent.html

I've just tested on Firefox Nightly 61.0a1 (2018-03-25) (64-bit) on Ubuntu 16.04, and I can reproduce the issue.
Flags: needinfo?(yann.flory)
@yflory, I somehow missed that I wasn't supposed to take any action in the onbeforeunload modal.

I was able to reproduce this issue on the latest Firefox release (59.0.1) and the latest Nightly (61.0a1) on Windows 10 x64, Mac 10.13.3 and Arch Linux x64. I was also able to reproduce with the initial page I created (https://jsfiddle.net/qjLd9bar/).

I'm not sure which of Core :: DOM : Core & HTML and Core :: DOM : Events is the correct component.
Status: UNCONFIRMED → NEW
Component: Untriaged → DOM
Ever confirmed: true
OS: Unspecified → All
Product: Firefox → Core
Hardware: Unspecified → All
Summary: Refresh a page with onbeforeunload in an iframe and setTimeout/setInterval stop working → setTimeout/setInterval stop working if you refresh a page with onbeforeunload in an iframe
Andreas, do you have any bandwidth to look at this?
Flags: needinfo?(afarre)
I'll take a look.
Assignee: nobody → afarre
Flags: needinfo?(afarre)
Attached file index.html
Ran mozregression and this bug is present before 2015-01-01 (builds from 2009 doesn't start for me, so I randomly picked a time in the past). It starts appearing when e10s is enabled, and from what I see happening it is that when we close the unload modal dialog (by reloading) we fail leaving modal state, and effectively leaving the window suspended.

This also means that it isn't only happening for onbeforeunload. Reloading when an alert dialog is showing will leave suspended windows. See attachment. STR is to wait for the dialog then press reload (button, F5 or Ctrl-Shift-R).

It seems that the modal dialog needs to be opened by the iframe for it to happen.

I'll look into this. Ben, you don't happen to know exactly where we'd expect the call to LeaveModalState to happen? If I find it before you see this I'll remove the ni.
Flags: needinfo?(bkelly)
I'm sorry, I really don't know.  When I looked at modal state stuff it was after the switch to e10s.

One question, though, do we get the correct behavior today if you run firefox with e10s disabled?
Flags: needinfo?(bkelly)
Yep, we get the correct behaviour with --disable-e10s.

So what after some more digging is that we can fail in two ways. In nsGlobalWindowOuter::LeaveModalState, which actually does get called, we either fail because we can't find a scriptable top or we fail because we decrease topWin->mModalStateDepth below 0 (even though we have only called Enter and Leave once each). Starting rr to see when topWin->mModalStateDepth is set to 0 erroneously.
Ok, now I have narrowed it down further:

nsDocShell::LoadURI about:blank
virtual nsresult nsDOMWindowUtils::EnterModalState(): this=0x7f28c175edf0, window=0x7f28c000b820, top=0x7f28c0039490
nsDocShell::LoadURI http://localhost:8000/reload/
nsDocShell::LoadURI about:blank
virtual nsresult nsDOMWindowUtils::LeaveModalState(): this=0x7f28c175edf0, window=0x7f28c000b820, top=(nil)
nsDocShell::LoadURI about:newtab
nsDocShell::LoadURI about:newtab
nsDocShell::LoadURI http://localhost:8000/reload/
nsDocShell::LoadURI http://localhost:8000/reload/
nsDocShell::LoadURI about:blank
virtual nsresult nsDOMWindowUtils::EnterModalState(): this=0x7fca831611f0, window=0x7fca8654fc20, top=0x7fca940af2a0
nsDocShell::LoadURI http://localhost:8000/reload/
nsDocShell::LoadURI about:blank
virtual nsresult nsDOMWindowUtils::LeaveModalState(): this=0x7fca831611f0, window=0x7fca8654fc20, top=0x7fca940afe40

The important thing is the value of top (which is the result of nsPIDOMWindowOuter::GetScriptableTop()), pressumably the load done messes up the tree.
Priority: -- → P2
So, thing is that nsDOMWindowUtils::{EnterModalState, LeaveModalState} both operate on scriptable top, through nsGlobalWindowOuter::{EnterModalState, LeaveModalState} calling GetScriptableTop. Problem is that when reloading with an open prompt the nsGlobalWindowOuter that opened the prompt could've been detached. Pre-e10s this is ok since we'll always close prompts before unloading. Post-e10s closing a prompt is a sequence of events that at best interleave with the unload. When this happens, and we try to call nsDOMWindowUtils::LeaveModalState it will either find a null top, or the wrong top, leaving us in either a suspended state of 1, or and underflowed suspended state of uint max.

From what I can tell there is no reason for why we couldn't call nsDOMWindowUtils::{EnterModalState, LeaveModalState} on window.top directly, which is what this patch does.

https://treeherder.mozilla.org/#/jobs?repo=try&revision=3b61a8eab86318a7a317df34e50d18c55e65e9bb&group_state=expanded
Attachment #8971202 - Flags: review?(bugs)
Comment on attachment 8971202 [details] [diff] [review]
0001-Bug-1440262-Enter-exit-modal-state-on-scriptable-top.patch

Looks reasonable
Attachment #8971202 - Flags: review?(bugs) → review+
Keywords: checkin-needed
Pushed by csabou@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/ba1278f999e0
Enter/exit modal state on scriptable top window. r=smaug
Keywords: checkin-needed
https://hg.mozilla.org/mozilla-central/rev/ba1278f999e0
Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla61
QA Whiteboard: [good first verify]
Component: DOM → DOM: Core & HTML
You need to log in before you can comment on or make changes to this bug.