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..
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;
}
}
}
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.
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