onblur event is going to infinite loop.
Reported by
alagar...@modeln.com,
Nov 17 2016
|
||||||||||||||||
Issue description
UserAgent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Steps to reproduce the problem:
1. validating data provided in box.
2. error alert came.
3. On click ok. we want to get focus on box again. but again alert appears and making infinite loop.
What is the expected behavior?
Once we click on ok button of alert. we should get the focus on box.
What went wrong?
On click ok in alert msg. we want to get focus on box again. but again alert appears and making infinite loop.
Did this work before? N/A
Chrome version: 54.0.2840.99 Channel: stable
OS Version: 6.1 (Windows 7, Windows Server 2008 R2)
Flash Version: Shockwave Flash 23.0 r0
my method is below which is working properly on other browser.
function validateLastQty(box, prevQty) {
if(!isValidNum(box)) return false;
var valueEntered = matrixParseNumber(box.value);
if (prevQty*1 + 1 > valueEntered) {
var msg = "The value entered (" + valueEntered + ") must be bigger than " + matrixAddCommas(prevQty*1 + 1);
showSoftError(msg);
alert(msg);
box.focus();
return false;
}
return true;
}
,
Nov 17 2016
Attaching a case with the behavior. WARNING: THIS LOCKS UP THE ENTIRE BROWSER! Run it in a chromium build or some place that's easy to identify and kill the process. The discussion linked to in comment #1 implies that this change was introduced somewhere in the M52 timeframe. If it's possible to bisect, that would be great, but note the WARNING above.
,
Nov 18 2016
,
Nov 18 2016
Able to reproduce this issue on windows 10, Mac 10.11.4,Linux Ubuntu 14.04 with Chrome stable version-53.0.2785.143 and Canary. Manual Bisect: Bad Build—54.0.2840.99 Good Build—53.0.2744.0 Unable to provide the tool bisect as good & bad builds are from different milestones, hence providing manual change log from Omahaproxy: Manual Change log- https://chromium.googlesource.com/chromium/src/+log/53.0.2744.0..54.0.2840.0?pretty=fuller&n=10000 Review-Url: https://codereview.chromium.org/2252913003 avi@ assigning to you, as you were listed as one of the reviewers for this CL. Kindly take a look and please help us to reassign this issue to a right owner if not with respect to this change. Thanks.!
,
Nov 18 2016
schenney, that is not a proper reduction. The original poster's function has an out that allows the defocus. Your reduction always re-focuses and forces an infinite loop no matter what. I'm attaching a better repro. It wants you to type "hello" into the text box. What seems to be happening is that calling focus() on the text field is triggering the onblur property, which is weird. Let me find someone in Blink to take a look at this.
,
Nov 18 2016
Actually, schenney, I was wrong. That is a proper reduction; on Chrome it spews dialogs incessantly whereas in other browsers it doesn't.
,
Nov 18 2016
kochi, you've fixed quite a few Blink focus issues. Can you take a look at this?
,
Nov 21 2016
This is currently being exploited in the wild by tech support scammers.
,
Nov 21 2016
Taking a look.
,
Nov 21 2016
I think I can reproduce the issue using attached html in c#3 or c#6, and understand what the issue is. However the dialog shows a "Prevent this page from creating additional dialogs" checkbox and if I check on the box I can escape from the infinite loop, though this is not a proper solution for this anyway. So I am not sure I am experiencing "WARNING: THIS LOCKS UP THE ENTIRE BROWSER!" correctly - (at my first impression on reading comments, I thought you can never escape from the infinite loop.)
,
Nov 21 2016
On the other hand, I checked other browsers on mac, on Safari 10: shows the same dialog, without "Prevent this page..." checkbox and fall into an infinite loop. Only way to escape from it (as far as I found) is to focus on URL bar and type other URL. on Firefox 50.0, shows the dialog, and click on "OK" button - then the dialog closes, but focus is gone somewhere not in the original input box, and clicking on input box doesn't restore the focus. So to me, neither one of these browsers (Chrome, Safari, Firefox) is working as expected.
,
Nov 24 2016
Apparently, avi's CL in https://codereview.chromium.org/2252913003 shouldn't be a suspect, as it is mac-only. I tried bisect myself, and got the range 394784(good)...394794(bad). Tried running the sample attached to c#6, type "hel" and click outside the input. The alert popup shows, and clicking the OK button should return the focus to the input field. Bad revisions will infinitely repeat the alert dialogs. The above range pointed me to https://chromium.googlesource.com/chromium/src/+log/ae9b7a05e087905774fb29807281fa771711ff3b..a4df8ada22f3d15ad7153a369c780795797dfa1d which does not seem to contain any suspicious change. I'll try again.
,
Nov 24 2016
Another bisect got the range of 394879...394885, https://chromium.googlesource.com/chromium/src/+/6ed4d4373c5ce4743850df50f94b867240472033 among which https://codereview.chromium.org/1931793002 looks suspicious. Reverting it seems not trivial as it is 6 months ago. Adding changwan@. Changwan, if you are familiar with the change and can try reverting it would fix the repro case in c#6, could you own this?
,
Nov 24 2016
Hmm... Not sure if reverting the change is the best course of action here. I wonder why we get onblur event when alert() dialog gets dismissed. box.focus() gets the box to be focused first, then it ends up calling onblur somehow...
,
Nov 24 2016
I wanted to check if reverting the CL changes the issue exposure or not, and I didn't intend to revert the CL to fix this issue. I can look into what is happening in Blink internally next week, and at this point I'm not sure the chromium-side only change https://codereview.chromium.org/1931793002 is the real cause.
,
Nov 25 2016
I haven't tried reverting it, but I think it has likely caused the changed behavior here. Previously, box.focus() was called in the background in a nested loop while alert() is being shown to the user - alert()'s dismissal moved focus back to the document and to the box. Now box.focus() is called after alert() gets dismissed. If alert()'s dismissal moved focus back to document/body and not to the box, then I think this infinite loop can happen.
,
Nov 28 2016
Looks like https://codereview.chromium.org/2532853002 (partially revert the changwan's CL to restor DoNotNotifyWebKitOfModalLoop() et al.) fixes this issue (and probably breaks something else). I'll take further look.
,
Nov 29 2016
For comment#12 about Safari - https://bugs.webkit.org/show_bug.cgi?id=18315 looks like a still-open bug.
,
Nov 30 2016
Here's my observation on Linux about the sequences before and after the change. The sequence of old behavior (good one) is: 1. Renderer: window.alert() is called 2. Browser: shows popup dialog 3. Browser: sends InputMsg_SetFocus(false) 4. Renderer: receives InputMsg_setFocus(false) and handle it 5. User: Clicks "OK" button on the dialog 6. Renderer: script continues, box.focus() is called 7. Browser: sends InputMsg_SetFocus(true) And after changwan's CL landed the sequence (bad one) is: a. Renderer: window.alert() is called b. Browser: shows popup dialog c. Browser: sends InputMsg_SetFocus(false) => The message is blocked, renderer is not pumping d. User: Clicks "OK" button on the dialog e. Renderer: script continues, box.focus() is called f. Browser: sends InputMsg_SetFocus(true) g. Renderer: receives InputMsg_setFocus(*false*) and handle it (The big difference is step c. and g.) While window.alert() dialog is shown, the sync message to show the popup was still pumping the messages and handle them, but now it is completely blocked until dialog is dismissed. So now it receives InputMsg_SetFocus(false) to blur the page focus, after the dialog is dismissed - then onblur handler is called.
,
Nov 30 2016
Hmm... Is it possible to handle InputMsg_SetFocus(true) before we resume on the script? Dismissal signal is also propagated from browser to renderer, anyways. Can we propagate dismissal and focus change at the same time? Alex, what do you think about this?
,
Nov 30 2016
I guess once the sync message (to show alert dialog) returns, Blink continues the execution of the script - thus the box.focus() is executed immediately after dialog is dismissed, then deferred messages are handled.
,
Nov 30 2016
Now I think this boils down to the following question: Does window.alert() and other modal dialog really blur focus from the originating window? - if yes, shall we dispatch onblur synchronously when window.alert() is executed? (How can we?) - if no, shall we ignore / treat specially from the window deactivation message from browser process? Can all messages delivered while popup is open be drained? Probably this is a gray area in terms of standard specifications, therefore interoperability is not guaranteed if window.alert() is used within focus or blur handlers, but anyway...
,
Nov 30 2016
I checked Edge behavior, and alert() didn't dispatch focus-related events in Edge.
,
Dec 1 2016
Found some relevant discussion at WebKit bugzilla: https://bugs.webkit.org/show_bug.cgi?id=33962 - In comment 2 (old browsers behavior) > Firefox 3.5.7 executes the 'onblur' handler when the modal dialog appears. > IE8 executes the 'onblur' handler when the modal dialog appears. > Safari 4.0.4 on Windows does not execute the 'onblur' handler at all. > WebKit ToT executes the 'onblur' handler while the dialog is up and > fires the timer while the dialog is up. - In comment 12 > window.alert(), window.pause(), and window.prompt() all require > the user agent to 'pause' which is defined at > http://dev.w3.org/html5/spec/Overview.html#pause - In comment 15 > Note that Firefox will fire an image onload event behind > a modal dialog when the image load finishes. - In comment 16 > Firing events on a page that is already in a modal UI means > more JS reentrancy. Very few JS developers are prepared to > handle reentrancy, that's a good reason to 'freeze' the page > behind the modal UI. - In comment 18 > I believe that's a bug in Firefox. JavaScript is supposed to > run to completion without any interleaving threads. I'll research more about other browser/platform behaviors on window.alert()/tab switch/app switch.
,
Dec 1 2016
Re #26, comment 12 is the reason why we had to introduce the alert() behavior change. Thanks for looking into this!
,
Dec 1 2016
The link in #26 is now https://html.spec.whatwg.org/#pause (reference for pause in the whatwg spec).
,
Dec 2 2016
So, in the pre-M52 world, since there was a nested message loop still running JS, it needed to do onBlur at the beginning and onFocus when the message was cleared, to avoid the page still being weirdly interactable while the alert box was up. After M52, this should no longer be needed since the Blink main thread is blocked, and conversely it's even actively harmful since the asynchronously posted blur event can arrive after a JS focus call. So I think we should just try and delete this blur/focus code; I think it's obsolete and hopefully it shouldn't cause any new bug to do so (the only thing to watch out for is an overhang of MouseMove spam, we should make sure that's coalesced properly).
,
Dec 5 2016
,
Jan 20 2017
Issue 682557 has been merged into this issue.
,
Jan 20 2017
,
Feb 1 2017
Any code snippet for the fix? I'm trying getting the error in google chrome version 52+, in JSF on blur event. Kindly do the needful
,
Feb 2 2017
+dcheng, feel free to comment on this.
,
Feb 11 2017
Are there any fix planned for this bug by Google chrome in the subsequent versions? Kindly suggest any workarounds for this bug.
,
Feb 20 2017
Fix work in progress: https://codereview.chromium.org/2702243002/
,
Feb 21 2017
With this test JSbin (see focus/blur on window when popup happens): http://jsbin.com/yorori/1/edit?html,console,output On IE, Edge and Firefox, "blur" event dispatched to window upon popup appearance. On Safari and Chrome, "blur" event dispatched to window *after* popup closes. So not sending a "blur" event isn't a solution here, considering interoperability. The patch on c#37 removed sending blur on popup window, but I have to give up the idea. (Also, a few browser tests that depend on blur event to be sent failed.) So with nested message loop disabled for Chrome, Blink could dispatch "blur" event before asking browser process to show popup window (the order is somewhat speculative, but from JS point of view it is synchronous) to match Firefox / Edge / IE behavior. aelias@, do you see any issue/other ideas?
,
Feb 21 2017
OK, I see the events are automatically generated by OS-level focus change. I had assumed there was some explicit code for alert() that we could delete, but it's not so simple. > So with nested message loop disabled for Chrome, Blink could dispatch "blur" event before asking browser process to show popup window (the order is somewhat speculative, but from JS point of view it is synchronous) to match Firefox / Edge / IE behavior. This idea is fundamentally incompatible with the current model where the renderer main thread is fully blocked waiting for the alert() result. JS can't receive the blur() event in that interval, as the JS code that called alert() is still holding onto the thread. We definitely shouldn't reintroduce a nested message loop for this. One alternative idea is to reimplement alert() in terms of ES7 async await. This would also elegantly address related developer complaint http://crbug.com/639150 . Then JS would actually release the message loop while the alert box is up, and the code after the alert() call would implicitly be packaged into a closure. The effect would be similar to creating an HTML fixed-position box that provides a promise for the button result, and await its result with ES7 await. This would be something of a project that probably would call for a Blink intent to ship and coordination with other browser vendors, but I'd support you if you have the cycles to take it on. In the short term though, given that you've found the current behavior is interoperable with Safari, I don't think we should introduce any weird compromise behavior. Developers who really care about this problem can themselves switch to a custom ES7 await-based polyfill instead of using alert().
,
Feb 22 2017
Thanks aelias@ for the excellent summary! I totally agree on the last paragraph (... the current behavior is interoperable with Safari, ... (we should not) introduce any compromise behavior). And yeah, dispatching blur at window.alert() could well be broken, like blur event calls window.alert() etc. etc. I do not have much cycle at this moment on this issue, so changing the status to "Available" so anyone who has interest in this can take, and as this is not really a regression, changed the type to "Feature", and lowered priority.
,
Feb 22 2017
Hi, I'm Avi. I'm working on making alert dialogs less awful, and one of my key constraints is that alert() and friends block the JavaScript event loop. I didn't realize that reimplementing it with async await was an option. It's beyond my abilities, but that certainly does open up lots of possibilities. If we could also move sync XHR as well, we could be rid of engine blocking events and that could be a huge win for complexity, allowing us to simplify things. I would love to see this happen, though I'm not sure who to talk to to try to make it so.
,
Feb 22 2017
#41 - I hardly believe that making alert() asynchronous would be web compatible.
,
Feb 22 2017
#41 - I have no idea if it would be. I didn't think it was a possibility. Re comment #39, maybe? aelias@, can you clarify?
,
Feb 22 2017
I think it might well be web-compatible because async await is indistinguishable from running a nested message loop for most practical purposes. In both cases, JS events are fired in the interval while the alert() call is running, then execution continues on the next line after alert() returns. According to dcheng@ at https://groups.google.com/a/chromium.org/forum/#!topic/scheduler-dev/FaWVXvggvWA, sync XHR also involves a nested message loop so we could consider it for that as well. There may be some deeper problems I don't realize, but prima facie it doesn't seem insane. dcheng@ and caitp@, any thoughts on this?
,
Feb 27 2017
According to adamk@ from V8 team, my async await idea is totally impossible because that primitive is not powerful/dynamic enough. The outer function that await is inside needs to be marked "async" at compile time in order to create some global tables. There is no way to do it at the time that alert() executes (which could be something like an exec of a string). So I don't think there's anything we can do better here unfortunately, WontFixing this.
,
Mar 24 2017
,
Jul 21 2017
,
Jul 25 2017
Is this issue going to have it's status changed from WontFix? My comments on this issue were made on Issue 703407 . We need to know if you will fix this bug or if we need to direct Users to a different browser that doesn't crash on expected browser behavior. A JavaScript .focus() to a form field should not cause the onblur event to occur by the browser. The onblur attribute is supposed to fire the moment that the form element loses focus, not when it gains focus by User interaction or by JavaScript.
,
Jul 26 2017
As I'm told from avi@ is that "The intended escape hatch for infinite dialogs is closing the tab.", so if you got into infinite loop situation, you have to close the tab, and is expected behavior on Chrome.
,
Aug 16 2017
Frankly, this is unacceptable. I mean.. sure.. closing the tab is a reasonable catch-all for unexpected infinite loops, but this is standard javascript for handling alerting the user to a bad entry in a text box. Are you actually asking people to switch browsers if they have problems fat fingering text boxes? I don't see why you can't revert this to operate the way it did before it was broken.
,
Aug 17 2017
Found this chrome bug this morning working on app that uses an onblur to validate a date field via a native browser alert. I end up in an infinite alert loop I have to kill the tab to get out of. Here's a simple workaround for those in the same boat.
Simply store the input value, clear the input field, focus the input field and restore the input value.
var temp = datefield.value;
datefield.value = '';
setTimeout(function () {
datefield.focus();
datefield.value = temp;
}, 0);
It isn't a perfect fix as if the blur event fires again (either outside the input field or browser), the alert fires again. This fix lets the user correct the input value (the input is focused at this point with the old value) to a correct value so the alert doesn't fire on the next blur.
,
Sep 29 2017
,
Sep 29 2017
,
Feb 16 2018
,
May 31 2018
Issue 847843 has been merged into this issue. |
||||||||||||||||
►
Sign in to add a comment |
||||||||||||||||
Comment 1 by alagar...@modeln.com
, Nov 17 2016