Suppose I have a function that allocates memory for the caller:
int func(void **mem1, void **mem2) {
*mem1 = malloc(SIZE);
if (!*mem1) return 1;
*mem2 = malloc(SIZE);
if (!*mem2) {
/* ... */
return 1;
}
return 0;
}
I'd like to hear your feedback on the best way to free() the allocated memory in case the second malloc() fails. You can imagine a more elaborate situation with more error exit points and more allocated memory.
I know people are loathe to use them, but this is the perfect situation for a goto
in C.
int func( void** mem1, void** mem2 )
{
int retval = 0;
*mem1 = malloc(SIZE);
if (!*mem1) {
retval = 1;
goto err;
}
*mem2 = malloc(SIZE);
if (!*mem2) {
retval = 1;
goto err;
}
// ...
goto out;
// ...
err:
if( *mem1 ) free( *mem1 );
if( *mem2 ) free( *mem2 );
out:
return retval;
}
This is a bit controversial, but I think the goto
approach used in Linux kernel actually works pretty well in this situation:
int get_item(item_t* item)
{
void *mem1, *mem2;
int ret=-ENOMEM;
/* allocate memory */
mem1=malloc(...);
if(mem1==NULL) goto mem1_failed;
mem2=malloc(...);
if(mem2==NULL) goto mem2_failed;
/* take a lock */
if(!mutex_lock_interruptible(...)) { /* failed */
ret=-EINTR;
goto lock_failed;
}
/* now, do the useful work */
do_stuff_to_acquire_item(item);
ret=0;
/* cleanup */
mutex_unlock(...);
lock_failed:
free(mem2);
mem2_failed:
free(mem1);
mem1_failed:
return ret;
}
This is where a goto is appropriate, in my opinion. I used to follow the anti-goto dogma, but I changed that when it was pointed out to me that do { ... } while (0); compiles to the same code, but isn't as easy to read. Just follow the some basic rules, like not going backwards with them, keeping them to a minimum, only using them for error conditions, etc...
int func(void **mem1, void **mem2)
{
*mem1 = NULL;
*mem2 = NULL;
*mem1 = malloc(SIZE);
if(!*mem1)
goto err;
*mem2 = malloc(SIZE);
if(!*mem2)
goto err;
return 0;
err:
if(*mem1)
free(*mem1);
if(*mem2)
free(*mem2);
*mem1 = *mem2 = NULL;
return 1;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With