[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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@288039 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 83054a2..d49de30 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,23 @@
+2022-01-14 Wenson Hsieh <wenson_hsieh@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 <dino@apple.com>
REGRESSION: ARKit example loads a page full of random symbols instead of a 3D model
diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
index 798755e..e7211bd 100644
--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
@@ -8646,19 +8646,21 @@
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];
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
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index d61c34e..68ddf13 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,18 @@
+2022-01-14 Wenson Hsieh <wenson_hsieh@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 <jbedard@apple.com>
[webkitbugspy] Support radar as issue tracker type
diff --git a/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm b/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm
index 1f5366d..84854dd 100644
--- a/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm
+++ b/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm
@@ -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)