Hi all,
I am writing a storage allocator using the First Fit Algorithm and would like to free up memory I have obtained from the system before quitting. So I have this list of 'free' memory which is obtained from the system and remains unused with me. At the end of the program when I try to free the list using the code , my program is crashing, I'm probably doing something silly but just can't figure it out!
Note : I tag every allocation by my allocator in a "tag table" and delete the tag when I free the allocated memory. So If I don't end up with any tags in the table , I must have freed all allocated blocks and hence I don't have memory leaks.
(I have not included the tag table routine nor the main file. )
Any Help is appreciated, Thanks
#include <string.h>
#include "MemRoutines.h"
#include "TagTable.h"
/*
* Alignment is chosen that will be forced on all blocks allocated.
* All allocated blocks will be rounded up to a multiple of this
* size.
*/
#define ALIGNMENT sizeof(double)
/*
* LARGEMEMORY is the minimum chunk of memory block obtained from
* the OS at once.This size is a multiple of ALIGNMENT.my_malloc()
* called with requested byte size greater than LARGEMEMORY will
* fail by design.
*/
#define LARGEMEMORY 4*1024*1024 /*4MB memory obtained from system at once */
/*
* BYTEn is the nth sentinal byte on either side of the space
* allocated to the user.They can be used later on to verify if the
* user has written beyond the allocated space. 0x00000000 should
* stop string operations.
*/
/*
* ------------------------------------------------------
* |Next Free |Size of | User is concerned only about |
* | Memory |Allocated| this portion of memory |
* |Address |Block | and has no knowledge of rest |
* ------------------------------------------------------
* |<------Header------>|^Address Returned to user
* ^-----User Requested Size------^
* ^-------Memory Needed for the Allocation-------------^
*
* " FRAMEWORK OF THE MEMORY MANAGEMENT SCHEME "
*/
/*
* Header is defined assuming double has the strictest memory
* alignment requirement
*/
union header {
struct {
union {
int sign; /*Used when the block is returned by malloc( ) */
union header* next; /*Used when the block is in free list */
}u;
size_t size;/*Size of block including this header*/
}s;
double dummy_align_var;
};
#define SIGN 0xD7E529A2 /* Our magical signature */
/*
* Global Pointer within File scope which points to the start
* of 'free' list
*/
static union header* freelist = NULL;
/*
* The function below will round off the size to a multiple
* of ALIGNMENT Works by setting the last few bits to zero.
* Exploits the fact that ALIGNMENT is a power of 2
*/
static size_t align(size_t size){
return ((size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
}
/*
* The following macros generate the rounded off size for the
* header and the footer.The overhead size is the extra memory
* that needs to be allocated in addition to user's request.
*/
#define HEADER_SIZE align(sizeof(union header))
/*
* Gets at least INITALLOC memory block from the OS.malloc() is
* used instead of actual system calls.
*/
union header* getmemory(size_t n){
union header* BigMem = NULL;
if(( BigMem = malloc( n * sizeof(union header))) == NULL )
return NULL;
BigMem->s.size = n;
BigMem->s.u.next = NULL;
return BigMem;
}
void* my_malloc(char* filename,
unsigned int lineno,
size_t request){
union header* prev = NULL;
union header* p = NULL;
union header* memblock = NULL;
size_t space_required = align( request + HEADER_SIZE );
size_t space_left = 0;
if((signed)request <= 0){
/*add_tag(filename,lineno,NULL,NULL,0);*/
return NULL; /*Bad Request*/
}
/*
* Traverse freelist sequentially until appropriate memory block
* is found is found in the freelist.
*/
p = freelist;
while( p != NULL && p->s.size < space_required ){
prev = p;
p = p->s.u.next;
}
/*
* No appropriate block present to fulfill request - Either this
* is the first call to memory or memory block already in the
* freelist is insuffient to fulfill request.
*/
if ( p == NULL ){
if(( memblock = getmemory(LARGEMEMORY)) == NULL ){
/*add_tag(filename,lineno,NULL,NULL,0);*/
return NULL;
}
/*
* Search the free list to insert this block at appropriate loc
* The list is kept sorted on addresses
*/
prev = NULL;
p = freelist;
while ( p != NULL && p < memblock ){
prev = p;
p = p->s.u.next;
}
memblock->s.u.next = p;/*Connect the block to list*/
/*
* The freelist is empty and the memory block is added as the
* first node in the list.
*/
if( prev == NULL )
freelist = memblock;
/*
* The memory block is added as the last node in the free list
*/
else if ( p == NULL ){
memblock->s.u.next = NULL;
prev->s.u.next = memblock;
}
/*
* The memory block is added somewhere in the middle of the
* free list
*/
else
prev->s.u.next = memblock;
/*
* Now p points to a memory block which is of appropriat size
* This block is then either chopped or passed as it is to the
* user
*/
p = memblock;
}
/*
* Calculate size requirements now
*/
if ( space_required > p->s.size ){
/*add_tag(filename,lineno,NULL,NULL,0);*/
return NULL;
}
space_left = p->s.size - space_required;
if ( space_left >= sizeof(union header) + sizeof(int) ){
/*
* Split the block, keep p in free list and return upper end
* of block.This way the pointers dont need to be saved again.
* Simpler
*/
memblock = (union header *)( (char*)p + space_left );
memblock->s.size = space_required;
memblock->s.u.sign = SIGN;/*Unlink Block*/
p->s.size = space_left;
add_tag(filename, lineno, memblock, memblock + 1, request );
return (void*)( memblock + 1 );
}
/*
* No split, unlink the block and return it to user for use
*/
if ( prev == NULL )
freelist = p->s.u.next;
else
prev->s.u.next = p->s.u.next;
p->s.u.sign = SIGN;
add_tag(filename, lineno, p, p + 1, request );
return (void*)( p + 1 );
}
/*
* Custom calloc , works by simply calling malloc and then sets
* all bytes to zero using memset()
*/
void* my_calloc( char* filename_c,
unsigned int lineno_c,
size_t nobj,
size_t size ){
void* callocp ;
/*
* Each successful allocation will be automatically tagged
*/
if( (callocp = my_malloc(filename_c,lineno_c,nobj * size )) == NULL )
return NULL;
/*Set all bytes to zero*/
memset( callocp, 0, nobj * size );
return callocp;
}
void my_free(char* filename_f,
unsigned int lineno_f,
void* ptr2free){
union header* memblock = NULL;
union header* prev = NULL;
union header* p = NULL;
unsigned int tag_no = 0;
/*
* Freeing a NULL pointer is legal , free() should not do
* anything. Simply return
*/
if( ptr2free == NULL ){
/*fprintf(stderr,"Line %u in %s is trying to free a NULL pointer\n\n",\
lineno_f,filename_f);*/
return ;
}
memblock = (union header*)ptr2free - 1 ;
/*
* My Signature not present and hence the pointer was not
* produced by my_malloc()
*/
if ( memblock->s.u.sign != SIGN ){
/*fprintf(stderr,"Line %u in %s is trying to free a wild pointer\n\n",\
lineno_f,filename_f);*/
return ;
}
/* Find the tag number in the tag table*/
for( tag_no = 0 ; tag_no < TAG_MAX; tag_no++ ){
if( tag_table[tag_no].returned_address == ptr2free )
break;
}
/*
* Search the free list to find an appropriate location to
* insert the memory block
*/
prev = NULL ;
p = freelist;
while( p != NULL && p < (union header*)ptr2free ){
prev = p ;
p = p->s.u.next;
} /*At this point of time , prev < memblock < p */
/*
* If prev == NULL , we must have either of the following two
* cases:
* 1. The Freelist is empty and the node has to be inserted as
* the first node in the free list.
* 2.There is a single node in freelist and the address of the
* memblock is less than the address of the first node , hence
* again this block is inserted as the first node in the list
*/
if( prev == NULL ){
memblock->s.u.next = p;
freelist = prev = memblock;
delete_tag(tag_no);
}
/*
* The memory block starts exactly where the previous block
* ends hence the two blocks are "combined". The size of the
* previous block is simply allowed to grow. There is nothing
* to link here
*/
if( (union header*)(prev + prev->s.size) == memblock ){
prev->s.size += memblock->s.size;
delete_tag(tag_no);
}
/*
* The memory block has to be inserted between the two adjacent
* blocks. Keep track of the 'new prev' as well.
*/
else {
memblock->s.u.next = p;
prev->s.u.next = memblock;
prev = memblock;
delete_tag(tag_no);
}
/*
* Check if the next block is adjacent to the newly added block
*/
if ( p != NULL && ((union header*)(memblock + memblock->s.size) == p) ){
memblock->s.size += p->s.size ;
memblock->s.u.next = p->s.u.next ;
delete_tag(tag_no);
}
/*
* All the my_malloc() calls have been successfully freed,now
* release all memory to the OS before quitting
*/
if( !is_table_initialised() )
freelist_destroy();
return;
}
void freelist_destroy(void)
{
union header* p = freelist;
union header* q = NULL;
if( p == NULL )
return ;
while ( p != NULL ){
q = p->s.u.next ;
free(p);
p = q;
}
return;
}