Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Freeing all allocated memory in case of failure

I'm working on a C project (assignment for school). One of the demands is that in case of malloc() failure, the program must free() all allocated memory and exit().

Consider a case where function A() constructs a linked-list and in each iteration it calls to another function, B(). Now, if a malloc failure occured at B(), it must free() the memory it allocated but function A() should do that as well.

Things are getting quite complicated when you have a tree of function calls larger than two.

In my previous project I used a flag to notify a malloc() failure - if a function uses another function which may use malloc(), it has to check the flag right after. It worked, but code got kinda messy.

Is there a neat solution for this problem?
Of course, with "real" applications all memory is de-allocated by the OS, but I guess this demand is pedagogical..

like image 911
eggbaz Avatar asked Oct 29 '25 07:10

eggbaz


2 Answers

I think the easiest approach is to create a custom allocator (as somebody already noted in a deleted post) to keep track of all your allocations, then do a custom deallocator, use these for all your heap memory needs.

if a malloc fails you have the list of previously allocated blocks at easy reach.

e.g. (you need to redo this cause it is not effective and should be optimized but shows the principle and only ocular compilation)

typedef struct
{
  void* pMemory; /* for the allocated memory */
  size_t size;   /* for better debugging */

} MemoryBlock;

#define MAXBLOCKS 1000

MemoryBlock myheap[MAXBLOCKS]; // global so zero:ed
static int block = 0;

void* myalloc(size_t size)
{
   static int block = 0;

   // you should check vs MAXBLOCKS 

   myheap[block].pMemory = malloc(size); 
   myheap[block].size = size;   

   // check if it failed.
   if ( myheap[block].pMemory == NULL )
   {
      for (int i = 0; i < block; ++i)
      {
         myfree(myheap[i].pMemory);
      }
      fprintf( stderr, "out of memory\n");
      exit(EXIT_FAILURE);
   }
   else
   {
     return myheap[block++].pMemory;
   }
}

void myfree(void* p)
{
   for (int i = 0; i < block; ++i)
   {
      if ( p == myheap[i].pMemory )
      {
         free(myheap[i].pMemory);
         myheap[i].pMemory = NULL;
         return; 
      }
   }
}
like image 130
AndersK Avatar answered Oct 31 '25 00:10

AndersK


Yes. The best (and conventional) way is to initialize every pointer value to zero. Then set it during the malloc() assignment. Ex: myPtr = malloc( 10 );

It will be zero in case of failure, and you check that. And finally, when you go about freeing, you always check the pointer value before calling free():

if ( myPtr != 0 )
    free( myPtr );

There is no need for an extra flag.

like image 34
donjuedo Avatar answered Oct 30 '25 22:10

donjuedo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!