Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSURLSession causing EXC_BAD_ACCESS

I've noticed that implementing NSURLSessionDataDelegate and starting a task will very occasionally throw an EXC_BAD_ACCESS. The actual calling method that gives the error seems to vary but always comes from CFNetwork. For the most part, the calling method comes from NSURLSession delegate_dataTask:didReceiveData:completionHandler. I've attached two crash logs with different callers below. I've also attached my implementation of NSURLSessionDataDelegate.

Unfortunately I cannot reliably reproduce the error, so I don't have an example script to share. Creating and starting Downloader objects will eventually create the error. It does seem to happen more often with larger files. Have I implemented something wrong here? Is there a good way to debug from this stacktrace?

I've tested on iOS10 and 10.1.1 with the same results.

Implementation:

class Downloader: NSObject, NSURLSessionDataDelegate {     private let url: String     var finished = false     let finishCondition = NSCondition()      init(url:String) {         self.url = url         super.init()     }      func start() {         let config = NSURLSessionConfiguration.defaultSessionConfiguration()         let session = NSURLSession(configuration: config,                                delegate: self,                                delegateQueue: nil)         guard let u = NSURL(string: url) else {             return         }         let request = NSMutableURLRequest(URL: u)         let task = session.dataTaskWithRequest(request)         task.resume()     }      func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,                     didReceiveData data: NSData) {     }      func URLSession(session: NSURLSession,                     task: NSURLSessionTask,                     didCompleteWithError error: NSError?) {         session.invalidateAndCancel()     }      func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,                     didReceiveResponse response: NSURLResponse,                                        completionHandler: (NSURLSessionResponseDisposition) -> Void) {         completionHandler(NSURLSessionResponseDisposition.Allow)     }      func waitForFinish() {         finishCondition.lock()         while !finished {             finishCondition.wait()         }         finishCondition.unlock()     }      func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {         finishCondition.lock()         finished = true         finishCondition.broadcast()         finishCondition.unlock()     } } 

Crash log #1:

* thread #5: tid = 0x25923, 0x0000000100042e8c libBacktraceRecording.dylib`__gcd_queue_item_enqueue_hook_block_invoke, queue = 'com.apple.NSURLSession-work', stop reason = EXC_BAD_ACCESS (code=1, address=0xf8686a68b98c6ec8)   * frame #0: 0x0000000100042e8c libBacktraceRecording.dylib`__gcd_queue_item_enqueue_hook_block_invoke     frame #1: 0x000000010004241c libBacktraceRecording.dylib`gcd_queue_item_enqueue_hook + 232     frame #2: 0x000000010065dee8 libdispatch.dylib`_dispatch_introspection_queue_item_enqueue_hook + 40     frame #3: 0x000000010063cba4 libdispatch.dylib`_dispatch_queue_push + 196     frame #4: 0x000000018ba50500 Foundation`iop_promote_qos_outward + 112     frame #5: 0x000000018ba4e524 Foundation`-[NSOperation setQualityOfService:] + 168     frame #6: 0x000000018b9d7714 Foundation`-[NSOperationQueue addOperationWithBlock:] + 76     frame #7: 0x000000018b73f82c CFNetwork`-[NSURLSession delegate_dataTask:didReceiveData:completionHandler:] + 208     frame #8: 0x000000018b5a2c5c CFNetwork`-[__NSCFLocalSessionTask _task_onqueue_didReceiveDispatchData:completionHandler:] + 276     frame #9: 0x000000018b5a5474 CFNetwork`-[__NSCFLocalSessionTask connection:didReceiveData:completion:] + 164     frame #10: 0x000000018b647bf0 CFNetwork`__48-[__NSCFURLLocalSessionConnection _tick_running]_block_invoke + 120     frame #11: 0x000000018b647b60 CFNetwork`-[__NSCFURLLocalSessionConnection _tick_running] + 344     frame #12: 0x000000018b648c74 CFNetwork`-[__NSCFURLLocalSessionConnection _didReceiveData:] + 412     frame #13: 0x000000018b64af8c CFNetwork`SessionConnectionLoadable::_loaderClientEvent_DidReceiveData(__CFArray const*) + 52     frame #14: 0x000000018b6f823c CFNetwork`___ZN19URLConnectionLoader19protocolDidLoadDataEPK8__CFDatax_block_invoke_2 + 44     frame #15: 0x000000018b64b58c CFNetwork`___ZN25SessionConnectionLoadable21withLoaderClientAsyncEU13block_pointerFvP21LoaderClientInterfaceE_block_invoke + 32     frame #16: 0x000000010063125c libdispatch.dylib`_dispatch_call_block_and_release + 24     frame #17: 0x000000010063121c libdispatch.dylib`_dispatch_client_callout + 16     frame #18: 0x000000010063eb54 libdispatch.dylib`_dispatch_queue_serial_drain + 1136     frame #19: 0x0000000100634ce4 libdispatch.dylib`_dispatch_queue_invoke + 672     frame #20: 0x0000000100640e6c libdispatch.dylib`_dispatch_root_queue_drain + 584     frame #21: 0x0000000100640bb8 libdispatch.dylib`_dispatch_worker_thread3 + 140     frame #22: 0x000000018a01e2b8 libsystem_pthread.dylib`_pthread_wqthread + 1288     frame #23: 0x000000018a01dda4 libsystem_pthread.dylib`start_wqthread + 4 

Crash log #2:

* thread #12: tid = 0x2521f, 0x000000010010ae8c libBacktraceRecording.dylib`__gcd_queue_item_enqueue_hook_block_invoke, queue = 'com.apple.CFNetwork.Connection', stop reason = EXC_BAD_ACCESS (code=1, address=0xd00f524835000200)       * frame #0: 0x000000010010ae8c libBacktraceRecording.dylib`__gcd_queue_item_enqueue_hook_block_invoke         frame #1: 0x000000010010a41c libBacktraceRecording.dylib`gcd_queue_item_enqueue_hook + 232         frame #2: 0x0000000100759ee8 libdispatch.dylib`_dispatch_introspection_queue_item_enqueue_hook + 40         frame #3: 0x0000000100738ba4 libdispatch.dylib`_dispatch_queue_push + 196         frame #4: 0x00000001975ccb3c libnetwork.dylib`nw_connection_read + 448         frame #5: 0x00000001975d938c libnetwork.dylib`tcp_connection_read + 168         frame #6: 0x000000018b719d54 CFNetwork`TCPIOConnection::read(unsigned long, unsigned long, void (dispatch_data_s*, CFStreamError) block_pointer) + 172         frame #7: 0x000000018b782af4 CFNetwork`HTTPEngine::_getBodyIntelligently(void (dispatch_data_s*, CFStreamError, bool) block_pointer) + 816         frame #8: 0x000000018b780d0c CFNetwork`HTTPEngine::_readBodyStartNextRead() + 76         frame #9: 0x000000018b783664 CFNetwork`___ZN10HTTPEngine21_getBodyIntelligentlyEU13block_pointerFvP15dispatch_data_s13CFStreamErrorbE_block_invoke.56 + 344         frame #10: 0x000000018b719f64 CFNetwork`___ZN15TCPIOConnection4readEmmU13block_pointerFvP15dispatch_data_s13CFStreamErrorE_block_invoke + 480         frame #11: 0x000000010072d25c libdispatch.dylib`_dispatch_call_block_and_release + 24         frame #12: 0x000000010072d21c libdispatch.dylib`_dispatch_client_callout + 16         frame #13: 0x000000010073ab54 libdispatch.dylib`_dispatch_queue_serial_drain + 1136         frame #14: 0x0000000100730ce4 libdispatch.dylib`_dispatch_queue_invoke + 672         frame #15: 0x000000010073ce6c libdispatch.dylib`_dispatch_root_queue_drain + 584         frame #16: 0x000000010073cbb8 libdispatch.dylib`_dispatch_worker_thread3 + 140         frame #17: 0x000000018a01e2b8 libsystem_pthread.dylib`_pthread_wqthread + 1288         frame #18: 0x000000018a01dda4 libsystem_pthread.dylib`start_wqthread + 4 

UPDATE: I can now semi-reliably reproduce this error by running the loop pasted below in the iOS Simulator. This does not happen on iOS 9.3. If you run the code below, within a minute you should receive the error. Since it's very likely to occur in the simulator, compared with a device, I would assume it's a concurrency issue that becomes more likely with more processing power/cores. To reproduce error, run this:

var i = 0 while true {     print("running: \(i)")     // random url, larger files seem more likely to cause error     let url = "http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/3340/33409.ts"     let c = Downloader(url: url)     c.start()     c.waitForFinish()     i += 1 } 
like image 663
oliveroneill Avatar asked Nov 02 '16 02:11

oliveroneill


People also ask

What is EXC_ BAD_ ACCESS SIGSEGV?

What does EXC_BAD_ACCESS mean? EXC_BAD_ACCESS is an exception raised as a result of accessing bad memory. We're constantly working with pointers to memory in Swift that link to a specific memory address. An application will crash whenever we try to access a pointer that is invalid or no longer exists.

What is COM Apple Nsurlsession delegate?

A protocol that defines methods that URL session instances call on their delegates to handle session-level events, like session life cycle changes.

How to debug EXC_ BAD_ ACCESS iOS?

To debug an EXC_BAD_ACCESS, you can generally find out the where the dangling pointer is by enabling zombie objects. Choose edit scheme, then Diagnostics tab in the Run section, then click the 'Zombie Objects' option. Another cause for EXC_BAD_ACCESS can be infinite recursion, which can be found by adding some logging.


Video Answer


2 Answers

After speaking with Apple Technical Support we confirmed that it's a bug within the libBacktraceRecording.dylib library, which is used for debugging within Xcode. I have filed a bug report and have been told that it won't crash on a users device since this is a debug error that occurs within a library not present on most users' devices.

like image 75
oliveroneill Avatar answered Sep 30 '22 07:09

oliveroneill


Try running in the Zombies Instrument. My guess is that your Downloader class instance is getting deallocated while the NSURLSession is operating, so when it goes to call your didReceiveData method, the memory formerly occupied by your object contains something else. (That's what a zombie is.)

like image 32
Duncan C Avatar answered Sep 30 '22 05:09

Duncan C