How do I free() after malloc() when the result of malloc() is returned by the function? - iphone

I have the following instance method (adapted from Listing 3-6 of the Event Handling section in the iPhone Application Programming Guide):
- (CGPoint)originOfTouch:(UITouch *)touch
{
CGPoint *touchOriginPoint = (CGPoint *)CFDictionaryGetValue(touchOriginPoints, touch);
if (touchOriginPoint == NULL)
{
touchOriginPoint = (CGPoint *)malloc(sizeof(CGPoint)); // leaks
CFDictionarySetValue(touchOriginPoints, touch, touchOriginPoint);
*touchOriginPoint = [touch locationInView:touch.view];
}
return *touchOriginPoint;
}
Every once in a while my app leaks 16 Bytes as a result of the call to malloc(). I'm not sure how to return touchOriginPoint while free()ing it as well.

If you do not care a minor performance loss, use an NSMutableDictionary and store the point as an NSValue:
NSValue* touchOriginPointValue = [touchOriginPoints objectForKey:touch];
if (touchOriginPointValue == nil) {
touchOriginPointValue = [NSValue valueWithCGPoint:[touch locationInView:touch.view]];
[touchOriginPoints setObject:touchOriginPointValue forKey:touch];
}
return [touchOriginPointValue CGPointValue];
If you must use the CFDictionary approach, you have to find a place to free those malloc-ed memory when the values are not needed. Therefore, you have to pass the values callbacks when creating the dictionary
static void free_malloced_memory (CFAllocatorRef allocator, const void *value) {
free((void*)value);
}
static const CFDictionaryValueCallBacks values_callbacks = {0, NULL, free_malloced_memory, NULL, NULL};
...
touchOriginPoints = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, & values_callbacks);
...

If you must return the malloc'd value from the function, then you have passed the responsibility for freeing the memory to the calling function, or one of its callers.
Since we can't see the calling functions, we can't diagnose any more.

If you are going to be returning an object that is allocated, then either you need to have the caller free() it, or else you need to be using some kind of garbage collection (so it gets freed automatically).

you don't actually return a pointer, the value is copied to a temp value when it is returned, so you aren't really returning the allocation at all, the problem is that you just aren't freeing it either, you add the allocation to the dictionary and just leave it there?
is there like an EndOfTouch function? where you remove the touch from the dictionary? if there is, call free on your allocation there and you should be fine

Related

iOS - libical / const char * - memory usage

I am using the libical library to parse the iCalendar format and read the information I need out of it. It is working absolutely fine so far, but there is one odd thing concerning ical.
This is my code:
icalcomponent *root = icalparser_parse_string([iCalData cStringUsingEncoding:NSUTF8StringEncoding]);
if (root)
{
icalcomponent *currentEvent = icalcomponent_get_first_component(root, ICAL_VEVENT_COMPONENT);
while (currentEvent)
{
while(currentProperty)
{
icalvalue *value = icalproperty_get_value(currentProperty);
char *icalString = icalvalue_as_ical_string_r(value); //seems to leak
NSString *currentValueAsString = [NSString stringWithCString:icalString
encoding:NSUTF8StringEncoding];
icalvalue_free(value);
//...
//import data
//...
icalString = nil;
currentValueAsString = nil;
icalproperty_free(currentProperty);
currentProperty = icalcomponent_get_next_property(currentEvent, ICAL_ANY_PROPERTY);
} //end while
} //end while
icalcomponent_free(currentEvent);
}
icalcomponent_free(root);
//...
I did use instruments to check my memory usage and were able to find out, that this line seems to leak:
char *icalString = icalvalue_as_ical_string_r(value); //seems to leak
If I'd copy and paste this line 5 or six times my memory usage would grow about 400kb and never get released anymore.
There is no free method for the icalvalue_as_ical_string_r method because it's returning a char *..
Any suggestions how to solve this issue? I would appreciate any help!
EDIT
Taking a look at the apple doc says the following:
To get a C string from a string object, you are recommended to use UTF8String. This returns a const char * using UTF8 string encoding.
const char *cString = [#"Hello, world" UTF8String];
The C string you receive is owned by a temporary object, and will become invalid when automatic deallocation takes place. If you want to get a permanent C string, you must create a buffer and copy the contents of the const char * returned by the method.
But how to release a char * string properly now if using arc?
I tried to add #autorelease {...} in front of my while-loop but without any effort. Still increasing memory usage...
Careful with the statement "no free method...because it's returning a char*"; that is never something you can just assume.
In the absence of documentation you can look at the source code of the library to see what it does; for example:
http://libical.sourcearchive.com/documentation/0.44-2/icalvalue_8c-source.html
Unfortunately this function can do a lot of different things. There are certainly some cases where calling free() on the returned buffer would be right but maybe that hasn't been ensured in every case.
I think it would be best to request a proper deallocation method from the maintainers of the library. They need to clean up their own mess; the icalvalue_as_ical_string_r() function has at least a dozen cases in a switch that might have different deallocation requirements.
icalvalue_as_ical_string_r returns a char * because it has done a malloc() for your result string. If your pointer is non-NULL, you have to free() it after use.

A memory leak in simpleftp

I use simpleFTP to request document information. I detect memory-leak with instrument as below:
And in the call tree I find out where is the memory leak happened:
The method "_parseListData" as below:
- (void)_parseListData
{
NSMutableArray * newEntries;
NSUInteger offset;
// We accumulate the new entries into an array to avoid a) adding items to the
// table one-by-one, and b) repeatedly shuffling the listData buffer around.
newEntries = [NSMutableArray array];
assert(newEntries != nil);
offset = 0;
do {
CFIndex bytesConsumed;
CFDictionaryRef thisEntry;
thisEntry = NULL;
assert(offset <= self.listData.length);
bytesConsumed = CFFTPCreateParsedResourceListing(NULL, &((const uint8_t *) self.listData.bytes) [offset], self.listData.length - offset, &thisEntry);
if (bytesConsumed > 0) {
........
}
I don't know how to fix this problem.
The method "CFFTPCreateParsedResourceListing" is a system method and it create __NSDate (look at the second pic).
This is where the memory-leak happen.
The CFFTPCreateParsedResourceListing function returns a CFDictionary into the thisEntry variable, which presumably contains the NSDate objects.
The code should call CFRelease on thisEntry once it is finished with it:
// once we're done with thisEntry
if (thisEntry) {
CFRelease(thisEntry);
}
Old post, but useful solution. You can find the answer here BlackRaccoon ftp client.
According to the creator the CFFTPCreateParsedResourceListing method retains twice the NSDate, to override the issue add the next code, be aware of the comments here:
FAQ section
"Actually, in WhiteRaccoon, if you list a directory you will leak NSDate's. The function CFFTPCreateParsedResourceListing in Apple's SDK has a leak in it. I've attempted to "patch" this, however it isn't guaranteed to work. For OS 5.1 it does work."
........
if (parsedBytes > 0)
{
if (listingEntity != NULL)
{
//----- July 10, 2012: CFFTPCreateParsedResourceListing had a bug that had the date over retained
//----- in order to fix this, we release it once. However, just as a precaution, we check to see what
//----- the retain count might be (this isn't guaranteed to work).
id date = [(__bridge NSDictionary *) listingEntity objectForKey: (id) kCFFTPResourceModDate];
if (CFGetRetainCount((__bridge CFTypeRef) date) >= 2)
CFRelease((__bridge CFTypeRef) date);
this works for me

Unsolvable memory leak IPhone

I am new to IPhone programming and am I having trouble solving the following memory leak.
while(numDeckCounter < numDecks){
int cardCounter=1;
for (int i =1; i<=52; i++) {
tempCard = [Card new]; //leaks tool says that this is leaking object
if(i>=1 && i<=13)
{
tempCard.suit = CLUBS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard]; //reference count 2
cardCounter++;
}
else if(i>=14 && i<=26)
{
tempCard.suit = DIAMONDS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else if(i>=27 && i<=39)
{
tempCard.suit = HEARTS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else
{
tempCard.suit = SPADES;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
if(cardCounter ==14){
cardCounter=1;
}
[tempCard release]; //this causes an EXC_BAD_ACCESS -reference count should be 1
}
numDeckCounter++;
}
I was under the impression that adding an object to the array would increase its reference count by one, then it would be safe to release the object you just added because it would not be deallocated until the array was released bumping which would then release each object in the array. This is when the object should finally be deallocated.
When I add the [tempCard release]; it crashes my app because it can't access the memory location because it has already been deallocated.
From everything I have read, I think what I said above is true. Someone please correct me if I am wrong. Thanks.
I don't see any leaks in the code you presented. (There are some opportunities to slim it down, though, say by moving the identical operations out of the conditionals).
The Leaks tool output is pretty tricky to read. Is it possible that the Card object is leaking one of it's ivars?
Instead of leaks, run static analysis on your product (Product->Analyze). I think it will flag a different part of your code.
Perhaps try [[Card alloc] init] instead of [Card new]. This is just a guess. However trying the IMO more common method of object creation could be helpful.
Check this out: Use of alloc init instead of new
You could also try removing all the code for adding the Cards to the array. So you'd essentially have:
card = [Card new];
[card release];
This could help you find memory issues associated w/ the array retaining the object perhaps?

how to define a returning NSString function in Objective-C / Xcode using a temporary variable?

I would like to define the following function in Objective-C. I have provided pseudo-code to help illustrate what I'm trying to do.
PSEUDOCODE:
function Foo(param) {
string temp;
if(param == 1) then
temp = "x";
else if(param == 2) then
temp = "y";
else if(param == 3) then
temp = "z";
else
temp = "default";
end if
return temp;
}
For some reason if I do this... the variable who I assign it to results in a "BAD Access" error.
I don't know what the difference between:
static NSstring *xx;
or the non-static:
NSString *xx;
declarations are, and how or why I would want to use one over the other.
I also do not fully understand the initializers of NSString, and how they differ. For example:
[[NSString alloc] initWithString:#"etc etc" ];
or the simple assignment:
var = #""
or even:
var = [NSString stringWithString:#"etc etc"];
Can you give me a hand please?
So far, using the NSString value returned from functions like those listed above, always causes an error.
static NSstring *xx;
That declares a statically allocated variable, much like it does in C.
NSstring *xx;
Inside a method that declares a normal local stack variable, just as it does in C.
As you should be aware, the difference between the two is that the first will keep its value between invocations of the function (and can cause trouble if the function is called from multiple threads).
[[NSString alloc] initWithString:#"etc etc"]
That creates a new NSString object, with the contents etc etc. This may or may not be the same as any other NSString object in your program with the same contents, but you don't have to care. Memory management wise, you own it, so you are responsible for ensuring that you eventually call release or autorelease on it to avoid leaking memory.
#"etc etc"
[NSString stringWithString:#"etc etc"]
Those are basically the same. Both give you an NSString object with the contents etc etc. This may or may not be the same as any other NSString object in your program with the same contents, but you don't have to care. Memory management wise, you do not own it, so you must not call release or autorelease on the object unless you first took ownership by calling retain. Also, since you do not own it, you can use it within your method, pass it as a parameter to other methods, and even use it as the return value from your method, but you may not store it in an ivar or static variable without taking ownership by calling retain or making a copy (with copy).
Also, note that "" and #"" are very different. The first gives you a const char * exactly as it does in C, while the second gives you an NSString object. Your program will crash if you use a const char * where the code expects an NSString object.
You can do it this way:
- (NSString *)functionName:(int)param {
NSString *result = nil;
switch (param) {
case 1:
result = [NSString stringWithString:#"x"];
break;
case 2:
result = [NSString stringWithString:#"y"];
break;
case 3:
result = [NSString stringWithString:#"z"];
break;
default:
result = [NSString stringWithString:#"defaultv"];
break;
}
return result;
}
Post real code, not pseudo code, as it makes it much easier to answer your question in concrete terms.
Given that you indicate that you are quite new to Objective-C, I would suggest starting with the language guide and then moving on to the memory management guide.

Does realloc free the former buffer if it fails?

If realloc fails and returns NULL is the former buffer free'd or it is kept intact? I didn't found that particular piece of information in the man page and I'm quite unsure what to do. If memory is freed then double-free could be risky. If not then the leakage would occur.
No, it does not. That aspect has often annoyed me since you can't just use:
if ((buff = realloc (buff, newsize)) == NULL)
return;
in your code if you want to free the original on failure. Instead you have to do something like:
if ((newbuff = realloc (buff, newsize)) == NULL) {
free (buff);
return;
}
buff = newbuff;
Of course, I understand the rationale behind keeping the original buffer intact on failure but my use case has popped up enough that I generally code my own functions to handle that case, something like:
// Attempt re-allocation. If fail, free old buffer, return NULL.
static void *reallocFreeOnFail (void *oldbuff, size_t sz) {
void *newbuff = realloc (oldbuff, sz);
if (newbuff == NULL) free (oldbuff);
return newbuff;
}
// Attempt re-allocation. If fail, return original buffer.
// Variable ok is set true/false based on success of re-allocation.
static void *reallocLeaveOnFail (void *oldbuff, size_t sz, int *ok) {
void *newbuff = realloc (oldbuff, sz);
if (newbuff == NULL) {
*ok = 0;
return oldbuff;
}
*ok = 1;
return newbuff;
}
The relevant section in the C11 standard states (my italics):
7.20.3.4 The realloc function
If ptr is a null pointer, the realloc function behaves like the malloc function for the
specified size. Otherwise, if ptr does not match a pointer earlier returned by the
calloc, malloc, or realloc function, or if the space has been deallocated by a call
to the free or realloc function, the behavior is undefined. If memory for the new
object cannot be allocated, the old object is not deallocated and its value is unchanged.
realloc() returns a pointer to the newly allocated memory, which is suitably aligned for any kind of variable and may be different from ptr, or NULL if the request fails. If size was equal to 0, either NULL or a pointer suitable to be passed to free() is returned. If realloc() fails the original block is left untouched; it is not freed or moved.
malloc(3) - Linux man page
No. No change of the former buffer is done if realloc() failed.
man realloc(3):
realloc() returns a pointer to the newly allocated memory, which is suitably
aligned for any kind of variable and may be different from ptr, or NULL if the
request fails. If size was equal to 0, either NULL or a pointer suitable to be
passed to free() is returned. If realloc() fails the original block is left
untouched; it is not freed or moved.
No.It won't. Realloc changes increases/decreases the dynamic memory allocated via malloc or calloc. It will return NULL in case realloc fails while increasing memory but it won't change previously allocated memory. As Realloc computes new memory allocation from the base address of previously allocated memory, it does not perform any operation on the memory