AxlMem – Memory Allocation
Memory allocation with dmalloc-inspired debug features. Size-tracking headers
enable axl_realloc without passing the old size. Debug builds add
fence-post guards, alloc/free fill patterns, file/line tracking, and leak
reporting.
Header: <axl/axl-mem.h>
Overview
AXL provides its own allocator on top of UEFI’s pool memory. All allocated
memory is tracked with a small header that stores the block size, enabling
axl_realloc and debug features without requiring the caller to pass the
old size.
Do not mix axl_malloc with UEFI’s FreePool, or AllocatePool
with axl_free – they use different headers.
Debug vs. Release
In debug builds (-DAXL_MEM_DEBUG, the default for make):
Fill patterns: newly allocated memory is filled with
0xDA; freed memory is filled with0xDD. Use-after-free often manifests as reads of0xDD.Fence-post guards: 8 bytes of
0xFDare placed before and after each allocation.axl_mem_check(ptr)verifies these guards.File/line tracking: each allocation records
__FILE__and__LINE__for leak reports.Leak reporting:
axl_mem_dump_leaks()prints all outstanding allocations with their sizes and source locations.
In release builds (make BUILD=RELEASE), these features are disabled
and the allocator has minimal overhead.
RAII Auto-Cleanup
AXL provides GLib-style auto-cleanup macros using
__attribute__((cleanup)):
// Automatically freed when 's' goes out of scope
AXL_AUTO_FREE char *s = axl_strdup("hello");
// Automatically freed when 'h' goes out of scope
AXL_AUTOPTR(AxlHashTable) h = axl_hash_table_new();
if (error_condition) {
return -1; // both 's' and 'h' are freed automatically
}
Important: Always initialize at declaration. Never use with goto
that jumps over the declaration. See the
GLib g_autoptr documentation
for detailed rules.
Quick Reference
#include <axl.h>
// Basic allocation
char *buf = axl_malloc(256);
void *copy = axl_memdup(original, size);
char *str = axl_strdup("hello");
// Typed allocation (zero-initialized)
MyStruct *s = axl_new(MyStruct);
int *arr = axl_new_array(int, 100);
// Free (NULL-safe)
axl_free(buf);
// Debug: check for leaks before exit
axl_mem_dump_leaks();
API Reference
Defines
-
AXL_OK
operation succeeded
-
AXL_ERR
operation failed
-
AXL_AUTO_FREE
-
AXL_HAVE_AUTOPTR
Define an auto-cleanup function for a named type.
Place after the type’s _free() declaration in its header:
AXL_DEFINE_AUTOPTR_CLEANUP(AxlString, axl_string_free)
Then use AXL_AUTOPTR(AxlString) in variable declarations.
-
AXL_DEFINE_AUTOPTR_CLEANUP(Type, free_func)
-
AXL_AUTOPTR(Type)
Declare a pointer that is automatically freed at scope exit.
Requires AXL_DEFINE_AUTOPTR_CLEANUP for the type.
Declares a pointer — do not add an extra
*:AXL_AUTOPTR(AxlString) s = axl_string_new("hello"); axl_string_append(s, " world"); // s is freed automatically at end of scope
IMPORTANT: Always initialize at declaration (use NULL if no initial value). Never use with goto that jumps over the declaration.
-
AXL_ARRAY_SIZE(a)
Get the number of elements in a static array.
Only works on actual arrays, not pointers. Produces a compile-time constant suitable for use in static initializers.
-
AXL_SIGNATURE_32(a, b, c, d)
Construct a 32-bit signature from four ASCII characters.
Encodes characters in little-endian order. Commonly used for structure validation signatures in UEFI drivers.
-
AXL_CONTAINER_OF(ptr, type, member)
Derive a pointer to the enclosing structure from a member pointer.
Given a pointer to a struct member, returns a pointer to the containing structure. Equivalent to Linux kernel’s container_of and EDK2’s CR/BASE_CR macros.
- Parameters:
ptr – pointer to the member
type – type of the containing structure
member – name of the member within the structure
Functions
-
void *axl_malloc(size_t size)
Allocate size bytes of uninitialized memory.
- Parameters:
size – number of bytes to allocate
- Returns:
pointer to allocated memory, or NULL on failure. Free with axl_free().
-
void *axl_calloc(size_t count, size_t size)
Allocate zero-initialized memory for count elements of size bytes each.
- Parameters:
count – number of elements
size – size of each element in bytes
- Returns:
pointer to allocated memory, or NULL on failure. Free with axl_free().
-
void *axl_realloc(void *ptr, size_t size)
Resize a previously allocated block to size bytes.
Contents are preserved up to the smaller of old and new sizes. If ptr is NULL, behaves like axl_malloc().
- Parameters:
ptr – pointer from axl_malloc/axl_calloc/axl_realloc, or NULL
size – new size in bytes
- Returns:
pointer to reallocated memory, or NULL on failure (original block is unchanged).
-
void axl_free(void *ptr)
Free memory allocated by axl_malloc, axl_calloc, axl_realloc, axl_strdup, or axl_memdup. NULL-safe.
- Parameters:
ptr – pointer to free, or NULL
-
char *axl_strdup(const char *s)
Duplicate a NUL-terminated string.
- Parameters:
s – string to duplicate, or NULL
- Returns:
newly allocated copy, or NULL on failure. Free with axl_free().
-
void *axl_memdup(const void *src, size_t size)
Duplicate size bytes of memory from src.
- Parameters:
src – source buffer
size – number of bytes to copy
- Returns:
newly allocated copy, or NULL on failure. Free with axl_free().
-
void *axl_new(size_t Type)
Allocate and zero-initialize a single instance of a type.
Usage:
MyStruct *p = axl_new(MyStruct);- Parameters:
Type – the type to allocate (passed as a type name)
- Returns:
typed pointer, or NULL on failure. Free with axl_free().
-
void *axl_new_array(size_t Type, size_t Count)
Allocate and zero-initialize an array of elements.
Usage:
int *arr = axl_new_array(int, 100);- Parameters:
Type – the type to allocate (passed as a type name)
Count – number of elements
- Returns:
typed pointer, or NULL on failure. Free with axl_free().
-
void axl_free_impl(void *ptr)
Auto-free a heap pointer when it goes out of scope.
Works with axl_malloc, axl_strdup, axl_memdup, and any pointer freed by axl_free().
AXL_AUTO_FREE char *s = axl_strdup("hello"); if (error) return -1; // s is freed automatically
IMPORTANT: Always initialize at declaration. Never use with goto that jumps over the declaration. Cleanup runs at scope exit regardless of whether the variable was assigned.
-
static inline void _axl_auto_free_func(void *p)
-
int axl_alloc_pages(size_t count, uint64_t *phys_addr)
Allocate contiguous page-aligned memory.
Allocates count pages (each 4096 bytes) of contiguous physical memory. Suitable for DMA buffers, RAM disks, and other uses requiring physical address alignment.
- Parameters:
count – number of 4KB pages to allocate
phys_addr – [out] receives physical address
- Returns:
0 on success, -1 on error.
-
void axl_free_pages(uint64_t phys_addr, size_t count)
Free page-aligned memory allocated by axl_alloc_pages.
- Parameters:
phys_addr – physical address from axl_alloc_pages
count – number of pages (must match alloc)
-
void axl_mem_get_stats(AxlMemStats *stats)
Get current allocation statistics.
- Parameters:
stats – [out] receives statistics
-
void axl_mem_dump_leaks(void)
Print all outstanding allocations to the log (debug builds).
Each leaked block is reported with its size, file, and line number. No-op in release builds.
-
bool axl_mem_check(const void *ptr)
Validate a heap pointer’s fence-post guards (debug builds).
- Parameters:
ptr – pointer to validate
- Returns:
true if valid, false if corrupted or not an axl_malloc’d pointer. Always returns true in release builds.
-
struct AxlMemStats