Crash caused by CFNetwork assertion

Hello,

Our app has an internal job processing queue. All jobs are built as a NSOperation and involve a network request, and they are added to NSOperationQueue. When the app is closed while a request is being sent, the app sometimes crashes, but it also keeps crashing whenever we build the operation again and retry it. This happens rarely, but we can systematically reproduce it after a few tries with many jobs.

This issue blocks the queue in our app. I understand if this is an issue deep within the framework, but it would be very useful to at least find a way to work around this issue so the queue can continue processing other jobs.

The full crash report is attached. I also submitted a bug report: FB13734737

There seems to be an internal assertion fired in CFNetwork:

Assertion failed: (CFReadStreamGetStatus(_stream.get()) == kCFStreamStatusNotOpen) function _onqueue_setupStream_block_invoke file HTTPRequestBody.cpp line 878.
Crashed: com.apple.NSURLConnectionLoader
0  libsystem_kernel.dylib         0xa974 __pthread_kill + 8
1  libsystem_pthread.dylib        0x60ec pthread_kill + 268
2  libsystem_c.dylib              0x75b80 abort + 180
3  libsystem_c.dylib              0x74e70 err + 282
4  CFNetwork                      0x1f73b8 CFHTTPCookieStorageUnscheduleFromRunLoop + 278252
5  libdispatch.dylib              0x3dd4 _dispatch_client_callout + 20
6  libdispatch.dylib              0x786c _dispatch_block_invoke_direct + 288
7  CFNetwork                      0x259ab0 estimatedPropertyListSize + 33724
8  CoreFoundation                 0x24b34 CFArrayApplyFunction + 72
9  CFNetwork                      0x2599a0 estimatedPropertyListSize + 33452
10 CFNetwork                      0x25c084 estimatedPropertyListSize + 43408
11 CoreFoundation                 0x3762c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
12 CoreFoundation                 0x368a8 __CFRunLoopDoSource0 + 176
13 CoreFoundation                 0x35058 __CFRunLoopDoSources0 + 244
14 CoreFoundation                 0x33d88 __CFRunLoopRun + 828
15 CoreFoundation                 0x33968 CFRunLoopRunSpecific + 608
16 CFNetwork                      0x25ac48 estimatedPropertyListSize + 38228
17 Foundation                     0x9ca9c __NSThread__start__ + 732
18 libsystem_pthread.dylib        0x2a90 _pthread_start + 136
19 libsystem_pthread.dylib        0x1fcc thread_start + 8

This is how we build the operation:

-(NSOperation*)operationForRequest:(Job*)job
{
    NSURL *url = [NSURL URLWithString:job.url];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:@"application/json, application/xml, text/plain" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"];
    [request setValue:[NSString stringWithFormat:@"Bearer %@", [self getToken]] forHTTPHeaderField:@"Authorization"];
    [request setHTTPMethod:job.method];
    NSData *bodyData = [job.payload dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:bodyData];

    return [[NetworkOperation alloc] initWithRequest:request uuid:job.jobId completionHandler:^(NSString* jobId, NSData *data, NSURLResponse *response, NSError *error) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            @autoreleasepool {
                RLMRealm *realm = [RLMRealm defaultRealm];
                Job *opJob = [Job objectInRealm:realm forPrimaryKey:jobId];
                [self processJobResponse:opJob response:response data:data error:error realm:realm];
            }
        });
    }];
}

This is how the NetworkOperation executes the request:

- (void)main {
    NSURLSession *session = [NSURLSession sharedSession];

    NSURLSessionTask *task = [session dataTaskWithRequest:self.request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (self.networkOperationCompletionBlock) {
            self.networkOperationCompletionBlock(self.uuid, data, response, error);
            self.networkOperationCompletionBlock = nil;
        }

        [self completeOperation];
    }];

    [task resume];

    self.task = task;
}

That crash report is from iOS 15.0.2, and there’s been a loth of water under the bridge since there. Are you seeing this on newer iOS versions? If so, please post a crash report from something in the iOS 17 timeframe.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Apologies. From what I tested, this happens on all iOS versions. Here's a crash report from iOS 17.3.1

Thanks for the new crash report.

Your third-party crash reporter (thread 9) means that I can’t 100% trust it [1], but it seems to be generally OK.

The crashing thread backtrace looks like this:

Thread 16 Crashed:
0  libsystem_kernel.dylib  … __pthread_kill + 8 (:-1)
1  libsystem_pthread.dylib … pthread_kill + 268 (pthread.c:1681)
2  libsystem_c.dylib       … __abort + 136 (abort.c:159)
3  libsystem_c.dylib       … abort + 192 (abort.c:126)
4  libsystem_c.dylib       … __assert_rtn + 284 (assert.c:94)
5  CFNetwork               … invocation function for block in RequestBodyStream::_onqueue_setupStream() + 252 (…
6  libdispatch.dylib       … _dispatch_client_callout + 20 (object.m:561)
7  libdispatch.dylib       … _dispatch_block_invoke_direct + 284 (queue.c:496)
8  CFNetwork               … RunloopBlockContext::_invoke_block(void const*, void*) + 44 (CoreSchedulingSet.mm:…
9  CoreFoundation          … CFArrayApplyFunction + 72 (CFArray.c:672)
10 CFNetwork               … RunloopBlockContext::perform() + 136 (CoreSchedulingSet.mm:291)
11 CFNetwork               … MultiplexerSource::_perform(void*) + 336 (CFNRunLoopMultiplexer.c:39)
12 CoreFoundation          … __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 (CFRunLoop.c:1957)
13 CoreFoundation          … __CFRunLoopDoSource0 + 176 (CFRunLoop.c:2001)
14 CoreFoundation          … __CFRunLoopDoSources0 + 244 (CFRunLoop.c:2038)
15 CoreFoundation          … __CFRunLoopRun + 828 (CFRunLoop.c:2955)
16 CoreFoundation          … CFRunLoopRunSpecific + 608 (CFRunLoop.c:3420)
17 CFNetwork               … +[__CFN_CoreSchedulingSetRunnable _run:] + 384 (CoreSchedulingSet.mm:1479)
18 Foundation              … __NSThread__start__ + 732 (NSThread.m:991)
19 libsystem_pthread.dylib … _pthread_start + 136 (pthread.c:904)
20 libsystem_pthread.dylib … thread_start + 8 (:-1)

Frames 4 through 0 indicate that you tripped an assert within CFNetwork. Frame 5 is part of the RequestBodyStream::_onqueue_setupStream() method. This is setting up the body stream for a streamed request. The assert looks something like this:

assert(CFReadStreamGetStatus(bodyStream) == .notOpen)

When you use a streamed body, CFNetwork opens the stream itself. This assert traps if you give it a stream that’s already been opened.

It’s possible that this might be an error is CFNetwork’s internal logic. However, the first step for you is to look at all your uses of streamed bodies to see if there’s any chance you’re giving CFNetwork an open stream.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] See Implementing Your Own Crash Reporter.

Thank you for the insights!

I reviewed our code and we don't send any streamed requests. All requests are built similarly to the snippet in my original message (with an NSData object) and they are all executed in the queue as a NetworkOperation.

We are also getting similar crashes for what should be simple NSMutableURLRequest. All the crashes occur within estimatedPropertyListSize, which appears to be an internal CFNetwork method which is spontaneously being called.

We do not access the CFNetwork instance directly, it is entirely being managed by the URLRequest.

0   CFNetwork                            0x000000019d93d150 _CFStreamErrorFromCFError + 54920
1   CFNetwork                            0x000000019d915434 CFURLConnectionInvalidateConnectionCache + 17224
2   CoreFoundation                       0x000000019c727c80 _CFStreamClose + 104
3   CFNetwork                            0x000000019d993de8 _CFStreamErrorFromCFError + 410396
4   CFNetwork                            0x000000019d993d74 _CFStreamErrorFromCFError + 410280
5   CoreFoundation                       0x000000019c726550 _CFRelease + 288
6   CFNetwork                            0x000000019daad8f8 estimatedPropertyListSize + 41472
7   libdispatch.dylib                    0x00000001a461513c _dispatch_call_block_and_release + 28
8   libdispatch.dylib                    0x00000001a4616dd4 _dispatch_client_callout + 16
9   libdispatch.dylib                    0x00000001a461e400 _dispatch_lane_serial_drain + 744
10  libdispatch.dylib                    0x00000001a461ef64 _dispatch_lane_invoke + 428
11  libdispatch.dylib                    0x00000001a4620284 _dispatch_workloop_invoke + 1752
12  libdispatch.dylib                    0x00000001a4629cb4 _dispatch_root_queue_drain_deferred_wlh + 284
13  libdispatch.dylib                    0x00000001a4629528 _dispatch_workloop_worker_thread + 400
14  libsystem_pthread.dylib              0x00000001f86fcf20 _pthread_wqthread + 284
15  libsystem_pthread.dylib              0x00000001f86fcfc0 start_wqthread + 4

Crash caused by CFNetwork assertion
 
 
Q