Skip to content
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

malloc error on recursive/chained calls to stubbed method #123

Closed
albsala opened this issue Jul 22, 2014 · 5 comments
Closed

malloc error on recursive/chained calls to stubbed method #123

albsala opened this issue Jul 22, 2014 · 5 comments

Comments

@albsala
Copy link

albsala commented Jul 22, 2014

I'm trying to stub an async method in a partial mock:

id mock = OCMPartialMock([[MyClass alloc] init]);

void (^theBlock)(NSInvocation *) = ^(NSInvocation *invocation) {
    MyObjectWithAction *owa = nil;
    [invocation getArgument:&owa atIndex:3];
    if (owa && owa.action) {
        owa.action();
    }
};
OCMStub([mock myMethodWithParam:[OCMArg any]]).andDo(theBlock);

But inside "action()", I'm calling to "myMethodWithParam:" one more time (but this time with a "MyObjectWithAction" without action).

...and I'm getting:

malloc: *** error for object 0xdd59a20: pointer being freed was not allocated
@albsala
Copy link
Author

albsala commented Jul 22, 2014

I have tried this with the same result:

id mock = OCMPartialMock([[MyClass alloc] init]);

void (^theBlock)(NSInvocation *) = ^(NSInvocation *invocation) {
    MyObjectWithAction *owa = nil;
    [invocation getArgument:&owa atIndex:3];
    if (owa && owa.action) {
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            owa.action();
        });
    }
};
OCMStub([mock myMethodWithParam:[OCMArg any]]).andDo(theBlock);

@erikdoe
Copy link
Owner

erikdoe commented Jul 22, 2014

Could you set a breakpoint on the malloc error and post the result here? In case you haven't done this before: http://stackoverflow.com/questions/14045208/how-to-set-a-breakpoint-in-malloc-error-break-to-debug

@albsala
Copy link
Author

albsala commented Jul 23, 2014

I did it, but all I see is assembly, maybe I'm doing something wrong.

libsystem_malloc.dylib`malloc_error_break:
0x4b3a7f9:  pushl  %ebp
0x4b3a7fa:  movl   %esp, %ebp
0x4b3a7fc:  subl   $0x8, %esp
0x4b3a7ff:  nop    
0x4b3a800:  nopl   (%eax)
0x4b3a804:  addl   $0x8, %esp
0x4b3a807:  popl   %ebp
0x4b3a808:  ret    

I'm starting to think that I am doing something wrong with the mock too. I am mocking a method of "MyClass" and I am testing another one of the same class, using the mock for the call, i mean:

[mock methodIWantToTest];

@carllindberg
Copy link
Contributor

NSInvocation and ARC don't play together very well. It's causing a double-release.

You declared MyObjectWithAction as a local strong variable. However, the value gets assigned by NSInvocation, which takes a "void *" argument, so ARC has no way to know an object came into scope and does not add a retain. However, it will add a release when it goes out of scope. Boom, that's a crash.

Declare the variable as __unsafe_unretained so ARC doesn't touch it. If you want, declare one variable as __unsafe_unretained, use getArgument:atIndex: on that, and then immediately assign to a local (normally declared) variable, which will then have a local strong reference, if you want to guard against deallocation during the block.

@albsala
Copy link
Author

albsala commented Jul 24, 2014

I get it. So it could not be an OCMock problem.
I had to change the way I was testing this class, avoiding the chained calls refactoring it and adding a dependency, so I can not test it now. I guess that was the problem.
Thank you for your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants