Crash in WebCore::RunLoopObserver::invalidate() after closing UIwebView

We have an app running on iPad that uses UIWebView. The crash seems to have started after upgrading to iOS 16.4, and it's not happening on all models of iPad tested.

The crash occurs in a background thread after we dismiss the view controller that displays the web view, but only if we have previously gone through webView:shouldStartLoadWithRequest:navigationType: which is kicked off by a successful submission.

Here are the relevant parts from a crash log:

Incident Identifier: 27C200B6-7F7D-4FF2-B9A1-E1B5FE8C1156
CrashReporter Key:   9c6442f7a7ab4ea89fa465d3d7769cde6bfe964e
Hardware Model:      iPad6,7
Process:             LineSkip POS [498]
Path:                /private/var/containers/Bundle/Application/F8E66EE3-C19E-42E2-8B9E-F8D83D9A389B/LineSkip POS.app/LineSkip POS
Identifier:          com.lineskipapp.LineSkip-POS
Version:             2.1.37 (706)
AppStoreTools:       14C17
AppVariant:          1:iPad6,7:15
Code Type:           ARM-64 (Native)
Role:                Foreground
Parent Process:      launchd [1]
Coalition:           com.lineskipapp.LineSkip-POS [612]

Date/Time:           2023-04-04 19:58:26.3638 -0500
Launch Time:         2023-04-04 19:55:30.1362 -0500
OS Version:          iPhone OS 16.4 (20E246)
Release Type:        User
Report Version:      104

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000010
Exception Codes: 0x0000000000000001, 0x0000000000000010
VM Region Info: 0x10 is not in any region.  Bytes before following region: 68719476720
      REGION TYPE                 START - END      [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      commpage (reserved)     1000000000-7000000000 [384.0G] ---/--- SM=NUL  ...(unallocated)
Termination Reason: SIGNAL 11 Segmentation fault: 11
Terminating Process: exc handler [498]

Triggered by Thread:  9

          .   .   . 

Thread 9 name:  WebThread
Thread 9 Crashed:
0   WebCore                       	       0x1c764be50 WebCore::RunLoopObserver::invalidate() + 16
1   WebKitLegacy                  	       0x1f9c53ed4 ***::Detail::CallableWrapper<WebViewRenderingUpdateScheduler::WebViewRenderingUpdateScheduler(WebView*)::$_6, void>::call() + 228
2   CoreFoundation                	       0x1b688da58 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
3   CoreFoundation                	       0x1b681d68c __CFRunLoopDoObservers + 552
4   CoreFoundation                	       0x1b687deec CFRunLoopRunSpecific + 676
5   WebCore                       	       0x1c6896b74 RunWebThread(void*) + 780
6   libsystem_pthread.dylib       	       0x1ffaa10ec _pthread_start + 116
7   libsystem_pthread.dylib       	       0x1ffa9f72c thread_start + 8

I'm at a loss for what's causing this. What can I do to troubleshoot this further?

UPDATE: So far, we've identified 3 iPads where it's crashing, and they are all 1st gen 12.9 inch iPad Pro ("HARDWARE Model: iPad6,7"). Every other model of iPad we've tested on (probably newer), we cannot reproduce the crash.

Replies

OK, after a lot of trial and error, I was able to fix the crash. It just amounted to commenting out various lines of code to see what made the crash go away. Here is an approximation of the original code:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if (self.appUrlNameSpace && [request.URL.absoluteString hasPrefix:self.appUrlNameSpace])
    {
        BOOL success = ([request.URL.absoluteString rangeOfString:self.failureUrlComponent].location != NSNotFound);
        if (success)
        {
            NSString *responseString = [[NSString alloc]initWithData:response.HTTPBody encoding:NSUTF8StringEncoding];
            responseItems = [[NSDictionary alloc]initWithHTTPPostResponse:responseString];
            NSLog(@"Returned items %@", responseItems);
            
            [self.delegate dismissViewControllerAnimated:NO completion:^{
                    .  .  .
            }];
        }
        else
        {
            . . .
        }
        return NO;
    }
    else if ( . . .)
    {
    }
    
    return YES;
}

The key finding was that disabling the dismissal of the view inside the webView:shouldStartLoadingWithRequest: was what prevented the crash. The code in the completion block did not need to be delayed, so I moved that to execute immediately (but this had no bearing on whether the crash occurred or not). So, I rearranged the code as follows such that dismissing the view does not occur directly from the UIWebView delegate callback, and magically the crash was gone.

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if (self.appUrlNameSpace && [request.URL.absoluteString hasPrefix:self.appUrlNameSpace])
    {
        BOOL success = ([request.URL.absoluteString rangeOfString:self.failureUrlComponent].location != NSNotFound);
        if (success)
        {
            NSString *responseString = [[NSString alloc]initWithData:response.HTTPBody encoding:NSUTF8StringEncoding];
            responseItems = [[NSDictionary alloc]initWithHTTPPostResponse:responseString];
            NSLog(@"Returned items %@", responseItems);
            
               .   .   .   /* Code that was originally in the completion block */
            
            /* Delaying dismissal somehow prevents crash */
            long delay = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC);
            dispatch_after( delay, dispatch_get_main_queue(), ^{
                [self.delegate dismissViewControllerAnimated:NO completion:nil];
            });
        }
        else
        {
            . . .
        }
        return NO;
    }
    else if ( . . .)
    {
    }
    
    return YES;
}

I have no idea why this would make any difference, or why this crash only occurred on certain (older) iPad models, but hopefully this helps someone in the future.