NSURLSession causing EXC_BAD_ACCESS

匿名 (未验证) 提交于 2019-12-03 01:26:01

问题:

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 } 

回答1:

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.



回答2:

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.)



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!