init: large bugged
This commit is contained in:
commit
290a120319
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
bozo
|
||||
bozo.d
|
||||
libmalloc.so
|
||||
build
|
||||
.vscode
|
41
Makefile
Normal file
41
Makefile
Normal file
@ -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)
|
7
include/malloc.h
Normal file
7
include/malloc.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void ft_free(void *ptr);
|
||||
void *ft_malloc(size_t size);
|
||||
void *ft_realloc(void *ptr, size_t size);
|
12
src/align.c
Normal file
12
src/align.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
}
|
7
src/align.h
Normal file
7
src/align.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define ALIGN_MARGING 16
|
||||
|
||||
size_t get_align_increment(void *block);
|
34
src/block.c
Normal file
34
src/block.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
}
|
7
src/block.h
Normal file
7
src/block.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
int add_new_block(chunk_t* chunk, size_t size, void *prev, void *next, bool is_used);
|
51
src/chunk.c
Normal file
51
src/chunk.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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;
|
||||
}
|
37
src/chunk.h
Normal file
37
src/chunk.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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);
|
63
src/chunk_manager.c
Normal file
63
src/chunk_manager.c
Normal file
@ -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);
|
||||
}
|
5
src/chunk_manager.h
Normal file
5
src/chunk_manager.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
void destroy_chunk(chunk_t *chunk);
|
110
src/malloc.c
Normal file
110
src/malloc.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#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);
|
||||
}
|
3
src/malloc.h
Normal file
3
src/malloc.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void* allocs_tree[3] = { 0, 0, 0};
|
29
src/raw_chunk_manager.c
Normal file
29
src/raw_chunk_manager.c
Normal file
@ -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;
|
||||
}
|
4
src/raw_chunk_manager.h
Normal file
4
src/raw_chunk_manager.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
void *raw_get_last_chunk(void **root);
|
||||
void *raw_get_chunk(void **root, void *data_start);
|
7
src/size.h
Normal file
7
src/size.h
Normal file
@ -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
|
50
test/main.c
Normal file
50
test/main.c
Normal file
@ -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 <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user