NSURLSession causant un mauvais accès à L'EXC

j'ai remarqué que la mise en œuvre NSURLSessionDataDelegate et démarrer une tâche lancera très occasionnellement un EXC_BAD_ACCESS. La réelle méthode d'appel qui donne l'erreur semble varier, mais vient toujours CFNetwork. Pour la plupart, la méthode d'appel vient de NSURLSession delegate_dataTask:didReceiveData:completionHandler. J'ai joint deux rapports de crash avec des appelants différents ci-dessous. J'ai également joint ma mise en œuvre de NSURLSessionDataDelegate.

malheureusement, je ne peux pas reproduire l'erreur de manière fiable, donc je n'ai pas de script d'exemple à partager. La création et le démarrage Downloader les objets finiront par créer l'erreur. Il semble se produire plus souvent avec de gros fichiers. Ai-je mis en place quelque chose de mal ici? Y a-t-il un bon moyen de déboguer de ce stacktrace?

j'ai testé sur iOS10 et 10.1.1 avec les mêmes résultats.

mise en oeuvre:

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

mise à jour: Je peux maintenant reproduire cette erreur de façon semi-fiable en exécuter la boucle collée ci-dessous dans le simulateur iOS. Cela n'arrive pas sur iOS 9.3. Si vous exécutez le code ci-dessous, vous devriez recevoir l'erreur en une minute. Comme il est très probable que cela se produise dans le simulateur, par rapport à un appareil, je suppose que c'est un problème de concurrence qui devient plus probable avec plus de puissance de traitement/cœurs. Pour reproduire l'erreur, exécutez ceci:

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
}
29
demandé sur oliveroneill 2016-11-02 05:24:38

2 réponses

après avoir parlé avec le support technique D'Apple, nous avons confirmé que c'est un bug dans le libBacktraceRecording.dylib bibliothèque, qui est utilisée pour déboguer dans Xcode. J'ai rempli un rapport de bogue et on m'a dit qu'il ne se crasherait pas sur un périphérique utilisateur puisqu'il s'agit d'une erreur de débogage qui se produit dans une bibliothèque qui n'est pas présente sur la plupart des périphériques utilisateurs.

44
répondu oliveroneill 2017-09-20 04:46:48

essayez de courir dans L'Instrument Zombies. Ma conjecture est que votre Downloader l'instance de classe est désactivée alors que la Nslsession fonctionne, donc quand elle va appeler votre méthode didReceiveData, la mémoire précédemment occupée par votre objet contient autre chose. (Qu'est ce qu'un zombie.)

2
répondu Duncan C 2016-11-02 11:47:19