aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README.md55
-rw-r--r--inc/malloc_internal.h45
-rw-r--r--src/malloc.c43
-rw-r--r--src/zone.c42
5 files changed, 181 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index fd8fe46..2935da6 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ LIBFT = $(LIBFT_DIR)/lib/libft.a
NAME = $(LIBDIR)/libft_malloc_$(HOSTTYPE).so
LINK = $(LIBDIR)/libft_malloc.so
-SRCS = malloc.c free.c realloc.c
+SRCS = malloc.c free.c realloc.c zone.c
OBJS = $(SRCS:%.c=$(OBJDIR)/%.o)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ef21ed7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,55 @@
+# ft_malloc
+
+Custom dynamic memory allocator implementing `malloc`, `free`, and `realloc` as a shared library (`libft_malloc_$HOSTTYPE.so`).
+
+42 School project.
+
+## Build
+
+```bash
+make # build lib/libft_malloc_$HOSTTYPE.so + symlink
+make test # build & run tests
+make clean # remove object files
+make fclean # full clean (library, Libft, tests)
+make re # fclean + all
+```
+
+## Usage
+
+The library is loaded at runtime via `LD_PRELOAD`, which instructs the Linux
+dynamic linker to load the specified shared library **before** any other,
+including libc. Any symbols it exports (such as `malloc`, `free`, `realloc`)
+override the default ones. This makes it a drop-in replacement with no
+recompilation needed:
+
+```bash
+LD_PRELOAD=./lib/libft_malloc.so ./my_program
+```
+
+Every call to `malloc`, `free`, or `realloc` inside `my_program` (and any
+library it uses) will go through `ft_malloc` instead of the system allocator.
+
+## API
+
+| Function | Description |
+|---|---|
+| `void *malloc(size_t size)` | Allocate `size` bytes |
+| `void free(void *ptr)` | Release a previously allocated block |
+| `void *realloc(void *ptr, size_t size)` | Resize a block to `size` bytes |
+| `void show_alloc_mem(void)` | Print all zones and allocations to stdout |
+
+## Architecture
+
+Allocations are divided into three categories:
+
+| Category | Size range | Strategy |
+|---|---|---|
+| TINY | 1 -- 128 bytes | Pre-allocated zone (fits 100+ allocations) |
+| SMALL | 129 -- 1024 bytes | Pre-allocated zone (fits 100+ allocations) |
+| LARGE | 1025+ bytes | Individual `mmap` per allocation |
+
+TINY and SMALL zones are page-aligned regions obtained via `mmap`. New zones
+are allocated on demand when the current one is full. LARGE allocations each
+get their own `mmap` region and are released individually via `munmap`.
+
+All returned pointers are 16-byte aligned.
diff --git a/inc/malloc_internal.h b/inc/malloc_internal.h
new file mode 100644
index 0000000..fe275e3
--- /dev/null
+++ b/inc/malloc_internal.h
@@ -0,0 +1,45 @@
+/**
+ * @file malloc_internal.h
+ * @brief Internal data structures and macros for the ft_malloc allocator.
+ */
+
+#ifndef MALLOC_INTERNAL_H
+#define MALLOC_INTERNAL_H
+
+#include <stddef.h>
+
+#define TINY_MAX 128
+#define SMALL_MAX 1024
+#define ALIGNMENT 16
+/* Round x up to the nearest multiple of ALIGNMENT. */
+#define ALIGN(x) (((x) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
+#define MIN_ALLOC_COUNT 100
+
+/* Header embedded before each allocation block inside a zone. */
+typedef struct s_chunk
+{
+ size_t size;
+ struct s_chunk *next;
+ int is_free;
+} t_chunk;
+
+/* Header at the start of each mmap'd region. */
+typedef struct s_zone
+{
+ struct s_zone *next;
+ size_t size;
+} t_zone;
+
+/* Global state: one linked list per zone category. */
+typedef struct s_heap
+{
+ t_zone *tiny;
+ t_zone *small;
+ t_zone *large;
+} t_heap;
+
+extern t_heap g_heap;
+
+t_zone *zone_new (size_t alloc_max);
+
+#endif
diff --git a/src/malloc.c b/src/malloc.c
index 8982de0..268e0d1 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -1,15 +1,48 @@
/**
* @file malloc.c
- * @brief Stub implementation of malloc.
+ * @brief malloc implementation.
*/
#include "malloc.h"
-#include "libft.h"
+#include "malloc_internal.h"
+
+t_heap g_heap = { 0 };
void *
malloc (size_t size)
{
- (void)size;
- ft_putendl_fd ("MALLOC", 1);
- return (NULL);
+ t_zone **zone_list;
+ t_zone *zone;
+ t_chunk *chunk;
+ size_t alloc_max;
+
+ if (size == 0)
+ size = 1;
+ if (size <= TINY_MAX)
+ {
+ zone_list = &g_heap.tiny;
+ alloc_max = TINY_MAX;
+ }
+ else if (size <= SMALL_MAX)
+ {
+ zone_list = &g_heap.small;
+ alloc_max = SMALL_MAX;
+ }
+ else
+ {
+ zone_list = &g_heap.large;
+ alloc_max = size;
+ }
+ if (*zone_list == NULL)
+ {
+ zone = zone_new (alloc_max);
+ if (zone == NULL)
+ return (NULL);
+ *zone_list = zone;
+ }
+ else
+ zone = *zone_list;
+ chunk = (t_chunk *)((char *)zone + ALIGN (sizeof (t_zone)));
+ chunk->is_free = 0;
+ return ((char *)chunk + ALIGN (sizeof (t_chunk)));
}
diff --git a/src/zone.c b/src/zone.c
new file mode 100644
index 0000000..724237b
--- /dev/null
+++ b/src/zone.c
@@ -0,0 +1,42 @@
+/**
+ * @file zone.c
+ * @brief Zone allocation via mmap.
+ */
+
+#include "malloc_internal.h"
+#include <sys/mman.h>
+#include <unistd.h>
+
+static size_t
+_s_zone_size (size_t alloc_max)
+{
+ size_t chunk_size;
+ size_t total;
+ size_t page_size;
+
+ chunk_size = ALIGN (sizeof (t_chunk)) + ALIGN (alloc_max);
+ total = ALIGN (sizeof (t_zone)) + MIN_ALLOC_COUNT * chunk_size;
+ page_size = (size_t)getpagesize ();
+ return ((total + page_size - 1) & ~(page_size - 1));
+}
+
+t_zone *
+zone_new (size_t alloc_max)
+{
+ size_t zone_size;
+ t_zone *zone;
+ t_chunk *chunk;
+
+ zone_size = _s_zone_size (alloc_max);
+ zone = mmap (NULL, zone_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (zone == MAP_FAILED)
+ return (NULL);
+ zone->next = NULL;
+ zone->size = zone_size;
+ chunk = (t_chunk *)((char *)zone + ALIGN (sizeof (t_zone)));
+ chunk->size = zone_size - ALIGN (sizeof (t_zone)) - ALIGN (sizeof (t_chunk));
+ chunk->next = NULL;
+ chunk->is_free = 1;
+ return (zone);
+}