GithubHelp home page GithubHelp logo

OCMVerify causing EXC_BAD_ACESS about ocmock HOT 17 CLOSED

erikdoe avatar erikdoe commented on August 17, 2024 1
OCMVerify causing EXC_BAD_ACESS

from ocmock.

Comments (17)

skunkworks avatar skunkworks commented on August 17, 2024 1

Just to throw my hat into the ring, I believe I'm seeing the same issue in 3.2. The argument for the invocation, which is an NSString, is not retained by the object being partially mocked. This causes a crash most of the time.

When I retain the argument in a contrived way -- by adding the argument to a mutable array that's retained by the object -- it no longer crashes.

from ocmock.

HiveHicks avatar HiveHicks commented on August 17, 2024

I'm having the same issue when using [OCMArg checkWithBlock:] in OCMVerify(). It doesn't throw though if I first use OCMExpect() and then OCMVerifyAll()

- (void)testThatDoesntThrow
{
    [self.mainContext performBlockAndWait:^{

        GRDocumentVariant *documentVariant = [GRDocumentVariant insertInManagedObjectContext:self.mainContext];

        id documentVC = [OCMArg checkWithBlock:^BOOL(id obj) {
            return [obj isKindOfClass:[GRDocumentVC class]] && [(GRDocumentVC *) obj documentVariant] == documentVariant;
        }];

        OCMExpect([_navigationController pushViewController:documentVC animated:YES]);

        [_mockedVC showDocumentVariant:documentVariant];

        OCMVerifyAll((id)_navigationController);

    }];
}

- (void)testThatThrows_EXC_BAD_ACCESS
{
    [self.mainContext performBlockAndWait:^{

        GRDocumentVariant *documentVariant = [GRDocumentVariant insertInManagedObjectContext:self.mainContext];
        [_mockedVC showDocumentVariant:documentVariant];

        id documentVC = [OCMArg checkWithBlock:^BOOL(id obj) {
            return [obj isKindOfClass:[GRDocumentVC class]] && [(GRDocumentVC *) obj documentVariant] == documentVariant;
        }];

        OCMVerify([_navigationController pushViewController:documentVC animated:YES]);

    }];
}

from ocmock.

leszarna avatar leszarna commented on August 17, 2024

I have similar problem in OCMock code line:
if(([recordedArg isEqual:passedArg] == NO) &&
for :
OCMVerify([_api getObjectWithId:@16]);
Method is stubbed before:
[OCMStub([_api getObjectWithId:[OCMArg any]]) andReturn:someObject];

OCMVerify with [OCMArg any] doesn't cause problem.

from ocmock.

albsala avatar albsala commented on August 17, 2024

+1
Using OCMExpect() and OCMVerifyAll()solved the problem, but I don't know why.

from ocmock.

seaburg avatar seaburg commented on August 17, 2024

Hi!
@leszarna, perhaps it not a bug
Try this:

OCMStub([_api getObjectWithId:@16]).andDo(^(NSInvocation *inv) {
    [inv retainArguments];

    [inv setReturnValue:&someObject];
});

<...>
OCMVerify([_api getObjectWithId:@16]);

@foulkesjohn, you can add to beforeAll:

OCMStub([mockObject methodCalledWithParam:OCMOCK_ANY completionHandler:OCMOCK_ANY]).andDo(^(NSInvocation *inv) {
    [inv retainArguments];
});

from ocmock.

iosdev-republicofapps avatar iosdev-republicofapps commented on August 17, 2024

I am also seeing the same EXC_BAD_ACCESS when I use [OCMArg checkWithBlock:] in OCMVerify(). This happens even if I keep strong references around to the things used in the block.

Something is going on .... Not sure what. Maybe the NSInvocation in OCM should retain is arguments?

from ocmock.

erikdoe avatar erikdoe commented on August 17, 2024

Finally found time to look into this. It seems that despite appearances these are separate issues.

@foulkesjohn Unfortunately, I can't diagnose this from the code you provided. I can only speculate that there is a memory problem somewhere around the return value of [ArrangeInvocation successfulInvocation] but at a minimum I'd have to see the code for that. Also, I'm not a Specta user but it seems that the code wouldn't even compile, particularly the following two lines:

OCMStub([mockObject anotherMethod]);
.andDo(successfulInvocation);

What is this test trying to show? That stubbing one method but calling another makes the verification of the other method fail?

@HiveHicks Only realised now that you probably just made a simple mistake. As far as I am aware you have to add __block to variables that will be accessed from a block. You're just "lucky" that in the first test the omission doesn't cause a problem.

@iosdev-republicofapps OCMock already retains the arguments on the recorded exception in almost all cases. For complicated reasons it can't retain the arguments when the method has at least one char* argument, but the methods discussed in this issue don't seem to have such arguments.

from ocmock.

foulkesjohn avatar foulkesjohn commented on August 17, 2024

The ArrangeInvocation is a helper class for creating the invocation to stub as in my codebase there are a lot of the same stubs happening. The implementation looks something like this:

typedef void (^Invocation)(NSInvocation *);
+ (Invocation)successfulInvocationWithParameter:(id)parameter atIndex:(NSInteger)index
{
  return ^(NSInvocation *invocation) {
    void (^completionHandler)(id, NSError *);
    [invocation getArgument:&completionHandler atIndex:index];
    completionHandler(param, nil);
  };
}

I also couldn't replicate the issue away from my main code base, which is frustrating. The code I provided probably doesn't compile as I put it as more of an example of how I was using it incase I was doing something wrong.

I've taken to just using OCMExpect and OCMVerifyAll which works around the issue, if I get time to look at it again soon I will.

from ocmock.

erikdoe avatar erikdoe commented on August 17, 2024

Looking at this code I think you're running into a know problem with ARC and NSInvocation that isn't specific to OCMock. Have a look at this comment, maybe this helps: #123 (comment)

from ocmock.

foulkesjohn avatar foulkesjohn commented on August 17, 2024

I did try the suggestions in that comment but they didn't seem to help. I think my issue is something with Specta, but it needs more investigation. Thanks for taking time to look into it

from ocmock.

aspyct avatar aspyct commented on August 17, 2024

Just had the same issue (OCMock 3.1.2):

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"mailto:[email protected]"]];

OCMStub([self.delegate secureWebviewShouldOpenMailSheetWithAdress:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) {
    [invocation retainArguments];
});

[self.secureWebView webView:self.webView
                shouldStartLoadWithRequest:request
                            navigationType:UIWebViewNavigationTypeLinkClicked];

OCMVerify([self.delegate secureWebviewShouldOpenMailSheetWithAdress:@"[email protected]"]);

If I remove that [invocation retainArguments], the test randomly succeeds, fails or crashes with EXC_BAD_ACCESS.

from ocmock.

drekka avatar drekka commented on August 17, 2024

Came across this with 3.1.2 and found the solution.

In my code I was calling another class and passing it a mock.

That class create an object and set it on the mock via a setValue: setter.

The class did not keep a reference to the object it just set on the mock so when the thread of execution returned to the test, the created object was released. As OCMock's internal NSInvocation of the setVale: method was not retaining the object, it realloced.

When I then executed a OCMVerify I got an EXEC_BAD_ACCESS.

I found that when I created an internal variable in the class that created the object and set it with the new object so that it was retained independently of the mock object. That everything worked.

Therefore I think that the problem is that OCMock's internal NSInvocations are running with retainArguments as NO (default).

So I'd like a way to be able to turn this on for cases where an argument value passed to a mock is not retained anywhere else in the code.

from ocmock.

hirad avatar hirad commented on August 17, 2024

I believe I'm seeing something similar. This is my code:

id delegateMock = OCMProtocolMock(@protocol(DBFetchedObjectsControllerDelegate));
controller.delegate = delegateMock;
[controller loadObjects];

OCMVerify([delegateMock controller:[OCMArg any] didDetectAdditions:[OCMArg checkWithBlock:^BOOL(NSSet* addedObjects) {
    NSLog(@"Block arg is %@", addedObjects);
    return [addedObjects count] == 5;
}]]);

[controller loadObjects];

The test prints "Block arg is __NSBlockVariable__ ..." before throwing an exception (__NSBlockVariable__ doesn't respond to count). It gets fixed with OCMExpect and OCMVerifyAll.

from ocmock.

sryze avatar sryze commented on August 17, 2024

I'm having a similar problem with OCMVerify and checkWithBlock, the test always crashes with EXC_BAD_ACCESS. I managed to reduce my test code to the following:

#import <AFNetworking.h>
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>

@interface ExampleTests : XCTestCase

@end

@implementation ExampleTests

- (void)sendRequesUsingSessionManager:(AFHTTPSessionManager *)sessionManager {
    NSDictionary *parameters = @{@"param": @"value"};
    [sessionManager POST:@"test" parameters:parameters success:nil failure:nil];
}

- (void)testExample {
    id sessionManagerMock = OCMClassMock([AFHTTPSessionManager class]);
    [self sendRequesUsingSessionManager:sessionManagerMock];
    OCMVerify([sessionManagerMock POST:@"test" parameters:[OCMArg checkWithBlock:^BOOL(NSDictionary *parameters) {
        return YES;
    }] success:[OCMArg any] failure:[OCMArg any]]);
}

@end

When I turn on Enable Zombie Objects in Xcode, test execution breaks with the following message:

*** -[__NSDictionaryI retain]: message sent to deallocated instance 0x7fbd8306f280

It seems that the parameters dictionary is released before it gets passed to the checkWithBlock block.

from ocmock.

davertay avatar davertay commented on August 17, 2024

Like @erikdoe mentioned, I think this is an ARC + NSInvocation issue, but I'm trying to find a workaround and having no luck. This example is contrived but representative of some real world cases we have that are causing the same crash. There is a nested block that needs to be invoked, but invoking it causes EXC_BAD_ACCESS.

@interface SomeTestClient: NSObject
- (void)processTheResponse:(void (^)())responseBlock;
- (void)checkWithCompletion:(void (^)())completion;
@end

@implementation SomeTestClient

- (void)processTheResponse:(void (^)())responseBlock {
    NSLog(@"THIS SHOULD NEVER GET CALLED");
}

- (void)checkWithCompletion:(void (^)())completion {
    [self processTheResponse:^() {
        completion();
    }];
}

@end

@interface MockCrashTestTests : XCTestCase
@end

@implementation MockCrashTestTests

- (void)testNestedBlockCallback {
    SomeTestClient *testClient = OCMPartialMock([SomeTestClient new]);

    OCMExpect([testClient processTheResponse:[OCMArg checkWithBlock:^BOOL (id (^completionBlock)()) {
        completionBlock();  // CRASHES HERE WITH EXC_BAD_ACCESS
        return YES;
    }]]);

    [testClient checkWithCompletion:^() {
        NSLog(@"Actual completionBlock invoked");
    }];

    OCMVerifyAll((id)testClient);
}

@end

from ocmock.

dmaclach avatar dmaclach commented on August 17, 2024

@davertay Pulling an ancient thread out here, but in your case I think the problem is that your "checkWithBlock" is taking a block that returns an id, but the blocks you are passing in do not return an id. If I change your code to

OCMExpect([testClient processTheResponse:[OCMArg checkWithBlock:^BOOL (void (^completionBlock)(void)) {
        completionBlock();  // CRASHES HERE WITH EXC_BAD_ACCESS
        return YES;
    }]]);

the problem goes away.

from ocmock.

erikdoe avatar erikdoe commented on August 17, 2024

Assuming @dmaclach's answer is correct.

from ocmock.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.