[Webkit-unassigned] [Bug 243264] New: Retain cycle after snapshotting a WKWebView displaying a PDF file
bugzilla-daemon at webkit.org
bugzilla-daemon at webkit.org
Wed Jul 27 13:44:36 PDT 2022
https://bugs.webkit.org/show_bug.cgi?id=243264
Bug ID: 243264
Summary: Retain cycle after snapshotting a WKWebView displaying
a PDF file
Product: WebKit
Version: WebKit Nightly Build
Hardware: Unspecified
OS: Unspecified
Status: NEW
Severity: Normal
Priority: P2
Component: PDF
Assignee: webkit-unassigned at lists.webkit.org
Reporter: ajuma at chromium.org
CC: bdakin at apple.com, justincohen at google.com,
thorton at apple.com, wenson_hsieh at apple.com
Created attachment 461260
--> https://bugs.webkit.org/attachment.cgi?id=461260&action=review
ViewController reproducing the leak
When a third-party embedder (that is, any embedder without the com.apple.QuartzCore.global-capture entitlement) calls -[WKWebView takeSnapshotWithConfiguration:completionHandler:], this creates a retain cycle that isn't broken until the WKWebView is navigated away. If, instead, the WKWebView is released by the embedder in this state, the cycle remains forever, and the WKWebView is leaked.
This seems to be a combination of two bugs:
1) In -[WKWebView takeSnapshotWithConfiguration:completionHandler:], the completion handler constructed on this line: https://github.com/WebKit/WebKit/blob/a790b3beee524f688f96f721372dee80a6235e7f/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm#L1247 captures strongSelf without seeming to need it (it's not used in the body of that completion handler).
2) For third-party embedders (for whom +[WKPDFView web_requiresCustomSnapshotting] is YES), the callback from (1) ends up getting passed to PDFHostViewController in -[WKPDFView web_snapshotRectInContentViewCoordinates], and for reasons that aren't clear (hard to tell without source for PDFKit), the callback isn't released even after it is called.
The result is we have a cycle:
1) WKWebView retains WKPDFView (through _customContentView)
2) WKPDFView retains PDFHostViewController (through _hostViewController)
3) PDFHostViewController retains the callback
4) The callback retains WKWebView (because of the strongSelf mentioned earlier)
I've confirmed using Xcode's memory graph that the WKWebView remains alive even if the embedder releases it and removes it from the view hierarchy.
In addition to leaking memory, this is also web-observable if another page has an opener to the leaked WKWebView, since window.closed remains false even though the tab has actually been closed. This reproduces in multiple 3rd-party browsers on iOS (Chrome, Firefox, Brave, Edge).
The simplest fix would be to change https://github.com/WebKit/WebKit/blob/a790b3beee524f688f96f721372dee80a6235e7f/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm#L1247 so that strongSelf isn't captured in the completionHandler constructed at the end of that line.
An alternative would be to figure out why PDFHostViewController isn't releasing the callback, but that's outside the scope of WebKit.
I've attached a simple example of constructing a WKWebView and taking a snapshot, which includes a comment at the point where we can look a the memory graph to see the leak.
--
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20220727/e7fcc6e2/attachment-0001.htm>
More information about the webkit-unassigned
mailing list