Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recommended way to handle multiple malloc errors in a single function in C

What is the recommended way to handle multiple malloc errors that might happen sequentially as in the following code?

bool myFunc(int x, int y)
{
    int *pBufX = null;
    int *pBufY = null;

    if((x <= 0) || (y <= 0))
    {
        return false;
    }

    pBufX = (int*)malloc(sizeof(int) * x);
    if(pBufX == null)
    {
        return false; 
    }

    pBufY = (int*)malloc(sizeof(int) * y);
    if(pBufY == null)
    {
        free(pBufX) //free the previously allocated pBufX 
        return false; 
    }

    //do something useful

    free(pBufX);
    free(pBufY);

    return true; 
}

The problem with this approach is that if the number of mallocs are high, you might forget to free some and cause memory leaks. Also, if there is some sort of log that needs outputting when an error occurs, the code becomes very long.

I have seen code that handles these with a goto, where you clear all of the mallocs in one place, only once. The code is not long, but I don't like using gotos.

Is there a better way than either of these two approaches?

Perhaps the problem is with the design in the first place. Is there a rule of thumb when designing functions when it comes to minimizing multiple mallocs?

Edit: There is another way that I have seen and used. Instead of using goto, you keep a status of the program and proceed only if the status is OK. Similar to goto but not using goto. But that increases the number of if statements which might make the code run slower.

bool myFunc(int x, int y)
{
    int *pBufX = null;
    int *pBufY = null;
    bool bRet  = true;

    if((x <= 0) || (y <= 0))
    {
        return false;
    }

    pBufX = (int*)malloc(sizeof(int) * x);
    if(pBufX == null)
    {
       bRet = false; 
    }

    if(bRet == true)
    {
        pBufY = (int*)malloc(sizeof(int) * y);
        if(pBufY == null)
        {
            bRet = false;
        } 
    }

    //do something useful

    if(pBufX != null)
        free(pBufX);

    if(pBufY != null)    
        free(pBufY);

    return bRet; 
}
like image 717
Anusha Dharmasena Avatar asked Dec 09 '15 06:12

Anusha Dharmasena


People also ask

How do you deal with malloc failure?

The same way you'd handle any failure without goto statements: avoid using goto statements! Really, what you need to decide is whether your program can continue after a malloc() failure. If it can't, just exit(), hopefully after providing information on why your program is exiting.

How many parameters in calloc() function requires?

The calloc() function does basically the same job as malloc(), except that it takes two parameters—the number of array elements and the size of each element—instead of a single parameter (which is the product of these two values).

What malloc() function returns?

malloc returns a void pointer to the allocated space, or NULL if there's insufficient memory available. To return a pointer to a type other than void , use a type cast on the return value.

What is the scope of malloc in C?

malloc() is a library function that allows C to allocate memory dynamically from the heap. The heap is an area of memory where something is stored. malloc() is part of stdlib. h and to be able to use it you need to use #include <stdlib.


2 Answers

This is a possible solution:

bool myFunc(int x, int y)
{
    int returnvalue = false;

    int *pBufX = NULL;   // << null -> NULL
    int *pBufY = NULL;

    if((x <= 0) || (y <= 0))
    {
        goto fail;
    }

    pBufX = (int*)malloc(sizeof(int) * x);
    if(pBufX == null)
    {
        goto fail; 
    }

    pBufY = (int*)malloc(sizeof(int) * y);
    if(pBufY == null)
    {
        goto fail;
    }

    //do something useful

    returnvalue = true;    

fail:
   free(pBufX);   // <<< free(x) -> free(pBufX)
   free(pBufY);   // <<< free(y) -> free(pBufY)

   return returnvalue;
}

I would not recommed your second ("evil" goto avoiding) solution. It is more complicated that the goto solution.

BTW it is safe to free a null pointer, therefore

if(pBufY != NULL)     // NULL and not null
  free(pBufY);        // not y but pBufY

can be replaced by:

  free(pBufY);
like image 92
Jabberwocky Avatar answered Oct 25 '22 02:10

Jabberwocky


Personally, I prefer using goto. But since it is safe to free(NULL), you can usually do all the allocations up front:

int *a = NULL; 
int *b = NULL;
a = malloc( sizeof *a * x);
b = malloc( sizeof *b * y);
if( a == NULL || b == NULL ) {
    free(a); 
    free(b); 
    return false;
}

If you need the allocated memory to do a computation to get a size for a further allocation, your function is probably sufficiently complex that it should be refactored anyway.

like image 28
William Pursell Avatar answered Oct 25 '22 01:10

William Pursell