Title: [285086] trunk
Revision
285086
Author
cdu...@apple.com
Date
2021-10-30 18:24:38 -0700 (Sat, 30 Oct 2021)

Log Message

Improve error handling in sendWithAsyncReply()
https://bugs.webkit.org/show_bug.cgi?id=232508

Reviewed by Darin Adler.

Source/WebKit:

* Platform/IPC/Connection.cpp:
(IPC::Connection::invalidate):
We stop delivering messages as soon as |m_valid| becomes false. It is
thus a good idea to cancel any pending async reply handlers as soon
as we set m_isValid to false. We were doing it correctly in connectionDidClose()
but not in invalidate(). The Connection destructor would eventually call
the async reply handlers. However, I have noticed when investigating a leak
that this may delay the calling of the reply handler for a long time if
something keeps the Connection alive (or forever in case of a leak).

* Platform/IPC/Connection.h:
(IPC::Connection::sendWithAsyncReply):
Return early if the connection is no longer valid and call the
completion handler right away (but asynchronously). Previously,
we'd register the async reply handler and then the call to
sendMessage() would fail.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _getContentsAsStringWithCompletionHandlerKeepIPCConnectionAliveForTesting:]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
Add helper SPI for API test.

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/WKWebViewGetContents.mm:
(TEST):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (285085 => 285086)


--- trunk/Source/WebKit/ChangeLog	2021-10-31 01:18:06 UTC (rev 285085)
+++ trunk/Source/WebKit/ChangeLog	2021-10-31 01:24:38 UTC (rev 285086)
@@ -1,3 +1,32 @@
+2021-10-30  Chris Dumez  <cdu...@apple.com>
+
+        Improve error handling in sendWithAsyncReply()
+        https://bugs.webkit.org/show_bug.cgi?id=232508
+
+        Reviewed by Darin Adler.
+
+        * Platform/IPC/Connection.cpp:
+        (IPC::Connection::invalidate):
+        We stop delivering messages as soon as |m_valid| becomes false. It is
+        thus a good idea to cancel any pending async reply handlers as soon
+        as we set m_isValid to false. We were doing it correctly in connectionDidClose()
+        but not in invalidate(). The Connection destructor would eventually call
+        the async reply handlers. However, I have noticed when investigating a leak
+        that this may delay the calling of the reply handler for a long time if
+        something keeps the Connection alive (or forever in case of a leak).
+
+        * Platform/IPC/Connection.h:
+        (IPC::Connection::sendWithAsyncReply):
+        Return early if the connection is no longer valid and call the
+        completion handler right away (but asynchronously). Previously,
+        we'd register the async reply handler and then the call to
+        sendMessage() would fail.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _getContentsAsStringWithCompletionHandlerKeepIPCConnectionAliveForTesting:]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        Add helper SPI for API test.
+
 2021-10-30  Kate Cheney  <katherine_che...@apple.com>
 
         [iOS 15] Loads after WKWebView session restore are marked as app-initiated 

Modified: trunk/Source/WebKit/Platform/IPC/Connection.cpp (285085 => 285086)


--- trunk/Source/WebKit/Platform/IPC/Connection.cpp	2021-10-31 01:18:06 UTC (rev 285085)
+++ trunk/Source/WebKit/Platform/IPC/Connection.cpp	2021-10-31 01:24:38 UTC (rev 285086)
@@ -428,6 +428,7 @@
     }
     
     m_isValid = false;
+    clearAsyncReplyHandlers(*this);
 
     m_connectionQueue->dispatch([protectedThis = Ref { *this }]() mutable {
         protectedThis->platformInvalidate();

Modified: trunk/Source/WebKit/Platform/IPC/Connection.h (285085 => 285086)


--- trunk/Source/WebKit/Platform/IPC/Connection.h	2021-10-31 01:18:06 UTC (rev 285085)
+++ trunk/Source/WebKit/Platform/IPC/Connection.h	2021-10-31 01:24:38 UTC (rev 285086)
@@ -546,6 +546,13 @@
 {
     COMPILE_ASSERT(!T::isSync, AsyncMessageExpected);
 
+    if (!isValid()) {
+        RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() mutable {
+            T::cancelReply(WTFMove(completionHandler));
+        });
+        return 0;
+    }
+
     auto encoder = makeUniqueRef<Encoder>(T::name(), destinationID);
     uint64_t listenerID = nextAsyncReplyHandlerID();
     addAsyncReplyHandler(*this, listenerID, CompletionHandler<void(Decoder*)>([completionHandler = WTFMove(completionHandler)] (Decoder* decoder) mutable {

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (285085 => 285086)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2021-10-31 01:18:06 UTC (rev 285085)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2021-10-31 01:24:38 UTC (rev 285086)
@@ -2962,6 +2962,14 @@
     });
 }
 
+- (void)_getContentsAsStringWithCompletionHandlerKeepIPCConnectionAliveForTesting:(void (^)(NSString *, NSError *))completionHandler
+{
+    THROW_IF_SUSPENDED;
+    _page->getContentsAsString(WebKit::ContentAsStringIncludesChildFrames::No, [handler = makeBlockPtr(completionHandler), connection = RefPtr { _page->process().connection() }](String string) {
+        handler(string, nil);
+    });
+}
+
 - (void)_getContentsOfAllFramesAsStringWithCompletionHandler:(void (^)(NSString *))completionHandler
 {
     THROW_IF_SUSPENDED;

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (285085 => 285086)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2021-10-31 01:18:06 UTC (rev 285085)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2021-10-31 01:24:38 UTC (rev 285086)
@@ -291,6 +291,7 @@
 - (void)_getMainResourceDataWithCompletionHandler:(void (^)(NSData *, NSError *))completionHandler;
 - (void)_getWebArchiveDataWithCompletionHandler:(void (^)(NSData *, NSError *))completionHandler;
 - (void)_getContentsAsStringWithCompletionHandler:(void (^)(NSString *, NSError *))completionHandler WK_API_AVAILABLE(macos(10.13), ios(11.0));
+- (void)_getContentsAsStringWithCompletionHandlerKeepIPCConnectionAliveForTesting:(void (^)(NSString *, NSError *))completionHandler;
 - (void)_getContentsOfAllFramesAsStringWithCompletionHandler:(void (^)(NSString *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
 - (void)_getContentsAsAttributedStringWithCompletionHandler:(void (^)(NSAttributedString *, NSDictionary<NSAttributedStringDocumentAttributeKey, id> *, NSError *))completionHandler WK_API_AVAILABLE(macos(10.15), ios(13.0));
 

Modified: trunk/Tools/ChangeLog (285085 => 285086)


--- trunk/Tools/ChangeLog	2021-10-31 01:18:06 UTC (rev 285085)
+++ trunk/Tools/ChangeLog	2021-10-31 01:24:38 UTC (rev 285086)
@@ -1,3 +1,15 @@
+2021-10-30  Chris Dumez  <cdu...@apple.com>
+
+        Improve error handling in sendWithAsyncReply()
+        https://bugs.webkit.org/show_bug.cgi?id=232508
+
+        Reviewed by Darin Adler.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WKWebViewGetContents.mm:
+        (TEST):
+
 2021-10-30  Sam Sneddon  <gsnedd...@apple.com>
 
         Ensure we stop LayoutTest servers without them becoming zombies

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewGetContents.mm (285085 => 285086)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewGetContents.mm	2021-10-31 01:18:06 UTC (rev 285085)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewGetContents.mm	2021-10-31 01:24:38 UTC (rev 285086)
@@ -49,6 +49,23 @@
     TestWebKitAPI::Util::run(&finished);
 }
 
+TEST(WKWebView, GetContentsShouldFailWhenClosingPage)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+
+    [webView synchronouslyLoadTestPageNamed:@"simple"];
+
+    __block bool finished = false;
+
+    [webView _getContentsAsStringWithCompletionHandlerKeepIPCConnectionAliveForTesting:^(NSString *string, NSError *error) {
+        finished = true;
+    }];
+
+    [webView _close];
+
+    TestWebKitAPI::Util::run(&finished);
+}
+
 TEST(WKWebView, GetContentsOfAllFramesShouldReturnString)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to