Reputation: 43
I run a bunch of malloc
s in sequence, and check each time to make sure it was successful. Something like this:
typedef struct {
int *aray;
char *string;
} mystruct;
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(int *));
if (!foo) exit(1);
foo->array = malloc(length * sizeof(int));
if (!foo->array) exit(1);
foo->string = malloc(length * sizeof(char));
if (!foo->string) exit(1);
return foo;
}
So when a malloc
fails, the program exits without freeing the previous ones. What are some techniques to make sure that in case something fails, the program exits safely with all the allocated memory freed?
Upvotes: 2
Views: 113
Reputation: 53016
You can do it this way too, I think it's the cleanest way to do it and I use it very often, but to return from a function, not to exit from the program since it is true that system will free memory at exit.
By the way your program as is will give segmentation fault, since you are not allocating enough space for foo
.
typedef struct {
int *aray;
char *string;
} mystruct;
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(mystruct)); // you need to allocate space for string too
if (!foo)
return NULL;
memset(foo, 0, sizeof(mystruct)); // initialize all members to NULL
foo->array = malloc(length * sizeof(int));
if (!foo->array)
goto abort;
foo->string = malloc(length * sizeof(char));
if (!foo->string)
goto abort;
return foo;
abort:
if (foo->array)
free(foo->array);
if (foo->string)
free(foo->string);
return NULL;
}
now in the calling function you can do it cleanly like
mystruct *foo;
foo = mystruct_init(length /* assuming this is declared and set. */);
if (!foo)
exit(1);
Upvotes: 0
Reputation: 809
If you're designing a driver that runs as part of the OS, you'll need to take care of this more carefully. In this case, goto
is often used. For example
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(int *));
if (!foo) goto FOO_FAIL;
foo->array = malloc(length * sizeof(int));
if (!foo->array) goto ARRAY_FAIL;
foo->string = malloc(length * sizeof(char));
if (!foo->string) goto STRING_FAIL;
return foo;
STRING_FAIL:
free(foo->array);
ARRAY_FAIL:
free(foo);
FOO_FAIL:
REPORT_ERROR; // user defined behavior
return NULL;
}
So if, say, foo->string
is not allocated successfully, foo->array
and foo
will be freed accordingly. If foo->array
fails, only foo
will be freed. When any of these fails, the function returns NULL, which allows the caller to check the return value and decide next step.
Upvotes: 2
Reputation: 50190
if you want to do post-mortem cleanup then you can register an atexit handler
http://man7.org/linux/man-pages/man3/atexit.3.html
BTW I am not saying its easy to do (or correct)
Upvotes: 1
Reputation: 87311
Most modern operating systems would free the right memory after the process terminates after calling exit(...)
. These operating systems include:
Upvotes: 3
Reputation: 13171
Here's one of my favorite tricks:
do {
a = malloc(...);
if (!a) break;
b = malloc(...);
if (!b) {
free(a);
break;
}
} while (0);
if (!a) {
...
return;
}
...
free(b);
free(a);
Upvotes: 2