Title: [288039] trunk
Revision
288039
Author
wenson_hs...@apple.com
Date
2022-01-14 16:56:22 -0800 (Fri, 14 Jan 2022)

Log Message

[iOS] Occasional crash under -[UITargetedPreview initWithView:parameters:target:] when focusing form controls
https://bugs.webkit.org/show_bug.cgi?id=235248
rdar://79220540

Reviewed by Tim Horton and Aditya Keerthi.

Source/WebKit:

It's possible for `-resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:` to return a `nil` snapshot
view in the case where a screen update has not been performed yet (among other scenarios). In the case where
UIKit returns `nil` when we're creating the targeted preview for the context menu when focusing a select element
or file input, we'll crash due to an Objective-C exception in the initializer of UITargetedPreview. Mitigate
this by falling back to an empty UIView after requesting the snapshot view to make our code robust against this
scenario.

Test: KeyboardInputTests.DoNotCrashWhenFocusingSelectWithoutViewSnapshot

* UIProcess/ios/WKContentViewInteraction.mm:
(createFallbackTargetedPreview):

Tools:

Add an API test that exercises the crash by forcing `-resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:`
to return nil via swizzling.

* TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
(TestWebKitAPI::nilResizableSnapshotViewFromRect):
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (288038 => 288039)


--- trunk/Source/WebKit/ChangeLog	2022-01-15 00:48:46 UTC (rev 288038)
+++ trunk/Source/WebKit/ChangeLog	2022-01-15 00:56:22 UTC (rev 288039)
@@ -1,3 +1,23 @@
+2022-01-14  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] Occasional crash under -[UITargetedPreview initWithView:parameters:target:] when focusing form controls
+        https://bugs.webkit.org/show_bug.cgi?id=235248
+        rdar://79220540
+
+        Reviewed by Tim Horton and Aditya Keerthi.
+
+        It's possible for `-resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:` to return a `nil` snapshot
+        view in the case where a screen update has not been performed yet (among other scenarios). In the case where
+        UIKit returns `nil` when we're creating the targeted preview for the context menu when focusing a select element
+        or file input, we'll crash due to an Objective-C exception in the initializer of UITargetedPreview. Mitigate
+        this by falling back to an empty UIView after requesting the snapshot view to make our code robust against this
+        scenario.
+
+        Test: KeyboardInputTests.DoNotCrashWhenFocusingSelectWithoutViewSnapshot
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (createFallbackTargetedPreview):
+
 2022-01-14  Dean Jackson  <d...@apple.com>
 
         REGRESSION:  ARKit example loads a page full of random symbols instead of a 3D model

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (288038 => 288039)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2022-01-15 00:48:46 UTC (rev 288038)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2022-01-15 00:56:22 UTC (rev 288039)
@@ -8646,7 +8646,9 @@
     if (backgroundColor)
         [parameters setBackgroundColor:backgroundColor];
 
-    UIView *snapshotView = [rootView resizableSnapshotViewFromRect:frameInRootViewCoordinates afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
+    RetainPtr snapshotView = [rootView resizableSnapshotViewFromRect:frameInRootViewCoordinates afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
+    if (!snapshotView)
+        snapshotView = adoptNS([UIView new]);
 
     CGRect frameInContainerViewCoordinates = [rootView convertRect:frameInRootViewCoordinates toView:containerView];
 
@@ -8653,12 +8655,12 @@
     if (CGRectIsEmpty(frameInContainerViewCoordinates))
         return nil;
 
-    snapshotView.frame = frameInContainerViewCoordinates;
+    [snapshotView setFrame:frameInContainerViewCoordinates];
 
     CGPoint centerInContainerViewCoordinates = CGPointMake(CGRectGetMidX(frameInContainerViewCoordinates), CGRectGetMidY(frameInContainerViewCoordinates));
     auto target = adoptNS([[UIPreviewTarget alloc] initWithContainer:containerView center:centerInContainerViewCoordinates]);
 
-    return adoptNS([[UITargetedPreview alloc] initWithView:snapshotView parameters:parameters.get() target:target.get()]);
+    return adoptNS([[UITargetedPreview alloc] initWithView:snapshotView.get() parameters:parameters.get() target:target.get()]);
 }
 
 - (UITargetedPreview *)_createTargetedContextMenuHintPreviewForFocusedElement

Modified: trunk/Tools/ChangeLog (288038 => 288039)


--- trunk/Tools/ChangeLog	2022-01-15 00:48:46 UTC (rev 288038)
+++ trunk/Tools/ChangeLog	2022-01-15 00:56:22 UTC (rev 288039)
@@ -1,3 +1,18 @@
+2022-01-14  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] Occasional crash under -[UITargetedPreview initWithView:parameters:target:] when focusing form controls
+        https://bugs.webkit.org/show_bug.cgi?id=235248
+        rdar://79220540
+
+        Reviewed by Tim Horton and Aditya Keerthi.
+
+        Add an API test that exercises the crash by forcing `-resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:`
+        to return nil via swizzling.
+
+        * TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
+        (TestWebKitAPI::nilResizableSnapshotViewFromRect):
+        (TestWebKitAPI::TEST):
+
 2022-01-07  Jonathan Bedard  <jbed...@apple.com>
 
         [webkitbugspy] Support radar as issue tracker type

Modified: trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm (288038 => 288039)


--- trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm	2022-01-15 00:48:46 UTC (rev 288038)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm	2022-01-15 00:56:22 UTC (rev 288039)
@@ -826,6 +826,27 @@
     EXPECT_EQ(contentView.undoManager, undoManager);
 }
 
+static UIView * nilResizableSnapshotViewFromRect(id, SEL, CGRect, BOOL, UIEdgeInsets)
+{
+    return nil;
+}
+
+TEST(KeyboardInputTests, DoNotCrashWhenFocusingSelectWithoutViewSnapshot)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    auto delegate = adoptNS([TestInputDelegate new]);
+    [webView _setInputDelegate:delegate.get()];
+    [delegate setFocusStartsInputSessionPolicyHandler:[](WKWebView *, id <_WKFocusedElementInfo>) {
+        return _WKFocusStartsInputSessionPolicyAllow;
+    }];
+
+    [webView synchronouslyLoadHTMLString:@"<select id='select'><option>foo</option><option>bar</option></select>"];
+
+    InstanceMethodSwizzler swizzler { UIView.class, @selector(resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:), reinterpret_cast<IMP>(nilResizableSnapshotViewFromRect) };
+    [webView stringByEvaluatingJavaScript:@"select.focus()"];
+    [webView waitForNextPresentationUpdate];
+}
+
 } // namespace TestWebKitAPI
 
 #endif // PLATFORM(IOS_FAMILY)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to