Homebrew Quick question about C memory management

mashers

Stubborn ape
OP
Member
Joined
Jun 10, 2015
Messages
3,837
Trophies
0
Age
40
Location
Kongo Jungle
XP
5,074
Country
Hey guys,

Objective C has spoiled me, especially with ARC, so I need to double check something on C memory management. Take the following example:

Code:
typedef struct myStruct {
    u8 * spriteData;
} myStruct;

myStruct myStructArray[16];

void doStuffWithStruct(int i) {
    myStruct aStruct = myStructArray[i];
    u8 * data = malloc(1024);
    doStuffWithData(data);
    aStruct.spriteData = data;
}

int main() {
    doStuffWithStruct(0);
    doStuffWithStruct(0);
}

I'm assuming that the second call to doStuffWithStruct(0) will cause aStruct.spriteData to leak. I'm wondering about two possible solutions.

Solution 1
Code:
typedef struct myStruct {
    u8 * spriteData;
} myStruct;

myStruct myStructArray[16];

void doStuffWithStruct(int i) {
    myStruct aStruct = myStructArray[i];
    u8 * data = malloc(1024);
    doStuffWithData(data);
    aStruct.spriteData = data;

/*
Free data here. This is like retaining properties in Obj-C, 
but I'm concerned aStruct.spriteData will then point to 
NULL or garbage in this instance
*/

    free(data);
}

int main() {
    doStuffWithStruct(0);
    doStuffWithStruct(0);
}

Solution 2
Code:
typedef struct myStruct {
    u8 * spriteData;
} myStruct;

myStruct myStructArray[16];

void doStuffWithStruct(int i) {
    myStruct aStruct = myStructArray[i];

/*
Free data here if it already exists. Is the if statement needed 
to prevent attempting to free NULL if aStruct.spriteData has 
not yet been allocated, or is freeing a NULL pointer ok?
*/
    if (aStruct.spriteData) {
        free(aStruct.spriteData);
    }

    u8 * data = malloc(1024);
    doStuffWithData(data);
    aStruct.spriteData = data;
}

int main() {
    doStuffWithStruct(0);
    doStuffWithStruct(0);
}


So, which, if either, of these will prevent a memory leak? Also, do I need to go through and free the memory for all of the myStruct objects in myStructArray before terminating the application, or will that be taken care of for me when the array itself is freed?
 
Last edited by mashers,

TheCruel

Developer
Banned
Joined
Dec 6, 2013
Messages
1,350
Trophies
2
XP
3,130
Country
United States
You should be able to free a null pointer:

The free() function deallocates the memory allocation pointed to by ptr. If ptr is a NULL pointer, no operation is performed.

But never free the pointer if you plan on using the data sometime later.
 

Gocario

GBAFail'd
Member
Joined
Sep 5, 2015
Messages
640
Trophies
0
Location
Bourg Palette
XP
804
Country
France
The first solution will always free the memory within the function (= no leak IF the pointer data wasn't malloced BEFORE).
The second will need a free function further.


Code:
// If ptr is a null pointer, no action occurs.
void free(void*ptr);

Care:
  • Once freed, spriteData will still be pointing to the address returned by the previous malloc. You should set it manually to NULL after the free.
  • If spriteData isn't initialized to NULL, problems might appear within `if (.spriteData)`.
 

mashers

Stubborn ape
OP
Member
Joined
Jun 10, 2015
Messages
3,837
Trophies
0
Age
40
Location
Kongo Jungle
XP
5,074
Country
The first solution will always free the memory within the function (= no leak IF the pointer data wasn't malloced BEFORE).
The second will need a free function further.


Code:
// If ptr is a null pointer, no action occurs.
void free(void*ptr);

Care:
  • Once freed, spriteData will still be pointing to the address returned by the previous malloc. You should set it manually to NULL after the free.
  • If spriteData isn't initialized to NULL, problems might appear within `if (.spriteData)`.
Oh right. So I should do

free(aStruct.spriteData);
aStruct.spriteData = NULL;
 

Gocario

GBAFail'd
Member
Joined
Sep 5, 2015
Messages
640
Trophies
0
Location
Bourg Palette
XP
804
Country
France

sarkwalvein

There's hope for a Xenosaga port.
Member
Joined
Jun 29, 2007
Messages
8,506
Trophies
2
Age
41
Location
Niedersachsen
XP
11,221
Country
Germany
I found that I got lock ups when freeing the pointer if I didn't check it was NULL first. Perhaps free() works differently in ctrulib.
Does your example work?
There are many privilege.
First when you write:
"myStruct aStruct = myStructArray;"
You are creating a copy, not a reference.
That copy and all modifications to it will die within the function.

Oh... I will look for a computer to finish this reply, the phone sucks.
 

Gocario

GBAFail'd
Member
Joined
Sep 5, 2015
Messages
640
Trophies
0
Location
Bourg Palette
XP
804
Country
France

sarkwalvein

There's hope for a Xenosaga port.
Member
Joined
Jun 29, 2007
Messages
8,506
Trophies
2
Age
41
Location
Niedersachsen
XP
11,221
Country
Germany
Oh, okay. I was replying based only in the posted example.
Another thing to mention is that free doesn't make the pointer NULL.
So if somebody wants to "check for NULL" in order to assign memory, it is compulsory to set the pointer to null after free manually:
free(pointer);
pointer=NULL;

So:
if(aStruct->spriteData){
free(aStruct->spriteData);
aStruct->spriteData = 0;
}

** But I see this is already being done in the github also.
 
Last edited by sarkwalvein,

Gocario

GBAFail'd
Member
Joined
Sep 5, 2015
Messages
640
Trophies
0
Location
Bourg Palette
XP
804
Country
France
Oh, okay. I was replying based only in the posted example.
Another thing to mention is that free doesn't make the pointer NULL.
So if somebody wants to "check for NULL" in order to assign memory, it is compulsory to set the pointer to null after free manually:
free(pointer);
pointer=NULL;

So:
if(aStruct->spriteData){
free(aStruct->spriteData);
aStruct->spriteData = 0;
}
As he said:
Oh right. So I should do

free(aStruct.spriteData);
aStruct.spriteData = NULL;
 

mashers

Stubborn ape
OP
Member
Joined
Jun 10, 2015
Messages
3,837
Trophies
0
Age
40
Location
Kongo Jungle
XP
5,074
Country
Heh, you realised which function I was talking about ;) I thought the real function was too complex for this questions so I simplified with an example, but got the referencing wrong in the example!

And yes, I'm setting it to NULL manually now. The gridlauncher is probably so littered with uninitialised variables that it's a miracle it works at all. I've got so used to not having to do this in Obj-C, since everything is initialised to nil, 0 or false automatically when the variable is created.

Is there a static analyser which works with ctrulib? It would be good to run the code through something like clang to check for problems like this.

--------------------- MERGED ---------------------------

Oh and one other question, do I need to go through the array and release any existing objects or will that be taken care of for me?
 

Gocario

GBAFail'd
Member
Joined
Sep 5, 2015
Messages
640
Trophies
0
Location
Bourg Palette
XP
804
Country
France
Is there a static analyser which works with ctrulib? It would be good to run the code through something like clang to check for problems like this.
--------------------- MERGED ---------------------------
Oh and one other question, do I need to go through the array and release any existing objects or will that be taken care of for me?

Analysers? What are they? B-)
> Everytime you use a malloc, a free shall be used.
 

sarkwalvein

There's hope for a Xenosaga port.
Member
Joined
Jun 29, 2007
Messages
8,506
Trophies
2
Age
41
Location
Niedersachsen
XP
11,221
Country
Germany
Oh and one other question, do I need to go through the array and release any existing objects or will that be taken care of for me?
You take care of everything memory related.
If you created an array that contains pointers, and then assigned memory to those pointers, you have to use free for each one of those pointers later on.
 

mashers

Stubborn ape
OP
Member
Joined
Jun 10, 2015
Messages
3,837
Trophies
0
Age
40
Location
Kongo Jungle
XP
5,074
Country
You take care of everything memory related.
If you created an array that contains pointers, and then assigned memory to those pointers, you have to use free for each one of those pointers later on.
Thank you for clarifying. This is different to what I'm used to in Obj-C, even using manual reference counting. Take for example:

Code:
NSString *s1 = [[NSString alloc] initWithString:@"Hello];
NSString *s2 = [[NSString alloc] initWithString:@"World];
NSArray *a = [[NSArray alloc] initWithObjects:s1, s2, nil];

To release everything, all I have to do is call [a release]. This will decrement the retain count of a to 0 causing its dealloc function to be called. [NSArray dealloc] overloads [NSObject dealloc] to iterate through its contents and call release on each object. This causes dealloc to be called on each item within the array, and everything gets deallocated. Of course with ARC you don't have to do anything - just alloc and let the runtime deal with when things get deallocated.

So yeah, long story short, having to loop through an array and manually free anything which might have been allocated feels weird to me (but does make sense).
 

filfat

CTO @ Nordcom Group Inc.
Member
Joined
Nov 24, 2012
Messages
1,261
Trophies
1
Location
Gothenburg, Sweden
Website
www.sweetsideofsweden.com
XP
1,749
Country
Sweden
Thank you for clarifying. This is different to what I'm used to in Obj-C, even using manual reference counting. Take for example:

Code:
NSString *s1 = [[NSString alloc] initWithString:@"Hello];
NSString *s2 = [[NSString alloc] initWithString:@"World];
NSArray *a = [[NSArray alloc] initWithObjects:s1, s2, nil];

To release everything, all I have to do is call [a release]. This will decrement the retain count of a to 0 causing its dealloc function to be called. [NSArray dealloc] overloads [NSObject dealloc] to iterate through its contents and call release on each object. This causes dealloc to be called on each item within the array, and everything gets deallocated. Of course with ARC you don't have to do anything - just alloc and let the runtime deal with when things get deallocated.

So yeah, long story short, having to loop through an array and manually free anything which might have been allocated feels weird to me (but does make sense).

Super OT,
but Objective C looks like someone combined C# with a ini config file :P
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    Veho @ Veho: Thank you based Dinoh.