Curious crash with expectation

Discussion of the OCMock framework. If you have patches we would prefer you to send them to the mailing list, but attaching them to a topic is possible, too.

Curious crash with expectation

Postby scornflake » 26 Aug 2010, 13:39

Compiling on 10.5, without GC (explicitly turned off in OCMock + project).

If I comment out the expectation, the code works.
I'm getting a EXC_BAD_ACCESS upon draining the autorelease pool. Am I using the [mock expect] method correctly here? Should I be constructing the expectation in a different manner?

Neil
---

Code: Select all
- (void)testChangingTextPerformsMetadataUpdate {
   id uploader = [[OCMockObject mockForClass:[SWBUploader class]] retain];

   NSAutoreleasePool *pool = [NSAutoreleasePool new];
   @try {

      SWBMedia *media = [SWBMedia new];
      @try {
         [media setUploader:uploader];
         [media setObjectName:@"myName"];
         [media setMovieDescription:@"Download me"];
         [media setPublished:YES];

         NSDictionary *metadata = [NSDictionary dictionaryWithObjectsAndKeys:
                                   @"The new title", @"title",
                                   @"Download me", @"description", nil];
         [[uploader expect] replaceMetadataFor:@"myName" metadata:metadata];

         // This should initiate a server side update (after 1s)
         [media setTitle:@"The new title"];

         // Wait for a period, for the update to fire
         [NSThread sleepForTimeInterval:2.0];

         [uploader verify];
      } @finally {
         [media cleanUp];
         [media release];
      }
   } @finally {
      NSRunLoop *loop = [NSRunLoop currentRunLoop];
      [loop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
      [pool drain];
   }
}
scornflake
 
Posts: 2
Joined: 26 Aug 2010, 13:32

Re: Curious crash with expectation

Postby erik » 26 Aug 2010, 15:51

This is curious. A wild guess: does it also crash when you drain the pool before yielding to the run loop? Does it crash differently? I'm asking because without knowing how SWBMedia works I'm sceptical that the thread wait actually does what you think it does.

Code: Select all
   } @finally {
      [pool drain];
      NSRunLoop *loop = [NSRunLoop currentRunLoop];
      [loop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
erik
 
Posts: 90
Joined: 10 Oct 2009, 15:22
Location: Hamburg, Germany

Re: Curious crash with expectation

Postby scornflake » 26 Aug 2010, 23:57

Darn, did I leave that run loop in? I did. Didn't mean to. Before posting I took it out, and verified it still dies. Sorry bout that confusion.

The idea behind setTitle: is it's a delayed update to a server on another thread, like so:

Code: Select all
- (void)setTitle:(NSString *)aTitle {
   if(title != aTitle) {
      [title release];
      title = [aTitle copy];
   }
   [self republishState];
}

- (void)setUploader:(SWBUploader *)anUploader {
   if(uploader != anUploader) {
      [uploader release];
      uploader = [anUploader retain];
   }
}

// Very simple method that rebuilds the new metadata for the object, and sends the request to the server on
// another thread
- (void)republishState {
   return;
}


So right now, the method does nothing. It will eventually call a method on the SWBUploader class to replace the server side metadata (and it'll do so on a separate thread...).

The thread wait is in there because the original idea was to delay actual updates to the server by 1s. Allowing a short grace period before the server is hit with the update request. However; that wait can be removed and the crash still occurs.

I've now reduced the method to this:
Code: Select all
- (void)testChangingTextPerformsMetadataUpdate {
   id uploader = [[OCMockObject mockForClass:[SWBUploader class]] retain];

   NSAutoreleasePool *pool = [NSAutoreleasePool new];
   @try {

      SWBMedia *media = [SWBMedia new];
      @try {
         [media setUploader:uploader];

         NSDictionary *metadata = [NSDictionary dictionaryWithObjectsAndKeys:
                                   @"The new title", @"title",
                                   @"Download me", @"description", nil];
         [[uploader expect] replaceMetadataFor:@"myName" metadata:metadata];

         [uploader verify];
      } @finally {
      }
   } @finally {
      [pool drain];
   }
}


And it's coming back with a:

AnotherTestRunner(61124,0xa0673500) malloc: *** mmap(size=2183516160) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Program received signal: “EXC_BAD_ACCESS”.

I'll go do some more digging.
Running out of code to go wrong!


---- 30m later ----

So it turns out that SenTestingKit ain't catching the exception and failing the test (see http://skitch.com/shinywhitebox/du5cp/swbmediatests.m-swbuploader). At least I think that's the case.
Putting in manual exception handling around the [mock verify] method seems to fix it (including if I put the runloop back in).

So ... is it expected that in using OCMock, we have to put manual exception handling around mock verify methods?
scornflake
 
Posts: 2
Joined: 26 Aug 2010, 13:32


Return to OCMock



cron