for practice I'm currently trying to write my own malloc function in c. So my question is, after some allocation from the heap my program will freeze. I found the code segment which will couse the freeze and it'll freeze when i call the brk sys call. I allready tried to unlock my mutex there but this didn't work. To test it i wrote a permanent loop and allocate memory in an array and freed it randomly.
static list *head = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct list
{
size_t size_;
int free_;
struct list *next_;
struct list *previouse_;
} block;
void blockAdd(block *href, size_t size)
{
href->free_ = FALSE;
href->next_ = NULL;
href->previouse_ = NULL;
if (!head || head > href)
{
if (head)
{
head->previouse_ = href;
}
href->size_ = size + sizeof(block);
href->next_ = head;
head = href;
}
else
{
href->next_ = NULL;
block *current = head;
while (current->next_ && current->next_ < href)
{
current = current->next_;
}
href->size_ = size + sizeof(block);
href->next_ = current->next_;
href->previouse_ = current;
current->next_ = href;
}
}
void *findExactSizeMatch(size_t size)
{
block *href = head;
size_t t = size + sizeof(block);
while (href)
{
if (href->size_ == (size + sizeof(block)) && href->free_)
{
href->free_ = FALSE;
return href;
}
href = href->next_;
}
return NULL;
}
void *findLagerBlock(size_t size)
{
block *href = head;
while (href)
{
if (href->free_ && href->size_ > size)
{
return split(href, size);
}
href = href->next_;
}
return NULL;
}
void *allocateMemory(size_t size)
{
block *new_block = sbrk(BLOCK_SIZE(size));
if (new_block == SBRK_FAILED)
{
exit(1);
}
blockAdd(new_block, size);
return new_block;
}
bool checkAllFree()
{
block *href = head;
while (href)
{
if (!href->free_)
{
return FALSE;
}
href = href->next_;
}
return TRUE;
}
void freeList(block *ptr)
{
if (checkAllFree())
{
if (brk(ptr) == BRK_FAILED)
{
exit(1);
}
head = NULL;
}
}
void merge()
{
block *href = head;
while (href && href->next_)
{
if (href->free_ && href->next_->free_)
{
href->size_ = href->next_->size_;
href->next_ = href->next_->next_;
}
href = href->next_;
}
}
//--------------------------Here it makes some strange things
shrinkHeap()
{
block *href = head;
while (href && href->next_)
{
href = href->next_;
}
if (href && href->free_)
{
if (brk(href) == BRK_FAILED)
{
exit(1);
}
href->previouse_->next_ = href->next_;
}
}
void *malloc(size_t size)
{
if (!size)
{
return NULL;
}
pthread_mutex_lock(&mutex);
block *new_list = NULL;
new_list = findExactSizeMatch(size);
if (new_list)
{
pthread_mutex_unlock(&mutex);
return new_list + sizeof(block);
}
new_list = allocateMemory(size);
pthread_mutex_unlock(&mutex);
return new_list + sizeof(block);
}
void free(void *ptr)
{
if (!ptr || !head)
{
return;
}
pthread_mutex_lock(&mutex);
block *pref = ptr - sizeof(block);
pref->free_ = TRUE;
freeList(pref);
shrinkHeap();
merge();
pthread_mutex_unlock(&mutex);
}
I don't know why, but brk freeze my program.
Thx for your help!
There are multiple problems in your code:
in
blockAdd, you fail to updatehref->next_->previouse_ifhref->next_is notNULLin theelsebranch.findLagerSizeshould be changed tofindLargerSizeand should usesize + sizeof(block)to locate an appropriate block of memory.allocateMemoryis incorrect too: the size passed tosbrkshould includesizeof(block)extra bytes, the block thus allocated should be inserted into the heap and split if it is larger thansize + sizeof(block).in
freeList, in casecheckAllFree()returns true, you should callbrk(head), notbrk(ptr).in
merge, you do not updatehref->sizecorrectly: you should combine the sizes. Furthermore you do not upatehref-_next->previouse_.The prototype for
shrinkHeapshould have a return type and an argument list:In
shrinkHeapyou must update the link before callingbrkas the pointer may become invalid after the call. Furthermore, you must test ifhref->previouse_is notNULLand this update can be simplified as:Your
mallocfunction has a flaw:return new_list + sizeof(block);does not return the pointer to the allocated block, but one much farther away, causing the application to write beyond the end of the allocated block, potentially corrupting the arena. Furthermore, the pointer computed by free does not point to theblock, causing further corruption of the arena even if the program did not write to the memory block and invoking undefined behavior.In both places in
malloc(), you should write this instead:Similarly in
free(), but not necessarily causing an error, you should avoid performing arithmetics onvoidpointers, cast them asunsigned char *for portable code:Or perform the arithmetics after proper typing:
Here is a modified version: