The problem

After iOS 14 Beta 2 was released on July 8, we noticed a crash spike.

The stack at the top of the crash is:

0        _objc_retain (in libobjc.A.dylib)
1        -[UIInputResponderController prepareToMoveKeyboardForInputViewSet:animationStyle:] (in UIKitCore)
2        -[UIInputResponderController setKeyWindowSceneInputViews:animationStyle:] (in UIKitCore)
3        -[UIInputResponderController setInputViews:animationStyle:] (in UIKitCore)
4        -[UIInputResponderController setInputViews:animated:] (in UIKitCore)
5        -[UIInputResponderController setInputViews:] (in UIKitCore)
......
Copy the code

In addition, we noticed that the trigger of this problem was not closely related to the business form, and multiple apps had encountered this crash, and the magnitude was not low.

Repair plan

Here’s our final fix:

Hook private methods -[UIInputViewSet restorableResponder], return nil directly.

Since it is a problem with the system library itself, we do not have the source code, and it is difficult to guarantee that this fix does not introduce new pits. But from what we’ve seen so far, at least the crash is no longer recurring, and the keyboard scene that seems to be connected is not a serious problem.

Reasons for positioning

A restorableResponder property in the system private class UIInputViewSet is neither weak nor strong, similar to unsafe_unretained. So when it is accessed, it is easy to create wild Pointers. When it is assigned to a variable of type __strong ID, it crashes in _objc_retain.

We can use symbolic breakpoints to confirm from assembly that the getters and setters of restorableResponder property in iOS 14 Beta 2 simply access a memory value without doing anything weak or strong would do.

A hook -[UIInputViewSet restorableResponder] method can be used to verify that its return value is often a wild pointer.

Positioning process

How to locate the -[UIInputViewSet restorableResponder] method? My thinking goes like this:

1, speculation problem comes from the top of stack – [UIInputResponderController prepareToMoveKeyboardForInputViewSet: animationStyle:] (in UIKitCore) parameters

2, hook – [UIInputResponderController prepareToMoveKeyboardForInputViewSet: animationStyle:] method, obtain the incoming parameters, found that there are two parameters, The first parameter type is UIInputViewSet. These two parameters are not wild Pointers themselves.

3, hook – [UIInputResponderController prepareToMoveKeyboardForInputViewSet: animationStyle:], try to pass in two arguments to nil, It turns out crash doesn’t recur. This basically confirms that the problem is with parameters. But the parameter itself is not a wild pointer, so presumably the problem is the return value of one of the methods of the parameter.

4. According to an old UIInputViewSet header file, send messages to this UIInputViewSet object in turn in LLDB. Found a property restorableResponder marked weak on older versions, but the address returned by the getter method was not an object. Seriously doubt this is a wild pointer.

[UIInputViewSet restorableResponder] hook -[UIInputViewSet restorableResponder] [UIInputViewSet restorableResponder

6. Verify by assembly that restorableResponder is neither strong nor weak on iOS 14 Beta 2

I believe that many teams have encountered this crash. I failed to search on the Internet before, so I will present my solution for now. Welcome to communicate with you. Of course, the apple dad will eventually fix it 😭