diff --git a/src/magic_memory.c b/src/magic_memory.c index bb498ea..6db4a91 100644 --- a/src/magic_memory.c +++ b/src/magic_memory.c @@ -6,49 +6,61 @@ #include "magic_memory.h" -magic_memory_context_t *magic_memory_begin(void) { - magic_memory_context_t *new_mm = (magic_memory_context_t *) malloc(sizeof(magic_memory_context_t)); +mm_ctx magic_memory_begin(void) { + /** + * Creates a new MagicMemory context to be used with MagicMemory functions. + */ - if (new_mm == NULL) { + mm_ctx new_mm_ctx = (magic_memory_context_t *) malloc(sizeof(magic_memory_context_t)); + + if (new_mm_ctx == NULL) { return NULL; } - new_mm->ptr = NULL; - new_mm->next = NULL; + new_mm_ctx->ptr = NULL; + new_mm_ctx->next = NULL; // This is always will be NULL in order to keep the code simple - return new_mm; + return new_mm_ctx; } -void *magic_malloc(magic_memory_context_t *magic_memory, size_t size) { +void *magic_malloc(mm_ctx context, size_t size) { + /** + * Same as simple malloc, but the pointer is also added to the context. + * MagicMemory keeps track of all pointers to allocated blocks in a context so they will never be lost. + */ - magic_memory_context_t *mm = (magic_memory_context_t *) malloc(sizeof(magic_memory_context_t)); + magic_memory_context_t *new_ctx_link = (magic_memory_context_t *) malloc(sizeof(magic_memory_context_t)); - if (mm == NULL) { + if (new_ctx_link == NULL) { return NULL; } void *new_ptr = malloc(size); if (new_ptr == NULL) { - free(mm); + free(new_ctx_link); return NULL; } - mm->ptr = new_ptr; - mm->next = NULL; + new_ctx_link->ptr = new_ptr; + new_ctx_link->next = NULL; - magic_memory_context_t *p = magic_memory; + magic_memory_context_t *p = context; while (p->next != NULL) { p = p->next; } - p->next = mm; + p->next = new_ctx_link; return new_ptr; } -void magic_free(magic_memory_context_t *magic_memory, void *ptr) { +void magic_free(mm_ctx context, void *ptr) { + /** + * Same as free() but it marks the memory block as already freed in the context. + * So the magic_cleanup() won't double-free. + */ - magic_memory_context_t *p = magic_memory; + magic_memory_context_t *p = context; while (p != NULL) { if (p->ptr == ptr) { free(p->ptr); @@ -57,12 +69,18 @@ void magic_free(magic_memory_context_t *magic_memory, void *ptr) { p = p->next; } + // That link of the chain won't be freed up in order to keep the code simple and fast + } -void magic_cleanup(magic_memory_context_t *magic_memory) { +void magic_cleanup(mm_ctx context) { + /** + * Free up the context, including all memory blocks in the context as well. + * This should be called after the context (and the memory blocks in the context) no longer needed. + */ - magic_memory_context_t *p = magic_memory; + magic_memory_context_t *p = context; while (p != NULL) { if (p->ptr != NULL) { diff --git a/src/magic_memory.h b/src/magic_memory.h index 096ee03..b7ee61f 100644 --- a/src/magic_memory.h +++ b/src/magic_memory.h @@ -5,6 +5,21 @@ #ifndef CAFF_PREVIEWER_MAGIC_MEMORY_H #define CAFF_PREVIEWER_MAGIC_MEMORY_H +/** + * MagicMemory is a super-simple helper library to help fighting with common memory management mistakes in C. + * In C you have to allocate and free every memory block manually. While this giving a great freedom which might be + * highly d desirable in certain use cases, most of the time all it does is causing headaches (double free, memory leak, etc.) + * + * The goal of MagicMemory is to provide a safety net for developers by trying to dodge the most common issues. + * By keeping certain conventions, MagicMemory can help writing more reliable code. + * + * MagicMemory keeps track of all memory blocks allocated. And provides a simple way to free up all those allocated + * memory block at once. This way the developer does not have to manually call free avoiding both double free and + * the abscence of a free. The storage structure for the allocations is called a context. The context must be provided + * for each MagicMemory function call. + * -- Marcsello + */ + #include typedef struct magic_memory_context_t { @@ -12,10 +27,12 @@ typedef struct magic_memory_context_t { void *ptr; } magic_memory_context_t; -magic_memory_context_t* magic_memory_begin(void); -void* magic_malloc(magic_memory_context_t* magic_memory, size_t size); +typedef magic_memory_context_t* mm_ctx; -void magic_free(magic_memory_context_t* magic_memory, void* ptr); -void magic_cleanup(magic_memory_context_t* magic_memory); +mm_ctx magic_memory_begin(void); +void* magic_malloc(mm_ctx context, size_t size); + +void magic_free(mm_ctx context, void* ptr); +void magic_cleanup(mm_ctx context); #endif //CAFF_PREVIEWER_MAGIC_MEMORY_H