/*
* mm-bump.c – The fastest, least memory-efficient malloc package.
*
* In this naive approach, a block is allocated by simply incrementing
* the brk pointer. Blocks are never coalesced or reused. The size of
* a block is found at the first aligned word before the block (we need
* it for realloc).
*
* This code is correct and blazingly fast, but very bad usage-wise since
* it never frees anything.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include “mm.h”
#include “memlib.h”
/* If you want debugging output, use the following macro. When you hand
* in, remove the #define DEBUG line. */
#define DEBUG
#ifdef DEBUG
# define dbg_printf(…) printf(__VA_ARGS__)
#else
# define dbg_printf(…)
#endif
/* do not change the following! */
#ifdef DRIVER
/* create aliases for driver tests */
#define malloc mm_malloc
#define free mm_free
#define realloc mm_realloc
#define calloc mm_calloc
#endif /* def DRIVER */
#define ALIGNMENT (2 * sizeof(size_t))
typedef struct {
size_t header;
/*
* We don’t know what the size of the payload will be, so we will
* declare it as a zero-length array. This allow us to obtain a
* pointer to the start of the payload.
*/
uint8_t payload[];
} block_t;
static size_t round_up(size_t size, size_t n) {
return (size + n – 1) / n * n;
}
static size_t get_size(block_t *block) {
return block->header & ~0x1;
}
static void set_header(block_t *block, size_t size, bool is_allocated) {
block->header = size | is_allocated;
}
/*
* mm_init – Called when a new trace starts.
*/
int mm_init(void) {
/* Pad heap start so first payload is at ALIGNMENT. */
if ((long) mem_sbrk(ALIGNMENT – offsetof(block_t, payload)) < 0) {
return -1;
}
return 0;
}
/*
* malloc - Allocate a block by incrementing the brk pointer.
* Always allocate a block whose size is a multiple of the alignment.
*/
void *malloc(size_t size) {
size = round_up(sizeof(block_t) + size, ALIGNMENT);
block_t *block = mem_sbrk(size);
if ((long) block < 0) {
return NULL;
}
set_header(block, size, true);
return block->payload;
}
/*
* free – We don’t know how to free a block. So we ignore this call.
* Computers have big memories; surely it won’t be a problem.
*/
void free(void *ptr) {
}
/*
* realloc – Change the size of the block by mallocing a new block,
* copying its data, and freeing the old block.
**/
void *realloc(void *old_ptr, size_t size) {
/* If size == 0 then this is just free, and we return NULL. */
if (size == 0) {
free(old_ptr);
return NULL;
}
/* If old_ptr is NULL, then this is just malloc. */
if (!old_ptr) {
return malloc(size);
}
void *new_ptr = malloc(size);
/* If malloc() fails, the original block is left untouched. */
if (!new_ptr) {
return NULL;
}
/* Copy the old data. */
block_t *block = old_ptr – offsetof(block_t, payload);
size_t old_size = get_size(block);
if (size < old_size) {
old_size = size;
}
memcpy(new_ptr, old_ptr, old_size);
/* Free the old block. */
free(old_ptr);
return new_ptr;
}
/*
* calloc - Allocate the block and set it to zero.
*/
void *calloc(size_t nmemb, size_t size) {
size_t bytes = nmemb * size;
void *new_ptr = malloc(bytes);
/* If malloc() fails, skip zeroing out the memory. */
if (new_ptr) {
memset(new_ptr, 0, bytes);
}
return new_ptr;
}
/*
* mm_checkheap - So simple, it doesn't need a checker!
*/
void mm_checkheap(int verbose) {
}