<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[210055] branches/safari-603-branch</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/210055">210055</a></dd>
<dt>Author</dt> <dd>bshafiei@apple.com</dd>
<dt>Date</dt> <dd>2016-12-20 23:07:13 -0800 (Tue, 20 Dec 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Merged <a href="http://trac.webkit.org/projects/webkit/changeset/210031">r210031</a>. rdar://problem/29693817</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari603branchSourceWebKit2ChangeLog">branches/safari-603-branch/Source/WebKit2/ChangeLog</a></li>
<li><a href="#branchessafari603branchSourceWebKit2SharedCocoaCompletionHandlerCallCheckerh">branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h</a></li>
<li><a href="#branchessafari603branchSourceWebKit2SharedCocoaCompletionHandlerCallCheckermm">branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm</a></li>
<li><a href="#branchessafari603branchSourceWebKit2UIProcessAPICocoaWKWebViewmm">branches/safari-603-branch/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm</a></li>
<li><a href="#branchessafari603branchSourceWebKit2UIProcessCocoaNavigationStatemm">branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm</a></li>
<li><a href="#branchessafari603branchSourceWebKit2UIProcessCocoaUIDelegatemm">branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm</a></li>
<li><a href="#branchessafari603branchSourceWebKit2UIProcessCocoaVersionChecksh">branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h</a></li>
<li><a href="#branchessafari603branchToolsChangeLog">branches/safari-603-branch/Tools/ChangeLog</a></li>
<li><a href="#branchessafari603branchToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">branches/safari-603-branch/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#branchessafari603branchToolsTestWebKitAPITestsWebKit2CocoaDuplicateCompletionHandlerCallsmm">branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm</a></li>
<li><a href="#branchessafari603branchToolsTestWebKitAPITestsWebKit2Cocoaduplicatecompletionhandlercallshtml">branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari603branchSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/WebKit2/ChangeLog (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/WebKit2/ChangeLog        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Source/WebKit2/ChangeLog        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -1,3 +1,56 @@
</span><ins>+2016-12-20 Babak Shafiei <bshafiei@apple.com>
+
+ Merge r210031.
+
+ 2016-12-20 Andy Estes <aestes@apple.com>
+
+ [Cocoa] REGRESSION (r209558): Calling decisionHandler multiple times in webView:decidePolicyForNavigationAction:decisionHandler: leads to a crash
+ https://bugs.webkit.org/show_bug.cgi?id=165992
+ <rdar://problem/29693817>
+
+ Reviewed by Brady Eidson.
+
+ r209558 added additional move semantics to the decisionHandler block passed to
+ -webView:decidePolicyForNavigationAction:decisionHandler:, resulting in a null pointer
+ dereference in clients that call the decisionHandler block more than once.
+
+ None of the completion handlers we expose in the WebKit API are intended to be called more
+ than once, and we ASSERT in CompletionHandlerCallChecker::didCallCompletionHandler() that
+ this doesn't happen.
+
+ This change strenghtens that protection by returning immediately in completion handlers
+ called more than once. And in programs linked on or after WebKit 603.1.17, an NSException is
+ thrown if a completion handler is called a second time, like we do for completion handlers
+ that are never called.
+
+ New API test: WebKit2.DuplicateCompletionHandlerCalls
+
+ * Shared/Cocoa/CompletionHandlerCallChecker.h: Declared completionHandlerHasBeenCalled().
+ * Shared/Cocoa/CompletionHandlerCallChecker.mm:
+ (WebKit::shouldThrowExceptionForDuplicateCompletionHandlerCall): Added. Returns true if the
+ program is linked on or after
+ LibraryVersion::FirstWithExceptionsForDuplicateCompletionHandlerCalls.
+ (WebKit::CompletionHandlerCallChecker::completionHandlerHasBeenCalled): Added. Returns
+ whether or not the completion handler has been called. If it has, and
+ shouldThrowExceptionForDuplicateCompletionHandlerCall() returns true, throws an
+ NSInternalInconsistencyException.
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView _setInputDelegate:]): Added an early return if the completion handler has
+ already been called.
+ * UIProcess/Cocoa/NavigationState.mm:
+ (WebKit::NavigationState::NavigationClient::decidePolicyForNavigationAction): Ditto.
+ (WebKit::NavigationState::NavigationClient::decidePolicyForNavigationResponse): Ditto.
+ (WebKit::NavigationState::NavigationClient::didReceiveAuthenticationChallenge): Ditto.
+ * UIProcess/Cocoa/UIDelegate.mm:
+ (WebKit::UIDelegate::UIClient::runJavaScriptAlert): Ditto.
+ (WebKit::UIDelegate::UIClient::runJavaScriptConfirm): Ditto.
+ (WebKit::UIDelegate::UIClient::runJavaScriptPrompt): Ditto.
+ (WebKit::UIDelegate::UIClient::exceededDatabaseQuota): Ditto.
+ (WebKit::UIDelegate::UIClient::runOpenPanel): Ditto.
+ (WebKit::UIDelegate::UIClient::reachedApplicationCacheOriginQuota): Ditto.
+ * UIProcess/Cocoa/VersionChecks.h: Added
+ FirstWithExceptionsForDuplicateCompletionHandlerCalls with the version number for 603.1.17.
+
</ins><span class="cx"> 2016-12-19 Dean Jackson <dino@apple.com>
</span><span class="cx">
</span><span class="cx"> Another feature toggle for rdar://problem/29466493.
</span></span></pre></div>
<a id="branchessafari603branchSourceWebKit2SharedCocoaCompletionHandlerCallCheckerh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> ~CompletionHandlerCallChecker();
</span><span class="cx">
</span><span class="cx"> void didCallCompletionHandler();
</span><ins>+ bool completionHandlerHasBeenCalled() const;
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> CompletionHandlerCallChecker(Class delegateClass, SEL delegateMethodSelector);
</span></span></pre></div>
<a id="branchessafari603branchSourceWebKit2SharedCocoaCompletionHandlerCallCheckermm"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -28,8 +28,10 @@
</span><span class="cx">
</span><span class="cx"> #if WK_API_ENABLED
</span><span class="cx">
</span><ins>+#import <mutex>
</ins><span class="cx"> #import <objc/runtime.h>
</span><span class="cx"> #import <wtf/Ref.h>
</span><ins>+#import "VersionChecks.h"
</ins><span class="cx">
</span><span class="cx"> namespace WebKit {
</span><span class="cx">
</span><span class="lines">@@ -60,6 +62,29 @@
</span><span class="cx"> m_didCallCompletionHandler = true;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static bool shouldThrowExceptionForDuplicateCompletionHandlerCall()
+{
+ static bool shouldThrowException;
+ static std::once_flag once;
+ std::call_once(once, [] {
+ shouldThrowException = linkedOnOrAfter(LibraryVersion::FirstWithExceptionsForDuplicateCompletionHandlerCalls);
+ });
+ return shouldThrowException;
+}
+
+bool CompletionHandlerCallChecker::completionHandlerHasBeenCalled() const
+{
+ if (!m_didCallCompletionHandler)
+ return false;
+
+ if (shouldThrowExceptionForDuplicateCompletionHandlerCall()) {
+ Class delegateClass = classImplementingDelegateMethod();
+ [NSException raise:NSInternalInconsistencyException format:@"Completion handler passed to %c[%@ %@] was called more than once", class_isMetaClass(delegateClass) ? '+' : '-', NSStringFromClass(delegateClass), NSStringFromSelector(m_delegateMethodSelector)];
+ }
+
+ return true;
+}
+
</ins><span class="cx"> Class CompletionHandlerCallChecker::classImplementingDelegateMethod() const
</span><span class="cx"> {
</span><span class="cx"> Class delegateClass = m_delegateClass;
</span></span></pre></div>
<a id="branchessafari603branchSourceWebKit2UIProcessAPICocoaWKWebViewmm"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -3886,6 +3886,8 @@
</span><span class="cx"> RefPtr<WebKit::WebFormSubmissionListenerProxy> localListener = WTFMove(listener);
</span><span class="cx"> RefPtr<WebKit::CompletionHandlerCallChecker> checker = WebKit::CompletionHandlerCallChecker::create(inputDelegate.get(), @selector(_webView:willSubmitFormValues:userObject:submissionHandler:));
</span><span class="cx"> [inputDelegate _webView:m_webView willSubmitFormValues:valueMap.get() userObject:userObject submissionHandler:[localListener, checker] {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> localListener->continueSubmission();
</span><span class="cx"> }];
</span></span></pre></div>
<a id="branchessafari603branchSourceWebKit2UIProcessCocoaNavigationStatemm"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -337,6 +337,8 @@
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), delegateHasWebsitePolicies ? @selector(_webView:decidePolicyForNavigationAction:decisionHandler:) : @selector(webView:decidePolicyForNavigationAction:decisionHandler:));
</span><span class="cx">
</span><span class="cx"> auto decisionHandlerWithPolicies = [localListener = RefPtr<WebFramePolicyListenerProxy>(WTFMove(listener)), localNavigationAction = RefPtr<API::NavigationAction>(&navigationAction), checker = WTFMove(checker), mainFrameURLString](WKNavigationActionPolicy actionPolicy, _WKWebsitePolicies *websitePolicies) mutable {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> WebsitePolicies policies;
</span><span class="lines">@@ -412,6 +414,8 @@
</span><span class="cx"> RefPtr<WebFramePolicyListenerProxy> localListener = WTFMove(listener);
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:decidePolicyForNavigationResponse:decisionHandler:));
</span><span class="cx"> [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationResponse:wrapper(navigationResponse) decisionHandler:[localListener, checker](WKNavigationResponsePolicy responsePolicy) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> switch (responsePolicy) {
</span><span class="lines">@@ -647,6 +651,8 @@
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:didReceiveAuthenticationChallenge:completionHandler:));
</span><span class="cx"> [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) webView:m_navigationState.m_webView didReceiveAuthenticationChallenge:wrapper(*authenticationChallenge)
</span><span class="cx"> completionHandler:[challenge, checker](NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> switch (disposition) {
</span></span></pre></div>
<a id="branchessafari603branchSourceWebKit2UIProcessCocoaUIDelegatemm"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -216,6 +216,8 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:));
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runJavaScriptAlertPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void ()>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)] {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> completionHandler();
</span><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -236,6 +238,8 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](BOOL result) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> completionHandler(result);
</span><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -256,6 +260,8 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:));
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runJavaScriptTextInputPanelWithPrompt:message defaultText:defaultValue initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (NSString *)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](NSString *result) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> completionHandler(result);
</span><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -281,6 +287,8 @@
</span><span class="cx"> ASSERT(securityOrigin);
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:));
</span><span class="cx"> [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideDatabaseQuotaForSecurityOrigin:wrapper(*securityOrigin) currentQuota:currentQuota currentOriginUsage:currentOriginUsage currentDatabaseUsage:currentUsage expectedUsage:expectedUsage decisionHandler:BlockPtr<void (unsigned long long newQuota)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long newQuota) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> completionHandler(newQuota);
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -302,6 +310,8 @@
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:));
</span><span class="cx">
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runOpenPanelWithParameters:wrapper(*openPanelParameters) initiatedByFrame:wrapper(frame) completionHandler:[checker, resultListener](NSArray *URLs) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> if (!URLs) {
</span><span class="lines">@@ -460,6 +470,8 @@
</span><span class="cx"> RefPtr<API::SecurityOrigin> apiOrigin = API::SecurityOrigin::create(securityOrigin);
</span><span class="cx">
</span><span class="cx"> [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideWebApplicationCacheQuotaForSecurityOrigin:wrapper(*apiOrigin) currentQuota:currentQuota totalBytesNeeded:totalBytesNeeded decisionHandler:BlockPtr<void (unsigned long long)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long newQuota) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> completionHandler(newQuota);
</span><span class="cx"> }).get()];
</span></span></pre></div>
<a id="branchessafari603branchSourceWebKit2UIProcessCocoaVersionChecksh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -23,8 +23,7 @@
</span><span class="cx"> * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx"> */
</span><span class="cx">
</span><del>-#ifndef VersionChecks_h
-#define VersionChecks_h
</del><ins>+#pragma once
</ins><span class="cx">
</span><span class="cx"> namespace WebKit {
</span><span class="cx">
</span><span class="lines">@@ -40,10 +39,9 @@
</span><span class="cx"> enum class LibraryVersion {
</span><span class="cx"> FirstWithNetworkCache = 0x02590116, // 601.1.22
</span><span class="cx"> FirstWithMediaTypesRequiringUserActionForPlayback = 0x025A0121, // 602.1.33
</span><ins>+ FirstWithExceptionsForDuplicateCompletionHandlerCalls = 0x025B0111, // 603.1.17
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> bool linkedOnOrAfter(LibraryVersion);
</span><span class="cx">
</span><span class="cx"> }
</span><del>-
-#endif
</del></span></pre></div>
<a id="branchessafari603branchToolsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Tools/ChangeLog (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Tools/ChangeLog        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Tools/ChangeLog        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2016-12-20 Babak Shafiei <bshafiei@apple.com>
+
+ Merge r210031.
+
+ 2016-12-20 Andy Estes <aestes@apple.com>
+
+ [Cocoa] REGRESSION (r209558): Calling decisionHandler multiple times in webView:decidePolicyForNavigationAction:decisionHandler: leads to a crash
+ https://bugs.webkit.org/show_bug.cgi?id=165992
+
+ Reviewed by Brady Eidson.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm: Added.
+ (expectException):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:decidePolicyForNavigationAction:decisionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate _webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate _webView:willSubmitFormValues:userObject:submissionHandler:]):
+ (TEST):
+ * TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html: Added.
+
</ins><span class="cx"> 2016-12-19 Dean Jackson <dino@apple.com>
</span><span class="cx">
</span><span class="cx"> Merge another patch for rdar://problem/29466493.
</span></span></pre></div>
<a id="branchessafari603branchToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (210054 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-12-21 04:44:01 UTC (rev 210054)
+++ branches/safari-603-branch/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -462,6 +462,8 @@
</span><span class="cx">                 A14FC5881B8991BF00D107EB /* ContentFiltering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5861B8991B600D107EB /* ContentFiltering.mm */; };
</span><span class="cx">                 A14FC58B1B89927100D107EB /* ContentFilteringPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */; };
</span><span class="cx">                 A14FC5901B8AE36F00D107EB /* TestProtocol.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC58E1B8AE36500D107EB /* TestProtocol.mm */; };
</span><ins>+                A155022A1E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm in Sources */ = {isa = PBXBuildFile; fileRef = A15502281E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm */; };
+                A155022C1E050D0300A24C57 /* duplicate-completion-handler-calls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */; };
</ins><span class="cx">                 A16F66BA1C40EB4F00BD4D24 /* ContentFiltering.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */; };
</span><span class="cx">                 A1C4FB731BACD1CA003742D0 /* pages.pages in Copy Resources */ = {isa = PBXBuildFile; fileRef = A1C4FB721BACD1B7003742D0 /* pages.pages */; };
</span><span class="cx">                 A1DF74321C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1DF74301C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm */; };
</span><span class="lines">@@ -595,6 +597,7 @@
</span><span class="cx">                         dstSubfolderSpec = 7;
</span><span class="cx">                         files = (
</span><span class="cx">                                 9BD4239C1E04C01C00200395 /* chinese-character-with-image.html in Copy Resources */,
</span><ins>+                                A155022C1E050D0300A24C57 /* duplicate-completion-handler-calls.html in Copy Resources */,
</ins><span class="cx">                                 5110FCF91E01CD8A006F8D0B /* IndexUpgrade.blob in Copy Resources */,
</span><span class="cx">                                 5110FCF61E01CD83006F8D0B /* IndexUpgrade.sqlite3 in Copy Resources */,
</span><span class="cx">                                 5110FCF11E01CD64006F8D0B /* IDBIndexUpgradeToV2.html in Copy Resources */,
</span><span class="lines">@@ -1136,6 +1139,8 @@
</span><span class="cx">                 A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentFilteringPlugIn.mm; sourceTree = "<group>"; };
</span><span class="cx">                 A14FC58D1B8AE36500D107EB /* TestProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProtocol.h; path = cocoa/TestProtocol.h; sourceTree = "<group>"; };
</span><span class="cx">                 A14FC58E1B8AE36500D107EB /* TestProtocol.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestProtocol.mm; path = cocoa/TestProtocol.mm; sourceTree = "<group>"; };
</span><ins>+                A15502281E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DuplicateCompletionHandlerCalls.mm; sourceTree = "<group>"; };
+                A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "duplicate-completion-handler-calls.html"; sourceTree = "<group>"; };
</ins><span class="cx">                 A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ContentFiltering.html; sourceTree = "<group>"; };
</span><span class="cx">                 A18AA8CC1C3FA218009B2B97 /* ContentFiltering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentFiltering.h; sourceTree = "<group>"; };
</span><span class="cx">                 A1A4FE5D18DD3DB700B5EA8A /* Download.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Download.mm; sourceTree = "<group>"; };
</span><span class="lines">@@ -1461,6 +1466,7 @@
</span><span class="cx">                                 5C2936911D5BF63E00DEAB1E /* CookieAcceptPolicy.mm */,
</span><span class="cx">                                 2DC4CF761D2D9DD800ECCC94 /* DataDetection.mm */,
</span><span class="cx">                                 A1A4FE5D18DD3DB700B5EA8A /* Download.mm */,
</span><ins>+                                A15502281E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm */,
</ins><span class="cx">                                 2D8104CB1BEC13E70020DA46 /* FindInPage.mm */,
</span><span class="cx">                                 2D1FE0AF1AD465C1006CD9E6 /* FixedLayoutSize.mm */,
</span><span class="cx">                                 CD78E11A1DB7EA360014A2DE /* FullscreenDelegate.mm */,
</span><span class="lines">@@ -1625,6 +1631,7 @@
</span><span class="cx">                                 5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */,
</span><span class="cx">                                 5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */,
</span><span class="cx">                                 5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */,
</span><ins>+                                A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */,
</ins><span class="cx">                                 9984FACD1CFFB038008D198C /* editable-body.html */,
</span><span class="cx">                                 93575C551D30366E000D604D /* focus-inputs.html */,
</span><span class="cx">                                 F4F405BA1D4C0CF8007A9707 /* full-size-autoplaying-video-with-audio.html */,
</span><span class="lines">@@ -2479,6 +2486,7 @@
</span><span class="cx">                                 7CCE7EEA1A411AE600447C4C /* DidNotHandleKeyDown.cpp in Sources */,
</span><span class="cx">                                 7CCE7EEB1A411AE600447C4C /* DocumentStartUserScriptAlertCrash.cpp in Sources */,
</span><span class="cx">                                 37A22AA71DCAA27200AFBFC4 /* ObservedRenderingProgressEventsAfterCrash.mm in Sources */,
</span><ins>+                                A155022A1E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm in Sources */,
</ins><span class="cx">                                 7CCE7EBB1A411A7E00447C4C /* DOMHTMLTableCellCellAbove.mm in Sources */,
</span><span class="cx">                                 5C9E56851DF9145400C9EE33 /* WebsitePolicies.mm in Sources */,
</span><span class="cx">                                 2D51A0C71C8BF00C00765C45 /* DOMHTMLVideoElementWrapper.mm in Sources */,
</span></span></pre></div>
<a id="branchessafari603branchToolsTestWebKitAPITestsWebKit2CocoaDuplicateCompletionHandlerCallsmmfromrev210031trunkToolsTestWebKitAPITestsWebKit2CocoaDuplicateCompletionHandlerCallsmm"></a>
<div class="copfile"><h4>Copied: branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm (from rev 210031, trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm) (0 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm         (rev 0)
+++ branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import <WebKit/WebKit.h>
+
+#if WK_API_ENABLED
+
+#import "PlatformUtilities.h"
+#import "Utilities.h"
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKInputDelegate.h>
+#import <wtf/RetainPtr.h>
+
+using namespace TestWebKitAPI;
+
+static bool testFinished;
+
+@interface DuplicateCompletionHandlerCallsDelegate : NSObject <WKNavigationDelegate, WKUIDelegate, _WKInputDelegate>
+@end
+
+@implementation DuplicateCompletionHandlerCallsDelegate
+
+static void expectException(void (^completionHandler)())
+{
+ bool exceptionThrown = false;
+ @try {
+ completionHandler();
+ } @catch (NSException *exception) {
+ EXPECT_WK_STREQ(NSInternalInconsistencyException, exception.name);
+ exceptionThrown = true;
+ }
+ EXPECT_TRUE(exceptionThrown);
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
+{
+ decisionHandler(WKNavigationActionPolicyAllow);
+
+ expectException(^ {
+ decisionHandler(WKNavigationActionPolicyAllow);
+ });
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
+{
+ decisionHandler(WKNavigationResponsePolicyAllow);
+
+ expectException(^ {
+ decisionHandler(WKNavigationResponsePolicyAllow);
+ });
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
+{
+ completionHandler();
+
+ expectException(^ {
+ completionHandler();
+ });
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
+{
+ completionHandler(YES);
+
+ expectException(^ {
+ completionHandler(YES);
+ });
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler
+{
+ completionHandler(nil);
+
+ expectException(^ {
+ completionHandler(nil);
+ });
+}
+
+- (void)_webView:(WKWebView *)webView decideDatabaseQuotaForSecurityOrigin:(WKSecurityOrigin *)securityOrigin currentQuota:(unsigned long long)currentQuota currentOriginUsage:(unsigned long long)currentOriginUsage currentDatabaseUsage:(unsigned long long)currentUsage expectedUsage:(unsigned long long)expectedUsage decisionHandler:(void (^)(unsigned long long newQuota))decisionHandler
+{
+ decisionHandler(expectedUsage);
+
+ expectException(^ {
+ decisionHandler(expectedUsage);
+ });
+}
+
+- (void)_webView:(WKWebView *)webView willSubmitFormValues:(NSDictionary *)values userObject:(NSObject<NSSecureCoding> *)userObject submissionHandler:(void (^)())submissionHandler
+{
+ submissionHandler();
+
+ expectException(^ {
+ submissionHandler();
+ });
+
+ testFinished = true;
+}
+
+@end
+
+TEST(WebKit2, DuplicateCompletionHandlerCalls)
+{
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]);
+ auto delegate = adoptNS([[DuplicateCompletionHandlerCallsDelegate alloc] init]);
+ [webView setNavigationDelegate:delegate.get()];
+ [webView setUIDelegate:delegate.get()];
+ [webView _setInputDelegate:delegate.get()];
+ [webView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"duplicate-completion-handler-calls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]];
+
+ Util::run(&testFinished);
+}
+
+#endif // WK_API_ENABLED
</ins></span></pre></div>
<a id="branchessafari603branchToolsTestWebKitAPITestsWebKit2Cocoaduplicatecompletionhandlercallshtmlfromrev210031trunkToolsTestWebKitAPITestsWebKit2Cocoaduplicatecompletionhandlercallshtml"></a>
<div class="copfile"><h4>Copied: branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html (from rev 210031, trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html) (0 => 210055)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html         (rev 0)
+++ branches/safari-603-branch/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html        2016-12-21 07:07:13 UTC (rev 210055)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+<!DOCTYPE html>
+<form action="about:blank"></form>
+<script>
+ alert("alert");
+ confirm("confirm");
+ prompt("prompt");
+ openDatabase("testDatabase", "1", "test database", 1024);
+ document.forms[0].submit();
+</script>
</ins></span></pre>
</div>
</div>
</body>
</html>