Re: -[NSString stringWithCString:encoding:] memory management question
Re: -[NSString stringWithCString:encoding:] memory management question
- Subject: Re: -[NSString stringWithCString:encoding:] memory management question
- From: Jens Miltner <email@hidden>
- Date: Thu, 12 Nov 2009 12:35:45 +0100
Am 11.11.2009 um 20:58 schrieb Hank Heijink (Mailinglists):
Hi all,
I've run into a funny crash when using -[NSString
stringWithCString:encoding:]. The code in question runs in the
iPhone Simulator. I haven't found anything on the web about this,
but I found out some things by experimenting. I have a workaround,
but I'm curious what's going on. I'd be very interested to hear your
thoughts on this - apologies for the lengthy post!
This is the relevant piece of code - I'm sorry I can't post it in
full (NDA prohibits):
nTags = 15;
unsigned long metadataTags[] = { /* fifteen tags defined in some
library */ };
NSMutableDictionary *tempDict = [[NSMutableDictionary alloc]
initWithCapacity:nTags];
for (NSUInteger i = 0; i < nTags; i++) {
unsigned long pcLength = 0;
if (getLengthOfMetaData(fileHandle, metadataTags[i], 0,
&pcLength) != 0) continue;
// pcLength is now the required buffer size.
// Fill the buffer with metadata (and make room for a \0)
unsigned char *pBuffer = malloc(pcLength + 1);
if (getMetadata(fileHandle, metadataTags[i], pBuffer, pcLength) ==
0) {
pBuffer[pcLength] = '\0';
NSString *key = [[NSString alloc] initWithFormat:@"%d",
metadataTags[i]];
NSString *contents = [[NSString alloc] initWithCString:(const
char *)pBuffer encoding:NSASCIIStringEncoding];
[tempDict setValue:contents forKey:key];
[key release];
[contents release];
}
free(pBuffer);
}
_metaData = [[NSDictionary alloc] initWithDictionary:tempDict];
[tempDict release];
The code runs as part of an -init method, and sets the _metaData
instance variable (it's an NSDictionary *) of the class in question.
Most of the time, but not always, the last line ([tempDict release])
crashes with the following stack backtrace (MyApp, MyFile, etc. do
have better names than that):
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000005
Crashed Thread: 0
Application Specific Information:
iPhone Simulator 3.1 (139.1), iPhone OS 3.0 (7A341)
Thread 0 Crashed:
0 CoreFoundation 0x302042c0 CFRelease + 96
1 CoreFoundation 0x30227249
__CFDictionaryDeallocate + 281
2 CoreFoundation 0x30204421 _CFRelease + 241
3 MyApp 0x00004ca0 -[MyFile
getMetaDataFromFileHandle:] + 859 (MyFile.m:247)
4 MyApp 0x000042fd -[MyFile initWithPath:]
+ 382 (MyFile.m:62)
5 MyApp 0x000026b4 -[MyAppDelegate
applicationDidFinishLaunching:] + 407 (MyAppDelegate.m:68)
6 UIKit 0x308f8ac3 -[UIApplication
_performInitializationWithURL:sourceBundleID:] + 500
7 UIKit 0x30901bf5 -[UIApplication
_runWithURL:sourceBundleID:] + 594
8 UIKit 0x308fef33 -[UIApplication
handleEvent:withNewEvent:] + 1532
9 UIKit 0x308fad82 -[UIApplication
sendEvent:] + 71
10 UIKit 0x309013e1
_UIApplicationHandleEvent + 4865
11 GraphicsServices 0x32046375 PurpleEventCallback +
1533
12 CoreFoundation 0x30245560 CFRunLoopRunSpecific
+ 3888
13 CoreFoundation 0x30244628 CFRunLoopRunInMode + 88
14 UIKit 0x308f930d -[UIApplication _run]
+ 611
15 UIKit 0x309021ee UIApplicationMain +
1157
16 MyApp 0x00002324 main + 102 (main.m:13)
17 MyApp 0x00002292 start + 54
Here's what I found:
1. If I use -[NSString initWithUTF8String:], the crash doesn't happen.
2. If I allocate pBuffer only once, outside of the loop, the crash
doesn't happen.
3. If I print out the memory ranges that pBuffer occupies, it seems
that the crash happens when one allocation of pBuffer overlaps
another one. If they start at the same address, it's no problem, but
if they start at different addresses and overlap, it's a problem.
This is why the app doesn't always crash: if the memory ranges don't
happen to overlap, all is well.
So, I'm curious about how -[NSString initWithCString:encoding:]
works. According to the documentation, it returns "An NSString
object initialized using the characters from nullTerminatedCString."
Does that mean it doesn't copy the bytes? Then what does it do? -
[NSString initWithUTF8String] explicitly states that it returns "An
NSString object initialized by copying the bytes from bytes."
I would be concerned about the following bit of documentation for -
[NSString initWithCString:encoding:]:
If nullTerminatedCString is not a NULL-terminated C string, or
encoding does not match the actual encoding, the results are
undefined.
I can't quite understand why the result would be undefined if the
encoding was wrong, but in any case, this means you _might_ get
something other than a valid object or nil, i.e. some garbage pointer,
which could explain the crash...
You could try using -[NSString stringWithBytes:length:encoding:]
instead, which - at least according to the documentation - does not
suffer from this restriction (although I'd assume you may get nil here
or the method may actually raise a runtime exception, so you'd still
need to get the encoding right)...
</jum>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden