New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Capturing NSStackBlock leads to EXC_BAD_ACCESS #85
Comments
I tried to reproduce the problem, but the following code successfully runs (and logs YO):
Are you on iOS, or something else? |
Thanks for taking the time to look into this. I am on iOS and you are right that neither mine nor your example repros the issue. I made a mistake distilling this down from the much more complex test case where I noticed the issue. It turns out this only happens with class mocks. Take the following example that is very similar to yours (it turns doWorkWithCompletion into a class method and uses OCMClassMock/OCMExpect instead of mock/verify).
This crashes for me. |
Reproduced. |
Fixed in 4a40c4a. Turns out the problem was that HCArgumentCaptor needs to copy its arguments, not just retain them. Blocks are kind of funny about how long they live. Thank you for reporting this! |
Now released in v7.1.0 |
OCHamcrest/Source/Library/Object/HCArgumentCaptor.m
Lines 33 to 40 in 11dcba8
Let's say we want to test code like this:
The completion block will be of type NSStackBlock since it is never assigned to a variable. If we try to test this code using a mocked asyncWorker like this:
we run into a EXC_BAD_ACCESS, because the foo's stack has gone out of scope before completion is called and therefore we are accessing the block after it's been released.
NSStackBlocks get copied on the heap lazily (upon first copy). Usually ARC inserts block copy statements automagically across method boundaries. However, it doesn't do so if the method signature specifies a non-block type (which
- (void)capture:(id)item
does).Currently, my workaround is to either in the production code assign the block to a local variable, explicitly call copy before passing, or use NSInvocation in the test code to get the argument from the invocation and manually copy it. Both solutions are not ideal.
Can we add a check for NSStackBlocks in
capture:
and call copy if we are dealing with a NSStackBlock? Or is there another solution?The text was updated successfully, but these errors were encountered: