MakeAWishFoundation/SwiftyMocky

EXC_BAD_ACCESS after updating to Xcode 13.3

IuliiaMishina opened this issue · 2 comments

After updating to Xcode 13.3 I am not able to mock closures inside protocol anymore using given method. Whenever I am trying to call a mocked closure I receive EXC_BAD_ACCESS:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7ff7ba78ede0)
    frame #0: 0x00007ff7ba78ede0
    frame #1: 0x000000010d07571c SwiftyMockyTest-Unit-Tests`thunk for @escaping @callee_guaranteed () -> (@out ()) at <compiler-generated>:0
  * frame #2: 0x000000010d06c35c SwiftyMockyTest-Unit-Tests`SwiftyMockyClosureTest.testExample(self=0x00007f9df8105900) at SwiftyMockyClosureTest.swift:22:14
    frame #3: 0x000000010d06c3b0 SwiftyMockyTest-Unit-Tests`@objc SwiftyMockyClosureTest.testExample() at <compiler-generated>:0
    frame #4: 0x00007fff2040d71c CoreFoundation`__invoking___ + 140
    frame #5: 0x00007fff2040aa8f CoreFoundation`-[NSInvocation invoke] + 305
    frame #6: 0x000000010625f588 XCTestCore`+[XCTFailableInvocation invokeErrorConventionInvocation:completion:] + 118
    frame #7: 0x000000010625f510 XCTestCore`__90+[XCTFailableInvocation invokeInvocation:withTestMethodConvention:lastObservedErrorIssue:]_block_invoke + 23
    frame #8: 0x000000010625f1ef XCTestCore`__81+[XCTFailableInvocation invokeWithAsynchronousWait:lastObservedErrorIssue:block:]_block_invoke.13 + 71
    frame #9: 0x000000010621bd83 XCTestCore`+[XCTSwiftErrorObservation observeErrorsInBlock:] + 68
    frame #10: 0x000000010625f084 XCTestCore`+[XCTFailableInvocation invokeWithAsynchronousWait:lastObservedErrorIssue:block:] + 443
    frame #11: 0x000000010625f4c3 XCTestCore`+[XCTFailableInvocation invokeInvocation:withTestMethodConvention:lastObservedErrorIssue:] + 205
    frame #12: 0x000000010625f7ca XCTestCore`+[XCTFailableInvocation invokeInvocation:lastObservedErrorIssue:] + 64
    frame #13: 0x000000010624c2c1 XCTestCore`__24-[XCTestCase invokeTest]_block_invoke.287 + 112
    frame #14: 0x0000000106213f33 XCTestCore`-[XCTestCase(XCTIssueHandling) _caughtUnhandledDeveloperExceptionPermittingControlFlowInterruptions:caughtInterruptionException:whileExecutingBlock:] + 181
    frame #15: 0x000000010624be4e XCTestCore`-[XCTestCase invokeTest] + 899
    frame #16: 0x000000010624d6b8 XCTestCore`__26-[XCTestCase performTest:]_block_invoke.396 + 43
    frame #17: 0x0000000106213f33 XCTestCore`-[XCTestCase(XCTIssueHandling) _caughtUnhandledDeveloperExceptionPermittingControlFlowInterruptions:caughtInterruptionException:whileExecutingBlock:] + 181
    frame #18: 0x000000010624d041 XCTestCore`__26-[XCTestCase performTest:]_block_invoke.375 + 516
    frame #19: 0x00000001062319b6 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 218
    frame #20: 0x000000010624cc65 XCTestCore`-[XCTestCase performTest:] + 287
    frame #21: 0x0000000106201853 XCTestCore`-[XCTest runTest] + 57
    frame #22: 0x0000000106234d12 XCTestCore`-[XCTestSuite runTestBasedOnRepetitionPolicy:testRun:] + 151
    frame #23: 0x0000000106234b92 XCTestCore`__27-[XCTestSuite performTest:]_block_invoke + 243
    frame #24: 0x00000001062344a6 XCTestCore`__59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 24
    frame #25: 0x00000001062319b6 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 218
    frame #26: 0x000000010623445d XCTestCore`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 159
    frame #27: 0x000000010623474f XCTestCore`-[XCTestSuite performTest:] + 219
    frame #28: 0x0000000106201853 XCTestCore`-[XCTest runTest] + 57
    frame #29: 0x0000000106234d12 XCTestCore`-[XCTestSuite runTestBasedOnRepetitionPolicy:testRun:] + 151
    frame #30: 0x0000000106234b92 XCTestCore`__27-[XCTestSuite performTest:]_block_invoke + 243
    frame #31: 0x00000001062344a6 XCTestCore`__59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 24
    frame #32: 0x00000001062319b6 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 218
    frame #33: 0x000000010623445d XCTestCore`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 159
    frame #34: 0x000000010623474f XCTestCore`-[XCTestSuite performTest:] + 219
    frame #35: 0x0000000106201853 XCTestCore`-[XCTest runTest] + 57
    frame #36: 0x0000000106234d12 XCTestCore`-[XCTestSuite runTestBasedOnRepetitionPolicy:testRun:] + 151
    frame #37: 0x0000000106234b92 XCTestCore`__27-[XCTestSuite performTest:]_block_invoke + 243
    frame #38: 0x00000001062344a6 XCTestCore`__59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 24
    frame #39: 0x00000001062319b6 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 218
    frame #40: 0x000000010623445d XCTestCore`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 159
    frame #41: 0x000000010623474f XCTestCore`-[XCTestSuite performTest:] + 219
    frame #42: 0x0000000106201853 XCTestCore`-[XCTest runTest] + 57
    frame #43: 0x0000000106203371 XCTestCore`__89-[XCTTestRunSession executeTestsWithIdentifiers:skippingTestsWithIdentifiers:completion:]_block_invoke + 115
    frame #44: 0x00000001062319b6 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 218
    frame #45: 0x0000000106203259 XCTestCore`-[XCTTestRunSession executeTestsWithIdentifiers:skippingTestsWithIdentifiers:completion:] + 271
    frame #46: 0x000000010626d0da XCTestCore`__72-[XCTExecutionWorker enqueueTestIdentifiersToRun:testIdentifiersToSkip:]_block_invoke_2 + 119
    frame #47: 0x000000010626d200 XCTestCore`-[XCTExecutionWorker runWithError:] + 112
    frame #48: 0x000000010622edf9 XCTestCore`__25-[XCTestDriver _runTests]_block_invoke.322 + 61
    frame #49: 0x000000010620c4a1 XCTestCore`-[XCTestObservationCenter _observeTestExecutionForBlock:] + 307
    frame #50: 0x000000010622ea2c XCTestCore`-[XCTestDriver _runTests] + 1457
    frame #51: 0x0000000106201e39 XCTestCore`_XCTestMain + 125
    frame #52: 0x00000001057734c4 xctest`main + 211
    frame #53: 0x000000010598af21 dyld_sim`start_sim + 10
    frame #54: 0x000000010cf9a51e dyld`start + 462

Here's the sample code that producing this exception:

protocol TestProtocol {
    var item: String { get }
    var closure: () -> Void { get }
}

class SwiftyMockyClosureTest: XCTestCase {
    var mock: TestProtocolMock!

    override func setUp() {
        mock = TestProtocolMock()
        mock.given(.closure(getter: { }))
    }

    override func tearDown() {
        mock.resetMock(.given)
    }

    func testExample() throws {
        mock.closure()
    }
}

The TestProtocol and SwiftyMockyClosureTest are in different targets.
If I change the closure to be mutable and mock the property like this:

mock = {}

It works, but breaks immutability of this property. In my case it's not applicable.
Do you have any idea how to avoid this happening, or it's rather a bug in SwiftyMocky itself?

Thanks, Iuliia

I have also experienced the same issue with SwiftMocky 4.0.1 and Xcode 13.3.1.
In our project we have abstraction as below:

public protocol Proxy: AnyObject {
    var shouldShowBadge: (() -> Bool)? { get set }
}

When accessing closure from Mock dependency in production code there is a crash.
I have managed to find out that changing code inside mock from this:

public var shouldShowBadge: (() -> Bool)? {
    get {    invocations.append(.p_shouldShowBadge_get); return __p_shouldShowBadge ?? optionalGivenGetterValue(.p_shouldShowBadge_get, "ProxyMock - stub value for shouldShowBadge was not defined") }
    set {    invocations.append(.p_shouldShowBadge_set(.value(newValue))); __p_shouldShowBadge = newValue }
}
private var __p_shouldShowBadge: (() -> Bool)?

to this:

public var shouldShowBadge: (() -> Bool)? {
    get {
        invocations.append(.p_shouldShowBadge_get)
        if let __p_shouldShowBadge = __p_shouldShowBadge {
            return __p_shouldShowBadge
        } else {
            return optionalGivenGetterValue(.p_shouldShowBadge_get, "ProxyMock - stub value for shouldShowBadge was not defined") }
        }
    set {    invocations.append(.p_shouldShowBadge_set(.value(newValue))); __p_shouldShowBadge = newValue }
}
private var __p_shouldShowBadge: (() -> Bool)?

solved crash related to memory management. Maybe there is a new compiler optimisation which does not work well with ?? operator in such case.

Looks fixed on Xcode 14.0