Potential leak of an object stored into setting username and setting password value - iphone

I am analyzing my application and face Potential leak of an object stored into setting username and setting password value my code is given
-(void) checkRememberPassword{
CFStringRef userNameKey = CFSTR("user_id_preferences");
CFStringRef settingUserName = (CFStringRef)CFPreferencesCopyAppValue(userNameKey, kCFPreferencesCurrentApplication);
CFStringRef passwordKey = CFSTR("password_preferences");
CFStringRef settingPasswordValue = (CFStringRef)CFPreferencesCopyAppValue(passwordKey, kCFPreferencesCurrentApplication);
NSString *tempString = (__bridge NSString *)settingPasswordValue;
NSString *tempString1 = (__bridge NSString *)settingUserName;
if(([tempString1 length] != 0) || ([tempString length] !=0)){
txtUserName.text = (__bridge NSString *)settingUserName;
txtPassword.text = (__bridge NSString *)settingPasswordValue;
[checkBoxButton setImage:[UIImage imageNamed:#"checkbox_full.png"] forState:UIControlStateNormal];
flagForRemPassword = YES;
}
}

The string returned by CFPreferencesCopyAppValue follows the Create rule (https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-103029) in Core Foundation -- you need to call CFRelease when you are finished with it. ARC does not do this for you.

Use CFBridgingRelease to transfer ownership of the object to ARC, instead of a simple C-style cast:
NSString *tempString = (NSString*)CFBridgingRelease(settingPasswordValue);

Related

Memory management in appending a string?

I have an iPhone application in which i am creating an array in the didfinishlaunch in the appdelegate. Like this:
for(int i=1;i<53;i++)
{
NSString *namestring=[NSString stringWithString:#"avatar"];
NSString *string = [NSString stringWithFormat:#"%d",i];
NSString *pngstring=[NSString stringWithString:#".png"];
string = [string stringByAppendingString:pngstring];
namestring = [namestring stringByAppendingString:string];
NSLog(#"%#",namestring);
[avtararray addObject:namestring];
}
working fine.and everywhere i am doing the avatar job with my avatararray in the appdelegate.But in one case when i pop back to the previous view and try to load the string from the array again
NSString *avatarstringt=[[appDelegate.avtararray objectAtIndex:i]description];here it is crashing with a an error
-[CFString description]: message sent to deallocated instance..
when doing the profile job i know that the leak is in the above loop in the appendingstring code.Can anybody help me to remove this?
First of all, Never do this
NSString *string = [NSString stringWithFormat:#"%d",i];
NSString *pngstring=[NSString stringWithString:#".png"];
string = [string stringByAppendingString:pngstring];
The following statements, are redundant
NSString *namestring=[NSString stringWithString:#"avatar"];
NSString *pngstring=[NSString stringWithString:#".png"];
and should be written as:
NSString *namestring=#"avatar";
NSString *pngstring=#".png";
You can use as :
NSString *namestring=#"avatar";
NSString *numberString = [NSString stringWithFormat:#"%d",i];
NSString *pngstring=#"png";
namestring = [namestring stringByAppendingFormat:#"%#.%#",numberString,pngstring];
Even the shortest of code :
for(NSInteger i=1;i<5;i++){
NSString *namestring = [NSString stringWithFormat:#"avatar%#.png",#(i)];
NSLog(#"%#",namestring);
}
As suggested by rmaddy: you can use i as integer, no need of converting it into nsnumber
NSString *namestring = [NSString stringWithFormat:#"avatar%d.png",i];

Memory leak in iphone App when analyzed

I'm getting a memory leak signal like the one shown in
how can i clear this, please help me .
Use (__bridge_transfer NSString *) instead of (__bridge NSString *)
With ARC, you can use __bridge_transfer to transfer memory management of the returned string to ARC
Example:
NSString *myString = [self encodeURL:#"hi*)"];
NSLog(#"%#",myString);
-(NSString *)encodeURL:(NSString *)string{
NSString *newString = #"";
newString = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, CFSTR("^%*)*&%$"),CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
return newString;
}
Try this...
NSString *newString = nil;
CFStringRef stringRef = CFURLCreateStringByAddingPercentEscapes(...);
newString = (NSString *)stringRef;
CFRelease(stringRef);
if(newString)
return newString;
Use
return [newString autorelease];
The NSString object newString is got allocated in the function CFURLCreateStringByAddingPercentEscapes.
so the object attaining the retain count of one at this moment. So when you are retuning the retained object you got memory leak signal. We can add the object newString to the autorelease pool so that the os will take care of the memory to release at the right time.
Hope this helps.

Saving in NSDocumentDirectory uniquely

Hi Im really having a hard time saving in my NSDocumentDirectory.Im using AGImagePickerby the way. Yes I was able to save this in NSDocumentDirectory. But how to save them uniquely ( in terms of their own then converting their names into oneSlotImages) or save them with their unique IDs then load them back. Sorry Im kinda new to this UIImagePickerControllerMediaURL thing., I think that would be my solution to my other problem for not overlaping them when saving. How to save this using their unique ID, or UIImagePickerControllerMediaURL.
for (int i = 0; i < info.count; i++) {
NSLog(#"%#", [info objectAtIndex:i]);
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask ,YES );
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"oneSlotImages%d.png", i]];
ALAssetRepresentation *rep = [[info objectAtIndex: i] defaultRepresentation];
UIImage *image = [UIImage imageWithCGImage:[rep fullResolutionImage]];
//----resize the images
image = [self imageByScalingAndCroppingForSize:image toSize:CGSizeMake(256,256*image.size.height/image.size.width)];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:YES];
Thanks for the help. Much Appreciated.
You could always keep a list of used names and do something like this
int i = 1;
while([listOfUsedNames containsObject:nextAvailableTile]) {
nextAvailableTitle = [kDefaultImageName stringByAppendingFormat:#" %d", i];
i++;
}
// found an unused name
The URL for each image is unique right? So we can make use of this. Convert the URL into MD5 string (which form a unique identifier for each image). And save with that name (like "MD5string.png").
Why can't we use this?
Hope this helps you.
For converting to MD5, please create a file named NSString+MD5.h and put the code
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#interface NSString(MD5)
- (NSString *)MD5;
#end
in it.
Then in the NSString+MD5.m,
#import "NSString+MD5.h"
#implementation NSString(MD5)
- (NSString*)MD5
{
const char *ptr = [self UTF8String];
unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(ptr, strlen(ptr), md5Buffer);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x",md5Buffer[i]];
return output;
}
#end
Import the NSString+MD5.h class where ever you want to use the MD5 function with normal NSString object.
In you code if you have the UIImagePickerControllerMediaURL string, since it is unique for every file you can convert in to MD5 String like
NSString *imgURL = [NSString stringWithString: UIImagePickerControllerMediaURL];
NSString *MD5String = [imgURL MD5];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", MD5String]];
Use that path to save your image file.
On Loading,
Convert the UIImagePickerControllerMediaURL into MD5 and check in the Documents directory for the file
// In this the UIImagePickerControllerMediaURL is the URL of media file to load
NSString *imgURL = [NSString stringWithString: UIImagePickerControllerMediaURL];
NSString *MD5String = [imgURL MD5];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", MD5String]];
Then do the checking with the fileExistsAtPath method of NSFileManager and if exists then load the file from the path. Thats it.
Note: For this you want to keep the UIImagePickerControllerMediaURL of the images you saved in documents directory locally somewhere in your app (In DB or NSUserDefaults) for make use of then at the time of loading.
Try this:
NSMutableString *imageName = [[[NSMutableString alloc] initWithCapacity:0] autorelease];
CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault);
if (theUUID) {
[imageName appendString:NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, theUUID))];
CFRelease(theUUID);
}
[imageName appendString:#".png"];

release CFString

I use this code to get the last name of ABPerson
CFStringRef lastNameRef = ABRecordCopyValue((ABRecordRef)personRecordRef, kABPersonLastNameProperty);
NSString *friendLastName = (NSString*)lastNameRef;
CFRelease(lastNameRef);
it work fine when the value of last name is not equal to NULL
but when the this value is NULL the application crash at the third line because I try to relese NULL
the question is witch is the best way to releasing the CFString in this case without causing the crash of the application
Just use an if to check for NULL.
if (lastNameRef != NULL)
CFRelease(lastNameRef);
CFRelease is old C style code. One should check for NULL before calling CFRelease as also set lastNameRef to NULL after calling CFRelease.
if (lastNameRef != NULL)
{
CFRelease(lastNameRef);
lastNameRef = NULL;
}
CFRelease expects a non-NULL pointer. You could check for that with an if statement, but it is easier to simply release or autorelease friendLastName instead:
CFStringRef lastNameRef = ABRecordCopyValue((ABRecordRef)personRecordRef, kABPersonLastNameProperty);
NSString *friendLastName = (NSString*)lastNameRef;
// use friendLastName
[friendLastName release];
or
CFStringRef lastNameRef = ABRecordCopyValue((ABRecordRef)personRecordRef, kABPersonLastNameProperty);
NSString *friendLastName = (NSString*)lastNameRef;
[friendLastName autorelease];
// use friendLastName
As you don't seem to use lastNameRef, you could also inline that variable:
NSString *friendLastName = (NSString*)ABRecordCopyValue((ABRecordRef)personRecordRef, kABPersonLastNameProperty);
// use friendLastName
[friendLastName release];
or
NSString *friendLastName = (NSString*)ABRecordCopyValue((ABRecordRef)personRecordRef, kABPersonLastNameProperty);
[friendLastName autorelease];
// use friendLastName

EXC_BAD_ACCESS when using string declared in header file

I've declared a string in my header file like so:
#property (nonatomic, retain) NSString *resultOfHash;
I call my getHash method like so:
NSString *hash = [self getHash];
My getHash method is:
-(NSString *) getHash
{
//Get username form Keychain
KeychainItemWrapper *keyChain = [[KeychainItemWrapper alloc] initWithIdentifier:KeyChainName accessGroup:nil];
username = [keyChain objectForKey:(__bridge id)kSecAttrAccount];
//get token from NSUserDefauls
NSString *token = [[NSUserDefaults standardUserDefaults]objectForKey:#"Token"];
NSString *toHash = [[username stringByAppendingString:HashExtra] stringByAppendingString:token];
const char *s = [toHash cStringUsingEncoding:NSASCIIStringEncoding];
NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
CC_SHA512(keyData.bytes, keyData.length, digest);
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
//convert to string
resultOfHash = [out description];
//App crashed out above
// get rid of unwanted characters
resultOfHash = [resultOfHash stringByReplacingOccurrencesOfString:#" " withString:#""];
resultOfHash = [resultOfHash stringByReplacingOccurrencesOfString:#"<" withString:#""];
resultOfHash = [resultOfHash stringByReplacingOccurrencesOfString:#">" withString:#""];
//log to make sure it works
NSLog(#"hash is: %#", resultOfHash);
return resultOfHash;
}
My code crashes out at the line: ResultOfHash = [out description]; but I'm not sure why.
When I use a local variable the conversion works fine but then I cannot return the local variable from the getHash method. Example:
Replace ResultOfHash = [out description];
with
NSString *local = [out description];
return local;
and the conversion works fine and when I debug line by line, the debugger will go to my closing bracket on my method and then produce the EXC_BAD_ACCESS error.
I've tried running NSZombie but that didn't find anything at all.
Any help in trying to sort this out would be greatly appreciated.
Have a look at the answer in this question. Try converting to NSString using
[NSString *local = [[[NSString alloc] initWithData:out encoding:NSASCIIStringEncoding];
I haven't tested this code with this encoding, but it's similar to something I already use.
Update -
I corrected an error in the code above. I somehow left the method signiture out in a distracted copy and paste.
I think the problem is here:
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
CC_SHA512(keyData.bytes, keyData.length, digest);
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
You are using CC_SHA512, but only allocate array of size CC_SHA1_DIGEST_LENGTH, which is smaller and will lead to the buffer overrunning.
To correct this, you should use CC_SHA512_DIGEST_LENGTH instead.
It's crashing because out is unretained. You should add retain:
resultOfHash = [[out description] retain];
or use retained property:
self.resultOfHash = [out description];
Check this, it should be work.
You probably need to use an NSMutableString.