Occasional crash in _cow_failure during test

We've started encountering a rare crash in the Alamofire test suite on our *Response transform APIs, now that we've made them doubly generic (e.g. DataResponse<Success, Failure: Error>) and use our AFError to encapsulate all errors by default.

Here's the backtrace
thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    frame #0: 0x00000001032475fe CoreFoundation`_cow_failure + 21
    frame #1: 0x00000001032475d1 CoreFoundation`_cow_release + 209
    frame #2: 0x000000010326eaae CoreFoundation`-[__NSFrozenDictionaryM dealloc] + 46
    frame #3: 0x00000001027b372c libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #4: 0x000000010205b423 Foundation`-[NSError dealloc] + 64
    frame #5: 0x00000001027b372c libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #6: 0x000000011d3b74dd Alamofire`destroy for AFError at <compiler-generated>:0
    frame #7: 0x000000011d3930ab Alamofire`destroy for DataResponse at <compiler-generated>:0
    frame #8: 0x000000011daab17b libswiftCore.dylib`(anonymous namespace)::destroyGenericBox(swift::HeapObject*) + 27
    frame #9: 0x000000011daaa870 libswiftCore.dylib`_swift_release_dealloc + 16
    frame #10: 0x000000011d4cbea9 Alamofire`___lldb_unnamed_symbol309$$Alamofire + 57
    frame #11: 0x000000011daaa870 libswiftCore.dylib`_swift_release_dealloc + 16
    frame #12: 0x000000011d4c1ed2 Alamofire`___lldb_unnamed_symbol281$$Alamofire + 34
    frame #13: 0x000000011daaa870 libswiftCore.dylib`_swift_release_dealloc + 16
    frame #14: 0x000000011d4c1ff5 Alamofire`block_destroy_helper.8 at <compiler-generated>:0
    frame #15: 0x000000010540b9cd libsystem_blocks.dylib`_Block_release + 105
    frame #16: 0x0000000100f417f2 libclang_rt.tsan_iossim_dynamic.dylib`__tsan::dispatch_callback_wrap(void*) + 306
    frame #17: 0x0000000105318d02 libdispatch.dylib`_dispatch_client_callout + 8
    frame #18: 0x0000000105324a50 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 1276
    frame #19: 0x00000001031638a9 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    frame #20: 0x000000010315df56 CoreFoundation`__CFRunLoopRun + 2310
    frame #21: 0x000000010315d302 CoreFoundation`CFRunLoopRunSpecific + 626
    frame #22: 0x0000000102684f24 XCTest`-[XCTWaiter waitForExpectations:timeout:enforceOrder:] + 996
    frame #23: 0x000000010261eb27 XCTest`-[XCTestCase(AsynchronousTesting) waitForExpectationsWithTimeout:handler:] + 461
  * frame #24: 0x000000011c6c04e5 Alamofire iOS Tests`ResponseMapTestCase.testThatMapTransformsSuccessValue(self=0x00007b0800039e40) at ResponseTests.swift:397:9
    frame #25: 0x000000011c6c35e1 Alamofire iOS Tests`@objc ResponseMapTestCase.testThatMapTransformsSuccessValue() at <compiler-generated>:0
    frame #26: 0x00000001032034cc CoreFoundation`__invoking___ + 140
    frame #27: 0x0000000103200a45 CoreFoundation`-[NSInvocation invoke] + 325
    frame #28: 0x0000000102632b74 XCTest`__24-[XCTestCase invokeTest]_block_invoke.194 + 78
    frame #29: 0x000000010268a8a4 XCTest`-[XCTestCase(Failures) performFailableBlock:testCaseRun:shouldInterruptTest:] + 57
    frame #30: 0x000000010268a7c2 XCTest`-[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 96
    frame #31: 0x0000000102632804 XCTest`__24-[XCTestCase invokeTest]_block_invoke + 848
    frame #32: 0x0000000102690d01 XCTest`-[XCUITestContext performInScope:] + 128
    frame #33: 0x00000001026323f1 XCTest`-[XCTestCase testContextPerformInScope:] + 116
    frame #34: 0x00000001026324a7 XCTest`-[XCTestCase invokeTest] + 137
    frame #35: 0x0000000102633f73 XCTest`__26-[XCTestCase performTest:]_block_invoke_2 + 43
    frame #36: 0x000000010268a8a4 XCTest`-[XCTestCase(Failures) performFailableBlock:testCaseRun:shouldInterruptTest:] + 57
    frame #37: 0x000000010268a7c2 XCTest`-[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 96
    frame #38: 0x0000000102633e8a XCTest`__26-[XCTestCase performTest:]_block_invoke.316 + 88
    frame #39: 0x000000010269b3b7 XCTest`+[XCTContext runInContextForTestCase:block:] + 225
    frame #40: 0x00000001026335f8 XCTest`-[XCTestCase performTest:] + 676
    frame #41: 0x0000000102676d6c XCTest`-[XCTest runTest] + 57
    frame #42: 0x000000010262e0d7 XCTest`__27-[XCTestSuite performTest:]_block_invoke + 365
    frame #43: 0x000000010262d8b3 XCTest`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 54
    frame #44: 0x000000010262db6f XCTest`-[XCTestSuite performTest:] + 290
    frame #45: 0x0000000102676d6c XCTest`-[XCTest runTest] + 57
    frame #46: 0x000000010262e0d7 XCTest`__27-[XCTestSuite performTest:]_block_invoke + 365
    frame #47: 0x000000010262d8b3 XCTest`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 54
    frame #48: 0x000000010262db6f XCTest`-[XCTestSuite performTest:] + 290
    frame #49: 0x0000000102676d6c XCTest`-[XCTest runTest] + 57
    frame #50: 0x000000010262e0d7 XCTest`__27-[XCTestSuite performTest:]_block_invoke + 365
    frame #51: 0x000000010262d8b3 XCTest`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 54
    frame #52: 0x000000010262db6f XCTest`-[XCTestSuite performTest:] + 290
    frame #53: 0x0000000102676d6c XCTest`-[XCTest runTest] + 57
    frame #54: 0x00000001026a5986 XCTest`__44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke + 171
    frame #55: 0x00000001026a5a57 XCTest`__44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke.80 + 68
    frame #56: 0x0000000102645474 XCTest`-[XCTestObservationCenter _observeTestExecutionForBlock:] + 588
    frame #57: 0x00000001026a573d XCTest`-[XCTTestRunSession runTestsAndReturnError:] + 623
    frame #58: 0x000000010261241c XCTest`-[XCTestDriver runTestsAndReturnError:] + 446
    frame #59: 0x000000010269756f XCTest`_XCTestMain + 2333
    frame #60: 0x0000000100e40cb9 xctest`main + 263
    frame #61: 0x0000000105386541 libdyld.dylib`start + 1

This test should make a network request which is then parsed successfully, so does this stack mean that it failed and produced an error, and that that error failed to dealloc properly, or is there something else?

Totally random guess but did you try running this with the thread sanitizer?

CC @millenomi & @Tony_Parker for qualified advise :slight_smile:

This absolutely looks like a memory management failure of some sort, and that it’s rare may suggest that concurrency is involved. Running on TSan may help find issues proactively, and if that fails running repeatedly with malloc logging enabled or the Zombies template in Instruments may capture retain/release information that would be invaluable to diagnose this.

The thread sanitizer is always active for or tests but I’ll try enabling the other memory tooling. I still can’t trigger it reliably. And while the value is created in the background, the transform and testing take place on the main queue.

If you have a minimal test case, it’d be interesting to encapsulate it in a feedback.

If I could get it to reproduce I would. Right now it seems most likely to occur in one of the Response mapping tests in Alamofire's ResponseTests file, namely in the ResponseMap*TestCase or ResponseTryMap*TestCase tests. They seem to have started when we made our DataResponse and DownloadResponse generic to the Failure type as well as the previously generic Success type in recent PRs (the developer of which noted occasional failures as well).

Terms of Service

Privacy Policy

Cookie Policy