Compare commits

..

11 commits

Author SHA1 Message Date
Gu://em_
a09cf2de17 masterclass le dementor 2025-12-19 19:02:50 +01:00
Gu://em_
4f8a0bb720 malloc moi le fion 2025-12-18 18:06:44 +01:00
Guillem George
de0af4715b nul 2025-11-07 23:38:51 +01:00
Guillem George
56636b54c4 backup 2025-11-07 23:30:27 +01:00
Guillem George
a531db5e3a backup 2025-11-07 23:29:21 +01:00
Guillem George
b4f942f678 backup 2025-11-07 20:29:21 +01:00
Guillem George
06fac933c2 tuez-moi 2025-11-06 22:14:56 +01:00
Guillem George
5aba0ff0c3 backup 2025-11-06 19:56:55 +01:00
Guillem George
ed8a843d3d ' 2025-11-05 21:22:34 +01:00
Guillem George
7629201717 ' 2025-11-04 19:13:31 +01:00
Guillem George
ac1b94ebc1 ' 2025-11-04 15:57:00 +01:00
12 changed files with 483 additions and 0 deletions

6
.gitignore vendored
View file

@ -1,3 +1,9 @@
a.out a.out
*~
*.swp
*.o *.o
*.a *.a
*.so
*.class
*.log
*.core

29
malloc/Makefile Normal file
View file

@ -0,0 +1,29 @@
CC=gcc
CFLAGS=-std=c99 -pedantic -Werror -Wall -Wextra -Wvla -fvisibility=hidden -fPIC
CPPFLAGS= -D_DEFAULT_SOURCE
LDFLAGS= -shared -Wl,--no-undefined
LDLIBS=
SRCS=src/malloc.c src/helpers/helpers.c src/helpers/allocate.c
OBJS=${SRCS:.c=.o}
TST_OBJS = tests/test.o
TARGET=libmalloc.so
library: $(OBJS)
$(CC) -o $(TARGET) $^ $(LDFLAGS)
debug: CFLAGS += -g
debug: $(OBJS)
$(CC) -o $(TARGET) $^ $(LDFLAGS)
# test: LDLIBS += -lcriterion
test: CFLAGS = -g -L. -lmalloc -fPIC -fvisibility=hidden
test: library $(TST_OBJS)
$(CC) -o $(TST_TARGET) $^ $(LDLIBS)
check:
dash tests/test-cmd.sh
clean:
$(RM) $(OBJS)
$(RM) $(TARGET)

View file

@ -0,0 +1,94 @@
#include "allocate.h"
#include <string.h>
#include <sys/mman.h>
#include "helpers.h"
// c'est dangereux de pas s'i3lock
// coucou
void *allocate_block(struct bucket *biquette, int block_number)
{
if (block_number == -1)
return NULL;
// Update header
unsigned char byte_mask = 1 << (block_number % 8);
biquette->alloc_blk_cnt++;
biquette->free_map[block_number / 8] |= byte_mask;
// Compute block address
return get_block(biquette, block_number);
}
struct bucket *create_bucket(size_t min_alloc_size)
{
size_t page_alloc_size;
size_t block_alloc_size;
if (min_alloc_size > PAGE_SIZE - sizeof(struct bucket))
{
// Huge page
page_alloc_size = min_alloc_size + sizeof(struct bucket);
block_alloc_size = page_alloc_size;
}
else
{
// Regular page
page_alloc_size = PAGE_SIZE;
block_alloc_size = s2p(min_alloc_size);
}
// Get page
void *page = mmap(NULL, page_alloc_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (page == NULL)
return NULL;
// Init bucket
struct bucket *header = page;
header->block_size = block_alloc_size;
header->alloc_blk_cnt = 0;
header->alloc_size = page_alloc_size;
memset(header->free_map, 0, FREE_LIST_SIZE);
return header;
}
void free_block(void *ptr, struct bucket **list)
{
// Compute header location and block number
struct bucket *header = get_page_begin(ptr);
// Verify that header belongs to list
struct bucket *elt = *list;
int found = 0;
while (elt != NULL)
{
if (elt == header)
{
found = 1;
break;
}
elt = elt->next;
}
if (!found)
return;
// free in map and update size
int block_number = get_block_number(header, ptr);
if (block_number == -1)
return;
unsigned char byte_mask = 1 << ((block_number % 8));
header->free_map[block_number / 8] &= ~byte_mask;
header->alloc_blk_cnt--;
// Huge page
// free bucket if necessary
if (header->alloc_blk_cnt == 0)
{
bucket_list_remove(list, header);
munmap(header, header->alloc_size);
}
}

View file

@ -0,0 +1,13 @@
#ifndef ALLOCATE_H
#define ALLOCATE_H
#include <stddef.h>
#include "helpers.h"
void *allocate_block(struct bucket *biquette, int block_number);
struct bucket *create_bucket(size_t min_alloc_size);
void bucket_append(struct bucket **head, struct bucket *elt);
void free_block(void *ptr, struct bucket **list);
#endif // ! ALLOCATE_H

View file

@ -0,0 +1,170 @@
#include "helpers.h"
// Returns the smallest power of 2 greater or equal to s
size_t s2p(size_t s)
{
// Trick I found on the internet but I don't completely understand it
// Quite amazing
// n--; // 1101 1101 --> 1101 1100
// n |= n >> 1; // 1101 1100 | 0110 1110 = 1111 1110
// n |= n >> 2; // 1111 1110 | 0011 1111 = 1111 1111
// n |= n >> 4; // ...
// n |= n >> 8;
// n |= n >> 16; // 1111 1111 | 1111 1111 = 1111 1111
// n++; // 1111 1111 --> 1 0000 0000
// There is also an x86 assembly instruction to do that in a single cycle:
// lzcnt
// Yeah... This one is definetely wild intel
// Now since asm{} is prohibited in the coding style it won't be useful
// Or maybe there is a builtin to do that ?
// (found __builtin_clzll but not sure of what it does)
// So here's the good old way
size_t n = MIN_BLOCK_SIZE;
while (n < s)
{
n <<= 1;
}
return n;
}
int find_free_block(struct bucket *buck)
{
// Huge pages
if (buck->block_size > BUCKET_SIZE)
{
// Check block 0
if (!(buck->free_map[0] & (1 << 0)))
return 0;
return -1;
}
size_t num_blocks_in_page =
(PAGE_SIZE - sizeof(struct bucket)) / buck->block_size;
size_t maplength = (num_blocks_in_page + 7)
/ 8; // +7 for ceiling division (oui c'est moche mais ça marche)
// Foreach byte
for (unsigned i = 0; i < maplength; i++)
{
unsigned char map_byte = buck->free_map[i];
if (map_byte == 0xFF) // Skip if used
continue;
for (unsigned j = 0; j < 8; j++)
{
if ((i * 8 + j) < num_blocks_in_page
&& !(map_byte & (1 << j))) // Check if free
return i * 8 + j;
}
}
return -1;
}
// Computes the block address based on its position in the freemap
void *get_block(struct bucket *biquette, int block_number)
{
if (block_number == -1)
return NULL;
char *data_begin = get_data_begin(biquette);
return data_begin + (biquette->block_size * (block_number));
}
// Gets block position in the freemap based on its address
int get_block_number(struct bucket *biquette, void *block)
{
if (block == NULL || biquette == NULL)
return -1;
char *block_nul = block;
char *bibiche =
get_data_begin(biquette); // Célèbre bar Capcinois, venez à l'occasion
return (block_nul - bibiche) / biquette->block_size;
// Au revoir mes belles
// Vous manquerez à papa
// (mais fallait marcher, là ça marche pas)
// void *biquetteounette = biquette;
// char *biquette_cherie = biquetteounette;
// return (block_nul - biquette_cherie - sizeof(struct bucket))
// / biquette->block_size;
}
// Gets a bucket with at least a block_size of size
// Returns NULL if nothing was found
struct bucket *get_bucket(struct bucket *head, size_t size)
{
while (head != NULL)
{
if (head->block_size >= size)
return head;
head = head->next;
}
return NULL;
}
// Computes the buckets first block address
void *get_data_begin(struct bucket *biquette)
{
void *maisqueltrucdemerde = biquette;
char *biquettas = maisqueltrucdemerde;
return biquettas + sizeof(struct bucket);
}
// Computes the beginning address of the page containing ptr
void *get_page_begin(void *ptr)
{
size_t quelenfer = ((size_t)ptr) & ~(PAGE_SIZE - 1);
char *pointeur_alacon = NULL;
return pointeur_alacon + quelenfer;
}
// Appends a bucket address to the list pointed by head
void bucket_list_append(struct bucket **head, struct bucket *elt)
{
struct bucket *list_elt = *head;
if (list_elt == NULL)
{
*head = elt;
return;
}
while (list_elt->next != NULL)
{
list_elt = list_elt->next;
}
list_elt->next = elt;
}
// Removes a bucket from the list pointed by head
void bucket_list_remove(struct bucket **head, struct bucket *elt)
{
struct bucket *list_elt = *head;
if (list_elt == NULL)
return;
if (*head == elt)
{
*head = elt->next;
return;
}
while (list_elt->next != NULL)
{
if (list_elt->next == elt)
{
list_elt->next = list_elt->next->next;
return;
}
list_elt = list_elt->next;
}
}

View file

@ -0,0 +1,40 @@
#ifndef HELPERS_H
#define HELPERS_H
// #define PAGE_SIZE sysconf(_SC_PAGE_SIZE)
#define PAGE_SIZE 4096
#define MIN_BLOCK_SIZE 16
#define FREE_LIST_SIZE PAGE_SIZE / MIN_BLOCK_SIZE / sizeof(unsigned char)
#include <stddef.h>
// Header
// Contains all informations about the concerned bucket
struct bucket
{
unsigned block_size;
unsigned char free_map[FREE_LIST_SIZE]; // Keeps track of allocations
// If block_size > MIN_BLOCK_SIZE
// It will use a consecutive
// representation
unsigned short alloc_blk_cnt; // Counts the number of allocated blocks
struct bucket *next;
size_t alloc_size;
unsigned short space1; //
unsigned int space2; // -> Both are used to align data on 16 bytes
};
#define BUCKET_SIZE PAGE_SIZE - sizeof(struct bucket)
size_t s2p(size_t n);
int find_free_block(struct bucket *buck);
struct bucket *get_bucket(struct bucket *head, size_t size);
void *get_data_begin(struct bucket *biquette);
void *get_page_begin(void *ptr);
void *get_block(struct bucket *biquette, int block_number);
int get_block_number(struct bucket *biquette, void *block);
void bucket_list_append(struct bucket **head, struct bucket *elt);
void bucket_list_remove(struct bucket **head, struct bucket *elt);
#endif // ! HELPERS_H

82
malloc/src/malloc.c Normal file
View file

@ -0,0 +1,82 @@
#include <stddef.h>
#include <string.h>
#include "helpers/allocate.h"
#include "helpers/helpers.h"
struct bucket *head = NULL;
__attribute__((visibility("default"))) void *malloc(size_t size)
{
if (size == 0)
return NULL;
// Find adequate bucket
struct bucket *buck = get_bucket(head, size);
while (buck != NULL)
{
// Find adequate block
int block_number = find_free_block(buck);
if (block_number != -1)
return allocate_block(buck, block_number);
else
{
// No free space -> loop
buck = get_bucket(buck->next, size);
}
}
buck = create_bucket(size);
bucket_list_append(&head, buck);
int first_free_buche = find_free_block(buck); // De noel (pas la mienne)
return allocate_block(buck, first_free_buche);
}
__attribute__((visibility("default"))) void free(void *ptr)
{
if (ptr == NULL)
return;
free_block(ptr, &head);
}
__attribute__((visibility("default"))) void *realloc(void *ptr, size_t size)
{
if (size == 0)
return NULL;
if (ptr == NULL)
return malloc(size);
struct bucket *header = get_page_begin(ptr);
if (header == NULL)
return NULL; // Shouldn't get here
if (header->block_size >= size)
{
return ptr;
}
else
{
void *new_ptr = malloc(size);
if (new_ptr == NULL)
return NULL;
memcpy(new_ptr, ptr, header->block_size);
free(ptr);
return new_ptr;
}
return NULL;
}
__attribute__((visibility("default"))) void *calloc(size_t nmemb, size_t size)
{
// Check overflow
size_t c;
if (__builtin_mul_overflow(nmemb, size, &c))
return NULL;
char *res = malloc(c);
if (res == NULL)
return NULL;
memset(res, 0, nmemb * size);
return res;
}

BIN
malloc/tests/corruptionproof Executable file

Binary file not shown.

BIN
malloc/tests/memoryfootprint Executable file

Binary file not shown.

BIN
malloc/tests/speed Executable file

Binary file not shown.

24
malloc/tests/test-cmd.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bi/sh
RED='\033[0;31m'
NC='\033[0m' # No color
echo Hello world!
check()
{
if [ $? -ne 0 ]; then
echo $RED ERROR $NC
fi
}
LD_PRELOAD=./libmalloc.so ls 1> /dev/null
check
LD_PRELOAD=./libmalloc.so ip a 1> /dev/null
check
LD_PRELOAD=./libmalloc.so grep --help 1> /dev/null
check
LD_PRELOAD=./libmalloc.so find 1> /dev/null
check
LD_PRELOAD=./libmalloc.so tree 1> /dev/null
check
LD_PRELOAD=./libmalloc.so git status 1> /dev/null

25
malloc/tests/test.c Normal file
View file

@ -0,0 +1,25 @@
// #include <criterion/criterion.h>
// #include <criterion/new/assert.h>
// TestSuite(Main);
// Test(Main, test1)
// {
// int *i = malloc(16);
// cr_assert(i != NULL);
// }
#include <stdlib.h>
int main(void)
{
int *test = malloc(8);
void *tes2 = malloc(8);
void *tes3 = malloc(32);
void *tes4 = malloc(64);
void *tes5 = malloc(128);
void *tes6 = malloc(256);
void *tes7 = malloc(512);
void *tes8 = malloc(4096);
void *tes9 = malloc(95956);
}