1

Some of our app store users are reporting a crash while searching their address book. I'm pretty lost here cause I can't reproduce this issue.

enter image description here

Is there anything wrong with how I'm querying the address book ? Thanks!!

+ (NSDictionary *) scanAddressBook
{
    #if TARGET_OS_IPHONE
    NSUInteger i;
    CFIndex index;

    ABAddressBookRef addressBook = ABAddressBookCreate();
    NSArray *people = (NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);

    if ( people==nil || (people && ([people count] == 0)))
    {
        TRACE_LOG(@"scanAddressBook ", @"NO ADDRESS BOOK ENTRIES TO SCAN");
        if(people) [people release];
        CFRelease(addressBook);
        return nil;
    }

    NSMutableArray *numbersArray = [NSMutableArray new];
    NSMutableArray *mailsArray = [NSMutableArray new];

    for ( i=0; i<[people count]; i++ )
    {
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

        ABRecordRef person = (ABRecordRef)[people objectAtIndex:i];

        NSMutableDictionary *phoneDictionary = [NSMutableDictionary new];

        CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
        CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);

        NSString* log =[NSString stringWithFormat:@"-----CONTACT ENTRY -> %@ : %@", firstName, lastName ];
        TRACE_LOG(@"scanAddressBook",log);


        NSString *userName = @"NoName";
        if (firstName && lastName)
            userName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
        else if (firstName)
            userName = [NSString stringWithFormat:@"%@", firstName];
        else if (lastName)
            userName = [NSString stringWithFormat:@"%@", lastName];

        if(firstName) CFRelease(firstName);
        if(lastName) CFRelease(lastName);
        //
        // Phone Numbers
        //
        ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
        CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNumbers );

        for ( index=0; index<phoneNumberCount; index++ )
        {
            CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, index);
            CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, index);
            CFStringRef phoneNumberLocalizedLabel = ABAddressBookCopyLocalizedLabel( phoneNumberLabel );    
            // converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
            // Find the ones you want here
            //

            NSString* log =[NSString stringWithFormat:@"-----PHONE ENTRY -> %@ : %@", phoneNumberLocalizedLabel, phoneNumberValue ];
            TRACE_LOG(@"scanAddressBook",log);

            if (![NetworkingUtils validatePhoneNumber:(NSString *)phoneNumberValue]) {
                NSLog(@"invalid phone number: %@",phoneNumberValue);
                CFRelease(phoneNumberLocalizedLabel);
                CFRelease(phoneNumberLabel);
                CFRelease(phoneNumberValue);
                continue;
            }

            [phoneDictionary setObject:(NSString *)phoneNumberValue forKey:InviteUserDataNumberKeyID];
            [phoneDictionary setObject:(NSString *)phoneNumberLocalizedLabel forKey:InviteUserDataNumberTypeKeyID];
            [phoneDictionary setObject:(NSString *)userName forKey:InviteUserDataNameTypeKeyID];

            CFRelease(phoneNumberLocalizedLabel);
            CFRelease(phoneNumberLabel);
            CFRelease(phoneNumberValue);
            NSMutableDictionary *copyPhoneDict = [phoneDictionary copy];
            [numbersArray addObject:copyPhoneDict];
            [copyPhoneDict release];
        }
        CFRelease(phoneNumbers);
        [phoneDictionary release];

        NSMutableDictionary *mailDictionary = [NSMutableDictionary new];
        ABMutableMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
        CFIndex mailsNumberCount = ABMultiValueGetCount( emails );
        for ( index=0; index < mailsNumberCount; index++ )
        {
            CFStringRef emailValue = ABMultiValueCopyValueAtIndex( emails,index);
            // converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
            // Find the ones you want here
            //
            NSString* log =[NSString stringWithFormat:@"-----EMAIL ENTRY -> : %@", emailValue ];
            TRACE_LOG(@"scanAddressBook",log);



            if (![NetworkingUtils validateEmail:(NSString *)emailValue]) {
                NSLog(@"invalid email address: %@",(NSString *)emailValue);
                if (emailValue) {
                    CFRelease(emailValue);
                }
                continue;
            }

            [mailDictionary setObject:(NSString *)emailValue forKey:InviteUserDataMailKeyID];
            [mailDictionary setObject:(NSString *)@"email" forKey:InviteUserDataMailTypeKeyID];
            [mailDictionary setObject:(NSString *)userName forKey:InviteUserDataMailOwnerKeyID];

            if (emailValue) {
                CFRelease(emailValue);
            }

            NSMutableDictionary *copyMailDict = [mailDictionary copy];
            [mailsArray addObject:copyMailDict];
            [copyMailDict release];
        }
        if(emails) CFRelease(emails);
        [mailDictionary release];


        [pool drain];
    }

    NSString *countryCode = [[NSUserDefaults standardUserDefaults] objectForKey:RequestUserCountryCodeKeyID];
    if (!countryCode) {
        NSLocale *locale = [NSLocale currentLocale];
        NSString *aCode = [locale objectForKey: NSLocaleCountryCode];
        countryCode = [[NetworkingUtils codesByCountryCode] objectForKey:aCode];
    }

    NSDictionary *aDictionary = [NSDictionary dictionaryWithObjectsAndKeys: [[numbersArray copy] autorelease], InviteUsersNumbersArrayKeyID, 
                                 [[mailsArray copy] autorelease], InviteUsersMailsArrayKeyID,
                                 countryCode, RequestUserCountryCodeKeyID, nil];

    [numbersArray release];
    [mailsArray release];

    [people release];
    CFRelease(addressBook);

    return aDictionary;
#else 
    return nil ;
#endif
}
Idan
  • 5,717
  • 10
  • 47
  • 84

1 Answers1

3

CFRelease() will crash if you provide a NULL value. I see most of your CFRelease() calls do check for NULL, but not all of them.

Most likely one of these is triggering the crash?

I'm not very familiar with ABAddressBook, so don't know in what situations they would return NULL.

On a related note, Objective-C's -release method does not crash on nil, so you may as well change: if(people) [people release]; to just [people release]; as all methods in Objective-C will silently do nothing if sent to a nil.

Abhi Beckert
  • 32,787
  • 12
  • 83
  • 110