Yet Another Malloc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

141 lines
3.7 KiB

/*
* Yet Another Malloc
* yamalloc.c
*/
/*---------------------*/
/* Feature test macros */
/*---------------------*/
#define _DEFAULT_SOURCE // for sbrk
/*----------*/
/* Includes */
/*----------*/
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include "yamalloc.h"
#include "ya_debug.h"
#include "ya_block.h"
/*-----------*/
/* Constants */
/*-----------*/
/*--------*/
/* Macros */
/*--------*/
/*--------------------*/
/* Local declarations */
/*--------------------*/
/*----------------------*/
/* Function definitions */
/*----------------------*/
#ifdef YA_DEBUG
/* Print all blocks in the heap */
void ya_print_blocks() {
block_print_range(heap_start, heap_end);
}
#endif
/* Allocates enough memory to store at least size bytes.
* Returns a dword-aligned pointer to the memory or NULL in case of failure. */
void *malloc(size_t n_bytes) {
if (n_bytes == 0) {
return NULL;
}
if (heap_start == NULL || heap_end == NULL) {
if (!heap_init()) {
return NULL;
}
}
intptr_t min_size = block_fit(n_bytes);
intptr_t *block = block_find(min_size);
block_split(block, min_size);
block_alloc(block);
return block;
}
/* Frees the memory block pointed to by ptr, which must have been allocated
* through a call to malloc, calloc or realloc before. Otherwise, undefined
* behavior occurs. */
void free(void *ptr) {
intptr_t *block = ptr;
if (block < heap_start || block > heap_end || !block_is_alloc(block)) {
return; // TODO: provoke segfault
}
block_free(block);
block_join(block);
}
/* Allocates enough memory to store an array of nmemb elements,
* each size bytes large, and clears the memory.
* Returns the pointer to the allocated memory or NULL in case of failure. */
void *calloc(size_t nmemb, size_t n_bytes) {
intptr_t *block = malloc(n_bytes * nmemb);
intptr_t size = block_size(block);
block_clear(block);
return block;
}
/* Resizes the previously allocated memory pointed to by ptr to size.
* If ptr is NULL, it is equivalent to malloc(size).
* If called with size 0, it is equivalent to free(ptr).
* If ptr does not point to memory previously allocated by malloc, calloc or
* realloc, undefined behavior occurs.
* */
void *realloc(void *ptr, size_t n_bytes) {
if (!ptr) {
return malloc(n_bytes);
}
if (n_bytes == 0) {
free(ptr);
}
intptr_t *block = ptr;
if (block < heap_start) {
return NULL; // TODO: provoke segfault
}
intptr_t new_size = block_fit(n_bytes);
intptr_t size = block_size(block); // segfault if ptr after heap end
if (new_size == size) {
return ptr; // don't change anything
}
if (new_size < size) {
intptr_t *next = block_split(block, new_size);
if (next) {
block_join_next(next); // coalesce the leftovers
}
block_alloc(block);
return block;
}
intptr_t *next = block + size;
// try to use next free block
if (next < heap_end) {
intptr_t next_size = block_size(next);
if (!block_is_alloc(next) && new_size <= size + next_size) {
block_join_next(block); // coalesce
block_split(block, new_size); // split if possible
// no need to coalesce
block_alloc(block); // mark block as allocated
return block;
}
}
// resizing failed, so allocate a whole new block and copy
// could handle the case when the block is the last in the heap
// a bit more gracefully and just grow the heap instead of copying
intptr_t *new_block = malloc(n_bytes);
for (int i = 0; i < size; i++) {
new_block[i] = block[i];
}
free(block);
return new_block;
}