/* * Yet Another Malloc * yamalloc.c */ /*---------------------*/ /* Feature test macros */ /*---------------------*/ #define _DEFAULT_SOURCE // for sbrk /*----------*/ /* Includes */ /*----------*/ #include #include #include #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 size) { if (size == 0) { return NULL; } if (heap_start == NULL || heap_end == NULL) { if (!heap_init()) { return NULL; } } intptr_t size_w = block_fit(size); intptr_t *block = block_find(size_w); intptr_t block_size = YA_BLK_SZ(block); if (size_w < block_size) { block_split(block, size_w); } 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 || !YA_BLK_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 size) { intptr_t *block = malloc(size * nmemb); intptr_t block_size = YA_BLK_SZ(block); for (int i = 0; i < block_size - 2; i++) { block[i] = 0; } 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 size) { if (!ptr) { return malloc(size); } if (size == 0) { free(ptr); } intptr_t *block = ptr; if (block < heap_start) { return NULL; // TODO: provoke segfault } intptr_t size_w = block_fit(size); intptr_t block_size = YA_BLK_SZ(block); // segfault if ptr after heap end if (size_w <= block_size) { intptr_t *next = block_split(block, size_w); if (next) { block_join_next(next); // coalesce the leftovers } block_alloc(block); return block; } intptr_t *next = block + block_size; // try to use next free block if (next < heap_end) { intptr_t next_size = YA_BLK_SZ(next); if (!YA_BLK_IS_ALLOC(next) && size_w <= block_size + next_size) { block_join_next(block); // coalesce block_split(block, size_w); // 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(size); for (int i = 0; i < block_size; i++) { new_block[i] = block[i]; } free(block); return new_block; }