2016-11-02 7 views
28

Я заметил, что реализация NSURLSessionDataDelegate и запуск задачи будут очень редко вызывать EXC_BAD_ACCESS. Фактический метод вызова, который дает ошибку, кажется, меняется, но всегда исходит от CFNetwork. По большей части метод вызова поступает от NSURLSession delegate_dataTask:didReceiveData:completionHandler. Я подключил два журнала сбоев с разными абонентами ниже. Я также приложил свою версию NSURLSessionDataDelegate.NSURLSession, вызывающий EXC_BAD_ACCESS

К сожалению, я не могу достоверно воспроизвести ошибку, поэтому у меня нет сценария для совместного использования. Создание и запуск объектов Downloader в конечном итоге приведет к ошибке. Кажется, что это происходит чаще с большими файлами. Я сделал здесь что-то не так? Есть ли хороший способ отладки из этой stacktrace?

Я тестировал на iOS10 и 10.1.1 с теми же результатами.

Реализация:

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() 
    } 
} 

Краш журнал # 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 

Краш журнал # 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: теперь я могу полу надежно воспроизвести эту ошибку запуская петлю, вставленную ниже в iOS Simulator. Это не происходит на iOS 9.3. Если вы запустите код ниже, в течение минуты вы должны получить сообщение об ошибке. Поскольку это может произойти в симуляторе, по сравнению с устройством, я бы предположил, что это проблема параллелизма, которая становится более вероятной с большей вычислительной мощностью/ядрами. Чтобы воспроизвести ошибку, выполните следующее:

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 
} 
+2

Увидеть это в iOS 10, но не в 9.3 симуляторе. Те же симптомы, одна и та же обратная линия, никаких подсказок. – Icydog

+2

Я вижу аналогичный сбой на 10.0 симуляторе '' '* thread # 64: tid = 0x5e3688, 0x000000010717deac libBacktraceRecording.dylib'__gcd_queue_item_enqueue_hook_block_invoke + 4, queue = 'com.apple.network.connections', stop reason = EXC_BAD_ACCESS (код = EXC_I386_GPFLT) '' ' – yuf

+1

Я рад, что я не единственный. Есть ли хороший способ отладить это? – oliveroneill

ответ

43

После разговора с Apple Technical Support мы подтвердили, что это ошибка в библиотеке libBacktraceRecording.dylib, которая используется для отладки в Xcode. Я отправил отчет об ошибке и сказал, что он не будет разбиваться на пользовательское устройство, поскольку это ошибка отладки, которая возникает в библиотеке, отсутствующей на большинстве устройств пользователей.

+1

Можете ли вы поделиться ссылкой или дополнительной информацией об отчете об ошибке? Так что другие могут оценить его прогресс? И любопытно, как именно вы связались с технической поддержкой Apple? Являются ли они отзывчивыми? – Honey

+1

Я еще не поставил его на openradar, но Apple вообще дает очень мало отзывов о прогрессе.Вы можете связаться с Apple для технической поддержки разработчиков с помощью https://developer.apple.com/support/technical/. На следующий рабочий день они обычно отвечают, так что они довольно отзывчивы. – oliveroneill

+2

Я получаю тот же самый крах на Mac в Сьерра; те же симптомы, (EXC_BAD_ACCESS глубоко в коде NSURLConnectionLoader, но только из сеансов отладки Xcode); любой из охранников Malloc, адрес дезинфицирующего средства и т. д. и т. д. все это исправляет. Тот же самый dylib используется на Mac – mackworth

1

Попробуйте запустить в зомби инструмент. Я предполагаю, что ваш экземпляр класса Downloader получает освобождение во время работы NSURLSession, поэтому, когда он вызывается для вызова метода didReceiveData, память, ранее занятая вашим объектом, содержит что-то еще. (Это то, что зомби.)

+2

Мне не удалось воссоздать ошибку в инструменте Zombie. Однако включение «объектов зомби» из «Edit Scheme» действительно вызывало ту же ошибку, не вызывая никаких предупреждений об объектах зомби. Есть ли разница между этими двумя? – oliveroneill

+1

Я вижу подобный сбой, и у меня были зомби, когда это произошло, но ничего не поймало. – yuf

+0

Я могу подтвердить, что это все еще происходит с Xcode 9, бета-5 на Sierra 10.12.5. – manmal

Смежные вопросы