πŸ§ βœ… Laser Focus Activated.
We’re now moving precisely and decisively into:


πŸ“¦ 09_arena_allocator_scope_test

🎯 Goal: Build and inspect a manual arena allocator where memory lifetime and boundaries are explicit and local β€” unlike malloc() which hides everything in libc internals.


🧠 Strategic Why:

We just finished [[08_malloc_tls_isolation_test/]], proving:

  • malloc() β‰  predictable

  • Thread-local arenas exist but aren’t visible

  • Scope and ownership of memory = unclear

Now, in 09, we flip the model:

βœ… You allocate the memory.
βœ… You track the offset.
βœ… You control the lifetime.
βœ… You see the fragmentation yourself.


Phase Structure:

FilePurpose
βœ… 09a_arena_scope_local_mmap.cAllocate a user arena via mmap() and write into it
⏳ 09b_arena_scope_leak_tracer.cSimulate scope leak and print memory before/after
⏳ 09c_arena_scope_fork_test.cFork after arena allocation β†’ trace outcome

Dropping 09a_arena_scope_local_mmap.c next β€” clean, 1-file focused.

Let’s begin your first user-controlled memory arena.
πŸ§ πŸ“¦ Ready? Let’s build.

// πŸ“¦ File: 09a_arena_scope_local_mmap.c
// πŸ”¬ Goal: Allocate a manual arena with mmap() and control memory lifetime and offset manually
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <stdint.h>
 
#define ARENA_SIZE 4096
#define BLOCK_SIZE 64
 
typedef struct s_arena
{
	void		*base;
	size_t		offset;
	size_t		capacity;
}	t_arena;
 
void	arena_init(t_arena *a, size_t size)
{
	a->base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
	if (a->base == MAP_FAILED)
	{
		perror("mmap");
		exit(1);
	}
	a->offset = 0;
	a->capacity = size;
	printf("πŸ“¦ Arena initialized at %p (%zu bytes)\n", a->base, size);
}
 
void	*arena_alloc(t_arena *a, size_t size)
{
	if (a->offset + size > a->capacity)
	{
		fprintf(stderr, "❌ Arena out of memory!\n");
		return (NULL);
	}
	void *ptr = (char *)a->base + a->offset;
	a->offset += size;
	printf("βœ… arena_alloc(%zu) β†’ %p (offset = %zu)\n", size, ptr, a->offset);
	return (ptr);
}
 
void	arena_dump(t_arena *a)
{
	printf("🧠 Arena dump:\n");
	for (size_t i = 0; i < a->offset; i++)
	{
		char c = ((char *)a->base)[i];
		if (c >= 32 && c < 127)
			printf("%c", c);
		else
			printf(".");
	}
	printf("\n");
}
 
void	arena_free(t_arena *a)
{
	if (munmap(a->base, a->capacity) != 0)
		perror("munmap");
	else
		printf("🧹 Arena memory freed\n");
	a->base = NULL;
	a->offset = 0;
	a->capacity = 0;
}
 
int	main(void)
{
	t_arena arena;
 
	arena_init(&arena, ARENA_SIZE);
 
	char *msg1 = arena_alloc(&arena, BLOCK_SIZE);
	char *msg2 = arena_alloc(&arena, BLOCK_SIZE);
	char *msg3 = arena_alloc(&arena, BLOCK_SIZE);
 
	strcpy(msg1, "Hello arena");
	strcpy(msg2, "Scoped allocator is born");
	strcpy(msg3, "This is not malloc");
 
	arena_dump(&arena);
 
	arena_free(&arena);
	return (0);
}

βœ… [[09a_arena_scope_local_mmap.c]] Summary

πŸ§ͺ What You LearnedπŸ’‘ Insight
mmap() allocatorYou now own the heap itself
Arena boundariesNo more hidden metadata β€” offset tells all
Scope-controlled memoryYou allocate β†’ you free
Fragmentation and reuseClearly visible if you modify reuse logic

🧠 Blindspots Unlocked

  • What happens when you fork after arena alloc?

  • What if two arenas overlap?

  • Can you detect use-after-unmap?

  • What about memory leaks from non-zeroed offsets?

  • Is this thread-safe? (Hint: ❌)


Next Up: [[09b_arena_scope_leak_tracer.c]]

We’ll simulate an arena memory leak by forgetting to track or free one allocation, then diff it before/after with memcmp() and visual logging.

Unless you want to skip directly to fork territory in 09c β€” say the word.

You’re now building memory engines.
No more mallocs.
πŸ“¦πŸ§ πŸ’₯

πŸ”₯ Let’s go full destructive mode then. Time to leak, corrupt, and dump like a real allocator stress-test.


πŸ“‚ 09b_arena_scope_leak_tracer.c

⚠️ Purpose:

Simulate memory leaks, corrupted offsets, and untracked allocations
Explore the consequences of managing your own arena without safety checks


🧬 Code: 09b_arena_scope_leak_tracer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <stdint.h>
 
#define ARENA_SIZE 256
#define BLOCK_SIZE 32
 
typedef struct s_arena {
	void	*base;
	size_t	offset;
	size_t	capacity;
}	t_arena;
 
void	arena_init(t_arena *a, size_t size)
{
	a->base = mmap(NULL, size,
		PROT_READ | PROT_WRITE,
		MAP_PRIVATE | MAP_ANONYMOUS,
		-1, 0);
	if (a->base == MAP_FAILED)
	{
		perror("mmap");
		exit(1);
	}
	a->offset = 0;
	a->capacity = size;
	printf("🎯 Arena initialized at %p (%zu bytes)\n", a->base, size);
}
 
void	*arena_alloc(t_arena *a, size_t size)
{
	if (a->offset + size > a->capacity)
	{
		fprintf(stderr, "❌ Arena out of memory at offset %zu\n", a->offset);
		return (NULL);
	}
	void *ptr = (char *)a->base + a->offset;
	a->offset += size;
	printf("βœ… arena_alloc(%zu) β†’ %p (offset now %zu)\n", size, ptr, a->offset);
	return (ptr);
}
 
void	arena_dump(t_arena *a)
{
	printf("\nπŸ“¦ Arena dump (%zu used / %zu total):\n", a->offset, a->capacity);
	for (size_t i = 0; i < a->offset; i++)
	{
		char c = ((char *)a->base)[i];
		if (c >= 32 && c < 127)
			printf("%c", c);
		else
			printf(".");
	}
	printf("\n");
}
 
void	arena_free(t_arena *a)
{
	if (munmap(a->base, a->capacity) != 0)
		perror("munmap");
	else
		printf("🧹 Arena memory freed\n");
	a->base = NULL;
	a->offset = 0;
	a->capacity = 0;
}
 
int	main(void)
{
	t_arena arena;
	arena_init(&arena, ARENA_SIZE);
 
	// Normal alloc
	char *a = arena_alloc(&arena, BLOCK_SIZE);
	char *b = arena_alloc(&arena, BLOCK_SIZE);
 
	strcpy(a, "First block ok.");
	strcpy(b, "Second block too.");
 
	// Leaked pointer: never saved return
	arena_alloc(&arena, BLOCK_SIZE); // not assigned to any variable
	printf("⚠️  Leaked 32 bytes β€” no tracking.\n");
 
	// Intentional overflow write
	char *c = arena_alloc(&arena, BLOCK_SIZE);
	strcpy(c, "This will overwrite next");
	strcpy(c + 20, " 🀑 Oops!");
 
	arena_dump(&arena);
 
	arena_free(&arena);
	return (0);
}

🧠 What to Look For

SymbolMeaning
βœ…Normal alloc
⚠️Leak (untracked pointer)
🀑Corrupting next block
πŸ“¦Heap visualization
🧹Manual unmapping

🧠 Strategic Questions (Generated for You)

πŸ” 180 IQ Review Triggers:

  • What if you realloc or resize this arena?

  • What if arena_alloc() returns NULL, but caller ignores it?

  • What tools in real life would detect that overflow?

  • Could you implement a double-free detector manually?


βœ… After This File, You’ll Know:

  • How memory leaks feel when you don’t track pointers

  • How arenas can silently overflow

  • How scoped allocators demand discipline and diagnostics


Say the word and I’ll prep:

  • πŸ“„ README.md for 09b

  • 🧠 09c_arena_scope_fork_test.c to test fork safety of arena

  • 🧬 10_overlapping_allocations_demo.c for weird memory layouts

This allocator playground is now your malloc().
You’re debugging your heap like a true memory monk. πŸ§˜β€β™‚οΈπŸ“¦πŸ§