PDA

View Full Version : Debugging EXC_BAD_ACCESS in AsyncSocket




MaxFreud
Jan 7, 2011, 02:44 AM
Hi all,

I'm new to the world of objective-c and cocoa programming, and I'm finding it a bit disorienting right now. So when I wanted to write an app that required wireless communication over wifi (done with Bonjour), I tried my best to find chunks of code that I could reuse.

I'm using AsyncSockets to handle the data transfer details after bonjour introduces my Mac app to the iPhone.

I get an EXC_BAD_ACCESS error in my app, which I've read has to do with memory management. However, my best attempts to find the source of the error (even just WHERE it crashes) have only lead me to think that the error is in AsyncSocket.m. This is unlikely because that code worked for me elsewhere (unless a difference between MacOS and the iOS is causing this). Here is the function:
- (BOOL)setSocketFromStreamsAndReturnError:(NSError **)errPtr
{
// Get the CFSocketNativeHandle from theReadStream
CFSocketNativeHandle native;
CFDataRef nativeProp = CFReadStreamCopyProperty(theReadStream, kCFStreamPropertySocketNativeHandle);
if(nativeProp == NULL)
{
if (errPtr) *errPtr = [self getStreamError];
return NO;
}

CFDataGetBytes(nativeProp, CFRangeMake(0, CFDataGetLength(nativeProp)), (UInt8 *)&native);
CFRelease(nativeProp);

CFSocketRef socket = CFSocketCreateWithNative(kCFAllocatorDefault, native, 0, NULL, NULL);
if(socket == NULL)
{
if (errPtr) *errPtr = [self getSocketError];
return NO;
}

// Determine whether the connection was IPv4 or IPv6
CFDataRef peeraddr = CFSocketCopyPeerAddress(socket);
struct sockaddr *sa = (struct sockaddr *)CFDataGetBytePtr(peeraddr);

if(sa->sa_family == AF_INET)
{
theSocket = socket;
}
else
{
theSocket6 = socket;
}

return YES;
}

The bold line is where the debugger breaks on error. In the debugger window, I see peeraddr's value as 0x0 and summary shows "<invalid CFDataRef>".

I'm reluctant to think that the error comes from this code, because it worked for me before, and it's used by a lot of people. I must be doing something wrong elsewhere but I can't for the life of me figure it out. Any help to help track this down is greatly appreciated.

Sorry if this post is a bit incoherent. I'm writing this late at night after hours of struggling with one annoying bug... we all know what that feels like ;)



PhoneyDeveloper
Jan 7, 2011, 10:07 AM
The author of asyncsocket has a blog. You might want to ask your questions there.

FWIW, that code wasn't developed on iPhone and I also found a bug in it related to IPv6 on iPhone, but it wasn't in the code you show.

MaxFreud
Jan 7, 2011, 03:54 PM
I did, and I'm awaiting their reply.

I poked around more carefully today, and (I think!) I pinpointed the root of the problem:

- (BOOL)setSocketFromStreamsAndReturnError:(NSError **)errPtr
{
// Get the CFSocketNativeHandle from theReadStream
CFSocketNativeHandle native;
CFDataRef nativeProp = CFReadStreamCopyProperty(theReadStream, kCFStreamPropertySocketNativeHandle);
if(nativeProp == NULL)
{
if (errPtr) *errPtr = [self getStreamError];
return NO;
}

CFDataGetBytes(nativeProp, CFRangeMake(0, CFDataGetLength(nativeProp)), (UInt8 *)&native); // native is 0x0 after this
CFRelease(nativeProp);

CFSocketRef socket = CFSocketCreateWithNative(kCFAllocatorDefault, native, 0, NULL, NULL);
if(socket == NULL)
{
if (errPtr) *errPtr = [self getSocketError];
return NO;
}

// Determine whether the connection was IPv4 or IPv6
CFDataRef peeraddr = CFSocketCopyPeerAddress(socket);
struct sockaddr *sa = (struct sockaddr *)CFDataGetBytePtr(peeraddr);

if(sa->sa_family == AF_INET)
{
theSocket = socket;
}
else
{
theSocket6 = socket;
}

return YES;
}

Like I said, my money is still on something external to the AsyncSocket code causing it to behave this way. Any ideas why CFDataGetBytes might produce 0?
From what I can see, it seems like a perfectly legitimate function call and perfectly legitimate variable values getting passed to the function.

PhoneyDeveloper
Jan 7, 2011, 04:24 PM
I think that an NSData can be valid but have a zero length. In that case it returns nil for the data property.

Try inspecting CFDataGetLength(nativeProp))