From 290a120319da421de8c79ba404cb2f353147205b Mon Sep 17 00:00:00 2001 From: starnakin Date: Tue, 30 Jul 2024 09:28:43 +0200 Subject: [PATCH] init: large bugged --- .gitignore | 5 ++ Makefile | 41 +++++++++++++++ include/malloc.h | 7 +++ src/align.c | 12 +++++ src/align.h | 7 +++ src/block.c | 34 +++++++++++++ src/block.h | 7 +++ src/chunk.c | 51 +++++++++++++++++++ src/chunk.h | 37 ++++++++++++++ src/chunk_manager.c | 63 +++++++++++++++++++++++ src/chunk_manager.h | 5 ++ src/malloc.c | 110 ++++++++++++++++++++++++++++++++++++++++ src/malloc.h | 3 ++ src/raw_chunk_manager.c | 29 +++++++++++ src/raw_chunk_manager.h | 4 ++ src/size.h | 7 +++ test/main.c | 50 ++++++++++++++++++ 17 files changed, 472 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 include/malloc.h create mode 100644 src/align.c create mode 100644 src/align.h create mode 100644 src/block.c create mode 100644 src/block.h create mode 100644 src/chunk.c create mode 100644 src/chunk.h create mode 100644 src/chunk_manager.c create mode 100644 src/chunk_manager.h create mode 100644 src/malloc.c create mode 100644 src/malloc.h create mode 100644 src/raw_chunk_manager.c create mode 100644 src/raw_chunk_manager.h create mode 100644 src/size.h create mode 100644 test/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..995e5c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bozo +bozo.d +libmalloc.so +build +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0552cec --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +MAKEFLAGS += -j + +CC := gcc +LD := $(CC) +CFLAGS := -g -O0 -Wall -Wextra -Werror -MMD + +OBJ := $(patsubst src/%.c,build/%.o,$(wildcard src/*.c)) +DEP := $(patsubst %.o,%.d,$(OBJ)) +NAME := libmalloc.so + +all: $(NAME) + +$(NAME): $(OBJ) + @printf 'LD %s\n' "$@" + $(LD) -shared -o $(NAME) $(OBJ) + +build/%.o: src/%.c + @printf 'CC %s\n' "$@" + @mkdir -p $(@D) + @$(CC) $(CFLAGS) -fPIC -c -o $@ $< + +clean: + @printf 'RM build\n' + @rm -rf build/ + +fclean: + @printf 'RM build %s\n' "$(NAME)" + @rm -rf build/ $(NAME) bozo bozo.d + +re: + @make --no-print-directory fclean + @make --no-print-directory all + +test: + @make --no-print-directory all + @$(CC) $(CFLAGS) test/main.c -o bozo -L. -lmalloc + @export LD_LIBRARY_PATH=$(shell pwd) && valgrind ./bozo + +.PHONY: all clean fclean re test + +-include $(DEP) \ No newline at end of file diff --git a/include/malloc.h b/include/malloc.h new file mode 100644 index 0000000..4eecd75 --- /dev/null +++ b/include/malloc.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +void ft_free(void *ptr); +void *ft_malloc(size_t size); +void *ft_realloc(void *ptr, size_t size); \ No newline at end of file diff --git a/src/align.c b/src/align.c new file mode 100644 index 0000000..d49e43e --- /dev/null +++ b/src/align.c @@ -0,0 +1,12 @@ +#include +#include + +#include "align.h" + +size_t get_align_increment(void *block) +{ + size_t gap = ((uintptr_t) block) % ALIGN_MARGING; + if (gap == 0) + return 0; + return ALIGN_MARGING - gap; +} \ No newline at end of file diff --git a/src/align.h b/src/align.h new file mode 100644 index 0000000..0c88cb0 --- /dev/null +++ b/src/align.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#define ALIGN_MARGING 16 + +size_t get_align_increment(void *block); \ No newline at end of file diff --git a/src/block.c b/src/block.c new file mode 100644 index 0000000..2983b01 --- /dev/null +++ b/src/block.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "align.h" +#include "./chunk.h" + +int add_new_block(chunk_t* chunk, size_t size, void *prev, void *next, bool is_used) +{ + static int block_id = 0; + void *new_block; + chunk_t previous_chunk; + + // TODO check with getrlimit() + + new_block = mmap(NULL, size + ALIGN_MARGING + CHUNK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + init_chunk(chunk, size + ALIGN_MARGING - get_align_increment(new_block + CHUNK_SIZE), block_id, prev, new_block, next, is_used); + + if (prev != NULL) + { + chunk_read(prev, &previous_chunk); + previous_chunk.next = chunk->current; + chunk_write(&previous_chunk); + } + + block_id++; + + return 0; +} \ No newline at end of file diff --git a/src/block.h b/src/block.h new file mode 100644 index 0000000..e336612 --- /dev/null +++ b/src/block.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "chunk.h" + +int add_new_block(chunk_t* chunk, size_t size, void *prev, void *next, bool is_used); \ No newline at end of file diff --git a/src/chunk.c b/src/chunk.c new file mode 100644 index 0000000..8ad34e2 --- /dev/null +++ b/src/chunk.c @@ -0,0 +1,51 @@ +#include +#include + +#include "./chunk.h" +#include "./align.h" + +void chunk_write(const chunk_t *chunk) +{ + void **block = chunk->current; + + block[CHUNK_NEXT_POS] = (void*) chunk->next; + block[CHUNK_CURRENT_POS] = (void*) chunk->current; + block[CHUNK_PREV_POS] = (void*) chunk->prev; + block[CHUNK_SIZE_POS] = (void*) chunk->size; + block[CHUNK_IS_USED_POS] = (void*) chunk->is_used; + block[CHUNK_BLOCK_ID_POS] = (void*) chunk->block_id; + block[CHUNK_DATA_START_POS] = chunk->data_start; +} + +void chunk_read(void * const *block, chunk_t *chunk) +{ + chunk->next = block[CHUNK_NEXT_POS]; + chunk->current = block[CHUNK_CURRENT_POS]; + chunk->prev = block[CHUNK_PREV_POS]; + chunk->size = (size_t) block[CHUNK_SIZE_POS]; + chunk->is_used = block[CHUNK_IS_USED_POS]; + chunk->block_id = (long) block[CHUNK_BLOCK_ID_POS]; + chunk->data_start = block[CHUNK_DATA_START_POS]; +} + +void init_chunk(chunk_t *chunk, size_t size, long block_id, void *prev, void *current, void *next, bool is_used) +{ + void *data_start = current + CHUNK_SIZE; + + data_start = data_start + get_align_increment(data_start); + + chunk->is_used = is_used; + chunk->data_start = data_start; + chunk->prev = prev; + chunk->current = current; + chunk->next = next; + chunk->size = size; + chunk->block_id = block_id; + + chunk_write(chunk); +} + +size_t get_physical_size(const chunk_t *chunk) +{ + return chunk->data_start + chunk->size - chunk->current; +} \ No newline at end of file diff --git a/src/chunk.h b/src/chunk.h new file mode 100644 index 0000000..88b1db9 --- /dev/null +++ b/src/chunk.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +typedef struct { + void *next; + void *current; + void *prev; + size_t size; + bool is_used; + long block_id; + void *data_start; +} chunk_t; + +enum { + CHUNK_NEXT_POS, + CHUNK_CURRENT_POS, + CHUNK_PREV_POS, + CHUNK_SIZE_POS, + CHUNK_IS_USED_POS, + CHUNK_BLOCK_ID_POS, + CHUNK_DATA_START_POS, + + CHUNK_SIZE +}; + +enum { + TINY, + SMALL, + LARGE +}; + +void chunk_read(void * const *block, chunk_t *chunk); +void chunk_write(const chunk_t *chunk); +void init_chunk(chunk_t *chunk, size_t size, long block_id, void *prev, void *current, void *next, bool is_used); +size_t get_physical_size(const chunk_t *chunk); \ No newline at end of file diff --git a/src/chunk_manager.c b/src/chunk_manager.c new file mode 100644 index 0000000..13df225 --- /dev/null +++ b/src/chunk_manager.c @@ -0,0 +1,63 @@ +#include "chunk.h" +#include "align.h" + +int get_unused_chunk(chunk_t *root, size_t size, chunk_t *result) +{ + void** current = root->current; + + while (current != NULL) + { + if ((bool) current[CHUNK_IS_USED_POS] == true) + continue; + if ((size_t) current[CHUNK_SIZE_POS] >= size) + { + chunk_read(current, result); + return 0; + } + current = current[CHUNK_NEXT_POS]; + } + return 1; +} + +void chunk_merge(chunk_t *first, chunk_t *second) +{ + //if (first->block_id != second->block_id) + + first->size = first->size + second->size + CHUNK_SIZE + ALIGN_MARGING - get_align_increment(first->next); + first->next = second->next; +} + +int chunk_split(chunk_t *chunk, chunk_t *new_chunk, size_t new_size) +{ + // NOT ENOUGH SIZE TO BE SPLITTED + if (chunk->size + 1 < new_size + CHUNK_SIZE + get_align_increment(chunk->current + CHUNK_SIZE)) + return 1; + + void *new_chunk_pos = chunk->data_start + new_size; + + init_chunk(new_chunk, chunk->size - new_size - CHUNK_SIZE - get_align_increment(new_chunk_pos + CHUNK_SIZE), chunk->block_id, chunk->current, new_chunk_pos, chunk->next, true); + init_chunk(chunk, new_size, chunk->block_id, chunk->prev, chunk->current, new_chunk->current, false); + + return 0; +} + +void destroy_chunk(chunk_t *chunk) +{ + chunk_t chunk_next_to; + + if (chunk->prev != NULL) + { + chunk_read(chunk->prev, &chunk_next_to); + if (chunk_next_to.block_id == chunk->block_id && chunk_next_to.is_used == false) + chunk_merge(&chunk_next_to, chunk); + *chunk = chunk_next_to; + } + if (chunk->next != NULL) + { + chunk_read(chunk->next, &chunk_next_to); + if (chunk_next_to.block_id == chunk->block_id && chunk_next_to.is_used == false) + chunk_merge(chunk, &chunk_next_to); + } + chunk->is_used = false; + chunk_write(chunk); +} \ No newline at end of file diff --git a/src/chunk_manager.h b/src/chunk_manager.h new file mode 100644 index 0000000..7ba5790 --- /dev/null +++ b/src/chunk_manager.h @@ -0,0 +1,5 @@ +#pragma once + +#include "chunk.h" + +void destroy_chunk(chunk_t *chunk); \ No newline at end of file diff --git a/src/malloc.c b/src/malloc.c new file mode 100644 index 0000000..d34ef1d --- /dev/null +++ b/src/malloc.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include + +#include "./size.h" +#include "block.h" +#include "raw_chunk_manager.h" +#include "chunk_manager.h" +#include "malloc.h" + +void *alloc_tiny(size_t size) +{ + (void)size; + return NULL; +} + +void *alloc_small(size_t size) +{ + (void)size; + return NULL; +} + +void *alloc_large(size_t size) +{ + chunk_t new_chunk; + void *first = allocs_tree[LARGE]; + + if (first == NULL) + { + if (add_new_block(&new_chunk, size, NULL, NULL, true)) + return NULL; + allocs_tree[LARGE] = new_chunk.current; + return new_chunk.data_start; + } + + void *last = raw_get_last_chunk(first); + + if (add_new_block(&new_chunk, size, last, NULL, true)) + return NULL; + + return new_chunk.data_start; +} + +void *ft_malloc(size_t size) +{ + if (size < n) + return alloc_tiny(size); + if (size < m) + return alloc_small(size); + return alloc_large(size); + //mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +void free_tiny(chunk_t *chunk) +{ + (void) chunk; +} + +void free_small(chunk_t *chunk) +{ + (void) chunk; +} + +void free_large(chunk_t *chunk) +{ + if (chunk->current == allocs_tree[LARGE]) + allocs_tree[LARGE] = chunk->next; + destroy_chunk(chunk); + munmap(chunk->current, get_physical_size(chunk)); +} + +static void (*free_funcs[3])(chunk_t*) = {free_tiny, free_small, free_large}; + +void ft_free(void *ptr) +{ + void **root; + void *raw_chunk; + chunk_t chunk; + size_t i; + + for (i = TINY; i <= LARGE + 1; i++) + { + if (i > LARGE) + { + // THROW ERROR + write(2, "block not found\n", 16); + } + + root = allocs_tree[i]; + + raw_chunk = raw_get_chunk(root, ptr); + if (raw_chunk == NULL) + continue; + + break; + } + + chunk_read(raw_chunk, &chunk); + + if (chunk.is_used == false) + { + write(2, "double free\n", 12); + // THROW ERROR + } + + // CALL THE RIGHT FREE FUNCTION DEPEND ON SIZE + free_funcs[i](&chunk); +} \ No newline at end of file diff --git a/src/malloc.h b/src/malloc.h new file mode 100644 index 0000000..1f88c81 --- /dev/null +++ b/src/malloc.h @@ -0,0 +1,3 @@ +#pragma once + +void* allocs_tree[3] = { 0, 0, 0}; \ No newline at end of file diff --git a/src/raw_chunk_manager.c b/src/raw_chunk_manager.c new file mode 100644 index 0000000..21bb197 --- /dev/null +++ b/src/raw_chunk_manager.c @@ -0,0 +1,29 @@ +#include "chunk.h" + +void *raw_get_last_chunk(void **root) +{ + void **current = root; + + if (current == NULL) + return NULL; + + while (current[CHUNK_NEXT_POS] != NULL) + current = current[CHUNK_NEXT_POS]; + + return current; +} + +void *raw_get_chunk(void **root, void *data_start) +{ + void**current = root; + + while (current != NULL) + { + if (current[CHUNK_DATA_START_POS] == data_start) + return current; + + current = current[CHUNK_NEXT_POS]; + } + + return NULL; +} \ No newline at end of file diff --git a/src/raw_chunk_manager.h b/src/raw_chunk_manager.h new file mode 100644 index 0000000..fe46795 --- /dev/null +++ b/src/raw_chunk_manager.h @@ -0,0 +1,4 @@ +#pragma once + +void *raw_get_last_chunk(void **root); +void *raw_get_chunk(void **root, void *data_start); \ No newline at end of file diff --git a/src/size.h b/src/size.h new file mode 100644 index 0000000..f1da247 --- /dev/null +++ b/src/size.h @@ -0,0 +1,7 @@ +#pragma once + +#define n 400 // TINY MAX SIZE +#define N n * 100 // TINY MUST BE STORED IN ZONES OF N bytes + +#define m 10000 // SMALL MAX SIZE +#define M m * 100 // SMALL MUST BE STORED IN ZONES OF N bytes \ No newline at end of file diff --git a/test/main.c b/test/main.c new file mode 100644 index 0000000..a7db4cc --- /dev/null +++ b/test/main.c @@ -0,0 +1,50 @@ +#include "../include/malloc.h" +#include "../src/align.h" +#include "../src/malloc.h" +#include "../src/chunk.h" +#include "../src/raw_chunk_manager.h" + +#include + +#define NOT_NULL (void*) 55342301 + +void test(const void* expected_value, const void* value, const char* test_name, const char* description) +{ + printf("%s ", test_name); + if ((expected_value == NOT_NULL && value != NULL) || (expected_value != NOT_NULL && expected_value == value)) + printf("[OK]"); + else + printf("[FAILED] %s {%p != %p}", description, expected_value, value); + printf("\n"); +} + +int main(int ac, char **av) +{ + (void) ac; + (void) av; + + printf("-----------ALIGN-----------\n"); + test(0, (void*) get_align_increment(0), "align test 1", ""); + test((void*) 15, (void*) get_align_increment((void*) 1), "align test 2", ""); + + printf("-----------ALLOC (LARGE)-----------\n"); + void* ptr = ft_malloc(10000000); + ft_free(ptr); + test(NULL, allocs_tree[LARGE], "alloc free", "simple alloc, simple free"); + ptr = ft_malloc(10000000); + test(ptr, ((void **) allocs_tree[LARGE])[CHUNK_DATA_START_POS], "free alloc", "alloc after a free on the first block"); + void *ptr1 = ft_malloc(10000000); + void *ptr2 = ft_malloc(10000000); + void *ptr3 = ft_malloc(10000000); + test(NOT_NULL, raw_get_chunk(allocs_tree[LARGE], ptr1), "alloc first", ""); + test(NOT_NULL, raw_get_chunk(allocs_tree[LARGE], ptr2), "alloc second", ""); + test(NOT_NULL, raw_get_chunk(allocs_tree[LARGE], ptr3), "alloc third", ""); + ft_free(ptr1); + test(NOT_NULL, raw_get_chunk(allocs_tree[LARGE], ptr2), "free disorder1", ""); + ft_free(ptr3); + test(NOT_NULL, raw_get_chunk(allocs_tree[LARGE], ptr2), "free disorder1", ""); + ft_free(ptr2); + test(NULL, allocs_tree[LARGE], "free disorder1", ""); + + return 0; +} \ No newline at end of file