commit b65f91b43b90a4ab69e69a40de05eeed50e44fa8 Author: hellerve Date: Thu May 3 18:30:29 2018 +0200 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..eddb654 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +TARGET=malloc +BUILDDIR=bin/ +PREFIX=/usr/local/bin/ +MAIN=malloc.c +override CFLAGS+=-Werror -Wall -g -fPIC -O2 -DNDEBUG -ftrapv -Wfloat-equal -Wundef -Wwrite-strings -Wuninitialized -pedantic -std=c11 + +all: malloc.c + mkdir -p $(BUILDDIR) + $(CC) $(MAIN) -o $(BUILDDIR)$(TARGET) $(CFLAGS) + +install: all + install $(BUILDDIR)$(TARGET) $(PREFIX)$(TARGET) + +uninstall: + rm -rf $(PREFIX)$(TARGET) diff --git a/README.md b/README.md new file mode 100644 index 0000000..4dc2d42 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# malloc + +Programming malloc from scratch, as Dan Luu does in [this +blog post](https://danluu.com/malloc-tutorial/). Ported to `mmap` and OS X, +because `sbrk` is deprecated there. + +Just use your system’s malloc. Seriously. diff --git a/malloc.c b/malloc.c new file mode 100644 index 0000000..f03635b --- /dev/null +++ b/malloc.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +struct block_meta { + size_t size; + struct block_meta* next; + int free; +}; +#define META_SIZE sizeof(struct block_meta) + +void* base = NULL; + +struct block_meta* request_space(struct block_meta* last, size_t size) { + struct block_meta *block; + block = mmap(0, size + META_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, VM_MAKE_TAG(VM_MEMORY_MALLOC), 0); + + if (block == (void*) -1) return NULL; + + if (last) last->next = block; + + block->size = size; + block->next = NULL; + block->free = 0; + return block; +} + +struct block_meta* find_free_block(struct block_meta** last, size_t size) { + struct block_meta* cur = base; + while (cur && !(cur->free && cur->size >= size)) { + *last = cur; + cur = cur->next; + } + return cur; +} + +void* malloc(size_t size) { + struct block_meta* b; + + if (size <= 0) return NULL; + + if (!base) { + b = request_space(0, size); + + if (!b) return NULL; + + base = b; + } else { + struct block_meta* l = base; + b = find_free_block(&l, size); + if (!b) { + b = request_space(l, size); + if (!b) return NULL; + } else { + b->free = 0; + } + } + return b+1; +} + +void free(void* ptr) { + if (!ptr) return; + + struct block_meta* b = (struct block_meta*)ptr - 1; + assert(b->free == 0); + b->free = 1; +} + +void* realloc(void* ptr, size_t size) { + if (!ptr) return malloc(size); + + struct block_meta* b = (struct block_meta*)ptr - 1; + if (b->size >= size) return ptr; + + void* new; + new = malloc(size); + if (!new) return NULL; + + memcpy(new, ptr, b->size); + free(ptr); + return new; +} + +void* calloc(size_t n, size_t nsize) { + size_t size = n * nsize; + void *ptr = malloc(size); + if (!ptr) return NULL; + + memset(ptr, 0, size); + return ptr; +} + +int main() { + char* a; + char* b; + char* c; + char* d; + + a = malloc(4); + b = malloc(4); + c = malloc(4); + + a = strcpy(a, "foo"); + + printf("%p\n", (void*)a); + printf("%p\n", (void*)b); + printf("%p\n", (void*)c); + printf("%s\n", a); + + free(b); + + d = malloc(4); + printf("%p\n", (void*)d); + + free(a); + free(c); + free(d); +}