title: NSURLSession causing EXC_BAD_ACCESS
body: <p>I've noticed that implementing <code>NSURLSessionDataDelegate</code> 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 <code>CFNetwork</code>. For the most part, the calling method comes from <code>NSURLSession delegate_dataTask:didReceiveData:completionHandler</code>. I've attached two crash logs with different callers below. I've also attached my implementation of <code>NSURLSessionDataDelegate</code>.</p>
  
  <p>Unfortunately I cannot reliably reproduce the error, so I don't have an example script to share. Creating and starting <code>Downloader</code> 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?</p>
  
  <p>I've tested on iOS10 and 10.1.1 with the same results.</p>
  
  <p>Implementation:</p>
  
  <pre><code>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) -&gt; 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()
      }
  }
  </code></pre>
  
  <p>Crash log #1:</p>
  
  <pre><code>* 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
  </code></pre>
  
  <p>Crash log #2:</p>
  
  <pre><code>* 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
  </code></pre>
  
  <p>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:</p>
  
  <pre><code>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
  }
  </code></pre>