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 (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to