views:

251

answers:

2

I am getting a strange EXC_BAD_ACCESS error when running my app on iOS4. The app has been pretty solid on OS3.x for some time - not even seeing crash logs in this area of the code (or many at all) in the wild.

I've tracked the error down to this code:

main class:

- (void) sendPost:(PostRequest*)request {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSURLResponse* response;
    NSError* error;
    NSData *serverReply = [NSURLConnection sendSynchronousRequest:request.request returningResponse:&response error:&error];

    ServerResponse* serverResponse=[[ServerResponse alloc] initWithResponse:response error:error data:serverReply]; 

    [request.objectToNotifyWhenDone performSelectorOnMainThread:request.targetToNotifyWhenDone withObject:serverResponse waitUntilDone:YES];

    [pool drain];
}

(Note: sendPost is run on a separate thread for each invocation of it. PostRequest is just a class to encapsulate a request and a selector to notify when complete)

ServerResponse.m:

@synthesize response;
@synthesize replyString;
@synthesize error;
@synthesize plist;

- (ServerResponse*) initWithResponse:(NSURLResponse*)resp error:(NSError*)err data:(NSData*)serverReply {
    self.response=resp;
    self.error=err;
    self.plist=nil;
    self.replyString=nil;

    if (serverReply) {
        self.replyString = [[[NSString alloc] initWithBytes:[serverReply bytes] length:[serverReply length] encoding: NSASCIIStringEncoding] autorelease];
        NSPropertyListFormat format;
        NSString *errorStr;
        plist = [NSPropertyListSerialization propertyListFromData:serverReply mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&errorStr];
    }

    return self;
}

ServerResponse.h:

@property (nonatomic, retain) NSURLResponse* response;
@property (nonatomic, retain) NSString* replyString;
@property (nonatomic, retain) NSError* error;
@property (nonatomic, retain) NSDictionary* plist;

- (ServerResponse*) initWithResponse:(NSURLResponse*)response error:(NSError*)error data:(NSData*)serverReply;

This reliably crashes with a bad access in the line:

self.error=err;

...i.e. in the synthesized property setter!

I'm stumped as to why this should be, given the code worked on the previous OS and hasn't changed since (even the binary compiled with the previous SDK crashes the same way, but not on OS3.0) - and given it is a simple property method.

Any ideas? Could the NSError implementation have changed between releases or am I missing something obvious?

+3  A: 

The setter calls [retain] on the new value, and [release] on the old value. One of those must be invalid (and non-nil) to cause the bad access.

sendPost doesn't initialize it's local error variable and if it is not set by NSURLConnection then it will contain garbage. Try initializing error to nil in sendPost.

progrmr
hmm but error is nil beforehand when I step through it in the debugger. same result whether in the simulator or on the device, too.
frankodwyer
that did the trick (I also initialised the response local variable).I'd expected NSURLConnection to overwrite these - I'm guessing I either got lucky before, and they used to be nil, or the implementation has changed in 4.0 and NSURLConnection releases the old value before setting the out parameters.
frankodwyer
+1  A: 

Do you ever free serverResponse in the sendPost: message?

You init never calls its parent init. Try something like:

- (ServerResponse*) initWithResponse:(NSURLResponse*)resp error:(NSError*)err data:(NSData*)serverReply
{   
    if (self = [super init])
    {
        // ....
    }
    return self;
}
No one in particular
I don't have an init method, the initWithResponse: method is the initialiser. Initialising the local vars seems to fix it (I had expected NSUrlConnection to initialise them - odd that it has worked up until now)And yes the ServerResponse is leaked I think - a separate issue tho.
frankodwyer