Bug 184144 - Reproducible, recurring crash when the completion handler passed to -[runJavaScriptAlertPanelWithMessage:initiatedByFrame: completionHandler:] is deallocated without being called once
Summary: Reproducible, recurring crash when the completion handler passed to -[runJava...
Status: RESOLVED INVALID
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit2 (show other bugs)
Version: Other
Hardware: iPhone / iPad iOS 11
: P1 Major
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2018-03-29 12:03 PDT by AV
Modified: 2018-04-11 12:52 PDT (History)
8 users (show)

See Also:


Attachments
xCode Project (90.79 KB, application/zip)
2018-04-02 06:38 PDT, AV
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description AV 2018-03-29 12:03:29 PDT
1. Open a page that shows a Javascript alert/confirm/text-input prompt.
2. Destroy the WKWebView Object when the alert/prompt is active.
3. App crashes with any of the following errors depending on the type of prompt:

- Uncaught exception: Completion handler passed to -[WebViewController webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:] was not called
- Uncaught exception: Completion handler passed to -[WebViewController webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:] was not called
- Uncaught exception: Completion handler passed to -[WebViewController webView:runJavaScriptTextInputPanelWithPrompt: defaultText:initiatedByFrame:completionHandler:] was not called
Comment 1 AV 2018-03-29 22:33:01 PDT
I use this link to simulate an alert:

https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_alert
Comment 2 Alexey Proskuryakov 2018-04-01 23:05:40 PDT
Could you please attach a crash log, and a test project that reproduces this problem?
Comment 3 AV 2018-04-02 06:38:53 PDT
Created attachment 336981 [details]
xCode Project
Comment 4 AV 2018-04-02 06:43:23 PDT
I have attached a test project to reproduce this. Below is the crash logs. The scenario is, we delete a view controller when the app enters background and dismiss all active modals.

This crash happens when the alert view gets dismissed as part of clearing all active modals from the view before entering into the background state.

Is there a way to handle this other than manually keeping track of all active WebKit JS Modals and calling all their corresponding completion-handlers, as this seems to be a complex workaround?


------------------------------------------------------------------------------------

2018-04-02 19:06:36.665964+0530 webKitCompText[1175:13720] [MC] Reading from private effective user settings.
2018-04-02 19:06:38.173182+0530 webKitCompText[1175:13720] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Completion handler passed to -[ViewController webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:] was not called'
*** First throw call stack:
(
	0   CoreFoundation                      0x0000000109c4112b __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x00000001092d5f41 objc_exception_throw + 48
	2   CoreFoundation                      0x0000000109cb6245 +[NSException raise:format:] + 197
	3   WebKit                              0x0000000108529365 _ZN6WebKit28CompletionHandlerCallCheckerD2Ev + 129
	4   WebKit                              0x000000010856bfc4 _ZNK3WTF20ThreadSafeRefCountedIN6WebKit28CompletionHandlerCallCheckerEE5derefEv + 36
	5   WebKit                              0x0000000108605889 _ZZN3WTF8BlockPtrIFvvEE12fromCallableIZN6WebKit10UIDelegate8UIClient18runJavaScriptAlertEPNS4_12WebPageProxyERKNS_6StringEPNS4_13WebFrameProxyERKN7WebCore18SecurityOriginDataEONS_8FunctionIS1_EEE3$_1EES2_T_ENUlPKvE_8__invokeESO_ + 29
	6   libsystem_blocks.dylib              0x000000011205d99d _Block_release + 111
	7   webKitCompText                      0x000000010821796d __destroy_helper_block_ + 29
	8   libsystem_blocks.dylib              0x000000011205d99d _Block_release + 111
	9   UIKit                               0x000000010aba2e9a -[UIAlertController _clearActionHandlers] + 246
	10  UIKit                               0x000000010aba1282 -[UIAlertController dealloc] + 420
	11  libobjc.A.dylib                     0x00000001092eb178 _ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv + 860
	12  FrontBoardServices                  0x0000000115f074a0 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 32
	13  FrontBoardServices                  0x0000000115f0714e -[FBSSerialQueue _performNext] + 464
	14  FrontBoardServices                  0x0000000115f076bd -[FBSSerialQueue _performNextFromRunLoopSource] + 45
	15  CoreFoundation                      0x0000000109be4101 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
	16  CoreFoundation                      0x0000000109c83f71 __CFRunLoopDoSource0 + 81
	17  CoreFoundation                      0x0000000109bc8a19 __CFRunLoopDoSources0 + 185
	18  CoreFoundation                      0x0000000109bc7fff __CFRunLoopRun + 1279
	19  CoreFoundation                      0x0000000109bc7889 CFRunLoopRunSpecific + 409
	20  GraphicsServices                    0x000000010d7a09c6 GSEventRunModal + 62
	21  UIKit                               0x000000010a7d25d6 UIApplicationMain + 159
	22  webKitCompText                      0x0000000108217adf main + 111
	23  libdyld.dylib                       0x0000000111fecd81 start + 1
	24  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Comment 5 Radar WebKit Bug Importer 2018-04-02 09:24:58 PDT
<rdar://problem/39106756>
Comment 6 Andy Estes 2018-04-10 14:04:05 PDT
The title claims this happens "when the WKWebView is destroyed."

But it doesn't look like the web view is being destroyed on backgrounding, just the UIAlert. Is that right?
Comment 7 Aravind V 2018-04-10 21:36:11 PDT
Yes, if happens when the alert is destroyed.




(In reply to Andy Estes from comment #6)
> The title claims this happens "when the WKWebView is destroyed."
> 
> But it doesn't look like the web view is being destroyed on backgrounding,
> just the UIAlert. Is that right?
Comment 8 Andy Estes 2018-04-11 09:54:54 PDT
JavaScript alerts run synchronously from the perspective of web content, so the web process hangs waiting for you to call the alert completion handler. If you allow the completion handler to be deallocated without calling it once, your WKWebView would become unresponsive.

That's why we throw this exception. You really need to call the completion handler whenever you dismiss the alert, whether its dismissed programmatically or by the user.
Comment 9 AV 2018-04-11 10:53:52 PDT
Thank you so much, Andy.

I get the solution. I know there is a way to handle this as I mentioned in my 2nd comment, by manually keeping track of the instances of all alerts and their respective completion handlers and call each of these completion handlers one by one when the app needs to be de-allocated for a valid reason.

Let's assume the following scenario:

1) I have an application that has an in-built secure browser built on top of WebKit, which gets locked when the app enters into the background. When locking, if the webkit instance is maintained and the alerts aren't dismissed, the alerts will show-up on top of the app's lock screen(or on top of whichever view is currently being rendered), which is not a good user experience.

2) In the last few versions of iOS, UIAlertView is deprecated and Apple suggests developers to use UIAlertController. UIAlertController doesn't have a method similar to UIAlertView's "dismissWithClickedButtonIndex: animated:(BOOL)animated". Hence, the best way to work-around on this is to use UIAlertView and dismiss alerts whenever necessary by calling "dismissWithClickedButtonIndex: animated:(BOOL)animated", but this is ruled-out as UIAlertView is deprecated.

3) The only other possible way, as I've mentioned in my previous comments, is to maintain a list of all active Alerts by adding each alert instance and it's respective completion-handlers as and when the JS Alert delegate methods get called, and traversing through the list maintained and calling all active alerts' completion-handlers manually. This works, but seems to be a complex workaround.


Can you please advice as to whether the work-around mentioned in "3)" is the only way to deal with this? If so, it piles-up the code for just dismissing the active alerts by maintaining the state of each active alert. Though UIAlertView's "dismissWithClickedButtonIndex: animated:(BOOL)animated" would work well, it may not be advisable as Apple has already deprecated and may soon remove UIAlertView from it's SDK soon in the future.

Please if there is a possible fix or a better work-around for this, or if WebKit already has methods exposed to clear pending completion handlers before dismissing the alerts using "dismissViewController".


Thank you you much for your support.
Comment 10 Andy Estes 2018-04-11 11:19:19 PDT
I can't give you advice for how to manage the UIAlerts in your application. That's outside the scope of WebKit; we've delegated how to display the alert UI to you.

There can only be one active alert per WKWebView, though, so it doesn't seem overly complex to keep track of up to one completion handler per view. I can't really speak to your application, though.