libmemalloc  v3.0.00
Modern Memory Allocator
Loading...
Searching...
No Matches
libmemalloc.c File Reference

Core memory management components for libmemalloc. More...

#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include "libmemalloc.h"
#include "logs.h"
Include dependency graph for libmemalloc.c:

Classes

struct  block_header_t
 Represents the header for a memory block. More...
 
struct  mem_arena_t
 Represents a memory arena with its own free lists. More...
 
struct  mmap_t
 Tracks memory-mapped regions for large allocations. More...
 
struct  gc_thread_t
 Orchestrates the background mark-and-sweep garbage collector. More...
 
struct  mem_allocator_t
 Manages dynamic memory allocation. More...
 

Macros

#define LOG_LEVEL   LOG_LEVEL_NONE
 Logging verbosity threshold for this module.
 
#define DEFAULT_NUM_BINS   (uint8_t)(10U)
 Default number of size classes (bins) for free lists.
 
#define CACHE_LINE_SIZE   (uint8_t)(64U)
 Size of the CPU cache line in bytes.
 
#define BYTES_PER_CLASS   (uint8_t)(128U)
 Fixed byte allocation per classification unit.
 
#define MMAP_THRESHOLD   (size_t)(128U * 1024U)
 Threshold size for using mmap-based allocation.
 
#define MIN_BLOCK_SIZE   (size_t)(sizeof(block_header_t) + ARCH_ALIGNMENT)
 Defines the minimum memory block size.
 
#define NR_OBJS   (uint16_t)(1000U)
 Number of iterations used to scale GC sleep duration.
 

Typedefs

typedef int(* find_fn_t) (mem_allocator_t *const, const size_t, block_header_t **)
 Type for functions that locate a suitable free block.
 

Functions

void * MEM_sbrk (const intptr_t increment)
 Invokes sbrk-like behavior by moving the program break.
 
static int MEM_getSizeClass (mem_allocator_t *const allocator, const size_t size)
 Calculates the size class index for a requested memory size.
 
static int MEM_allocatorInit (mem_allocator_t *const allocator)
 Initializes the memory allocator and its internal structures.
 
static int MEM_validateBlock (mem_allocator_t *const allocator, block_header_t *const block)
 Validates the integrity and boundaries of a memory block.
 
static int MEM_insertFreeBlock (mem_allocator_t *const allocator, block_header_t *const block)
 Inserts a block into the appropriate free list based on its size.
 
static int MEM_removeFreeBlock (mem_allocator_t *const allocator, block_header_t *const block)
 Removes a block from its free list.
 
static int MEM_findFirstFit (mem_allocator_t *const allocator, const size_t size, block_header_t **fit_block)
 Searches for the first suitable free memory block in size‐class lists.
 
static int MEM_findNextFit (mem_allocator_t *const allocator, const size_t size, block_header_t **fit_block)
 Searches for the next suitable free memory block using the NEXT_FIT strategy starting from the last allocated position.
 
static int MEM_findBestFit (mem_allocator_t *const allocator, const size_t size, block_header_t **best_fit)
 Searches for the smallest suitable free memory block in size‐class lists (BEST_FIT).
 
static int MEM_splitBlock (mem_allocator_t *const allocator, block_header_t *const block, const size_t req_size)
 Splits a memory block into allocated and free portions.
 
static int MEM_mergeBlocks (mem_allocator_t *const allocator, block_header_t *block)
 Merges adjacent free memory blocks.
 
static void * MEM_growUserHeap (mem_allocator_t *const allocator, const intptr_t inc)
 Expands the user heap by a specified increment.
 
static void * MEM_mapAlloc (mem_allocator_t *const allocator, const size_t total_size)
 Allocates a page-aligned memory region via mmap and registers it in the allocator’s mmap list for later freeing.
 
static int MEM_mapFree (mem_allocator_t *const allocator, void *const addr)
 Unmaps a previously mapped memory region and removes its metadata entry from the allocator’s mmap list.
 
static void * MEM_allocOp (mem_allocator_t *const allocator, const size_t size, const char *const file, const int line, const allocation_strategy_t strategy) __LIBMEMALLOC_INTERNAL_MALLOC
 Allocates memory using the specified strategy.
 
static void * MEM_reallocOp (mem_allocator_t *const allocator, void *const ptr, const size_t new_size, const char *const file, const int line, const allocation_strategy_t strategy) __LIBMEMALLOC_INTERNAL_REALLOC
 Reallocates memory with safety checks.
 
static void * MEM_callocOp (mem_allocator_t *const allocator, const size_t size, const char *const file, const int line, const allocation_strategy_t strategy) __LIBMEMALLOC_INTERNAL_MALLOC
 Allocates and zero‐initializes memory.
 
static int MEM_freeOp (mem_allocator_t *const allocator, void *const ptr, const char *const file, const int line)
 Releases allocated memory back to the heap.
 
static bool MEM_stackGrowsDown (void)
 Determine at runtime whether the stack grows downward.
 
static int MEM_stackBounds (const pthread_t id, mem_allocator_t *const allocator)
 Query and record the bounding addresses of a thread’s stack.
 
void * MEM_memset (void *const source, const int value, const size_t size)
 Fills a memory block with a specified byte value using optimized operations.
 
void * MEM_memcpy (void *const dest, const void *src, const size_t size)
 Copies a memory block between buffers using optimized operations.
 
void * MEM_allocFirstFit (const size_t size)
 Allocates memory using the FIRST_FIT strategy.
 
void * MEM_allocBestFit (const size_t size)
 Allocates memory using the BEST_FIT strategy.
 
void * MEM_allocNextFit (const size_t size)
 Allocates memory using the NEXT_FIT strategy.
 
void * MEM_alloc (const size_t size, const allocation_strategy_t strategy)
 Allocates memory using the specified strategy.
 
void * MEM_calloc (const size_t size, const allocation_strategy_t strategy)
 Allocates and zero‐initializes memory using the specified strategy.
 
void * MEM_realloc (void *const ptr, const size_t new_size, const allocation_strategy_t strategy)
 Reallocates memory with safety checks using the specified strategy.
 
int MEM_free (void *const ptr)
 Releases allocated memory back to the heap.
 

Variables

static mem_allocator_t g_allocator
 Process-wide default allocator instance.
 
static bool g_allocator_inited = false
 One-time initialization guard for g_allocator.
 

Detailed Description

Core memory management components for libmemalloc.

Implements memory allocator with advanced features:

  • Architecture-specific stack allocation (alloca)
  • Garbage collection (mark & sweep)
  • Block validation with magic numbers/canaries
  • Multiple allocation strategies (First/Best/Next Fit)
Version
v3.0.00
Date
28.09.2025
Author
Rafael V. Volkmer rafae.nosp@m.l.v..nosp@m.volkm.nosp@m.er@g.nosp@m.mail..nosp@m.com

Macro Definition Documentation

◆ BYTES_PER_CLASS

#define BYTES_PER_CLASS   (uint8_t)(128U)

Fixed byte allocation per classification unit.

Defines the number of bytes assigned to each classification category. Ensures memory alignment and efficient block processing in data structures.

◆ CACHE_LINE_SIZE

#define CACHE_LINE_SIZE   (uint8_t)(64U)

Size of the CPU cache line in bytes.

This constant defines the cache-line size used for prefetching and alignment optimizations, ensuring memory accesses align to hardware cache boundaries for maximum performance and correctness on platforms with strict alignment requirements.

◆ DEFAULT_NUM_BINS

#define DEFAULT_NUM_BINS   (uint8_t)(10U)

Default number of size classes (bins) for free lists.

Defines how many size categories (bins) the allocator will maintain for managing free memory blocks. This value affects allocation speed and fragmentation behavior.

◆ LOG_LEVEL

#define LOG_LEVEL   LOG_LEVEL_NONE

Logging verbosity threshold for this module.

Sets the minimum severity of log messages that will be compiled into this translation unit. Only log calls at or below the specified level are enabled:

  • LOG_LEVEL_NONE (0): disable all logging
  • LOG_LEVEL_ERROR (1): errors only
  • LOG_LEVEL_WARNING (2): warnings and errors
  • LOG_LEVEL_INFO (3): info, warnings, and errors
  • LOG_LEVEL_DEBUG (4): debug, info, warnings, and errors

◆ MIN_BLOCK_SIZE

#define MIN_BLOCK_SIZE   (size_t)(sizeof(block_header_t) + ARCH_ALIGNMENT)

Defines the minimum memory block size.

Ensures each memory block is large enough to hold a block header and alignment padding.

◆ MMAP_THRESHOLD

#define MMAP_THRESHOLD   (size_t)(128U * 1024U)

Threshold size for using mmap-based allocation.

When a requested allocation size meets or exceeds this value (128 KiB), the allocator will switch from using the heap (brk/sbrk) to using mmap for more efficient large-block handling and to reduce heap fragmentation.

◆ NR_OBJS

#define NR_OBJS   (uint16_t)(1000U)

Number of iterations used to scale GC sleep duration.

Specifies the multiplier applied to the base GC interval (in milliseconds) to compute the actual sleep time between successive garbage-collection cycles: sleep_time = gc_interval_ms * NR_OBJS

Typedef Documentation

◆ find_fn_t

find_fn_t

Type for functions that locate a suitable free block.

Parameters
[in]allocatorMemory allocator context in which to search.
[in]sizeTotal size requested (including header and canary).
[out]blockAddress of pointer to store the found block header.
Returns
Integer

Function Documentation

◆ MEM_allocatorInit()

static int MEM_allocatorInit ( mem_allocator_t *const  allocator)
static

Initializes the memory allocator and its internal structures.

This function prepares the allocator’s heap by:

  • Reading and aligning the initial program break to ARCH_ALIGNMENT.
  • Allocating the arena array and free‐list bins via MEM_growUserHeap().
  • Zeroing out the free‐list bins.
  • Initializing the allocator fields (heap_start, heap_end, free_lists).
  • Setting up the garbage‐collector thread state and its mutex/cond.
  • Capturing the current thread’s stack bounds via MEM_stackBounds().
  • (If under Valgrind) creating a mempool for the allocator.
Parameters
[in]allocatorPointer to a mem_allocator_t instance to initialize.
Returns
Integer status code indicating initialization result.
Return values
EXIT_SUCCESSAllocator initialized successfully.
-EINVALInvalid allocator pointer.
-ENOMEMHeap alignment or arena/bin allocation failed.

◆ MEM_allocOp()

static void * MEM_allocOp ( mem_allocator_t *const  allocator,
const size_t  size,
const char *const  file,
const int  line,
const allocation_strategy_t  strategy 
)
static

Allocates memory using the specified strategy.

This function attempts to allocate at least size bytes of user data by choosing between heap‐based allocation (via free‐lists and optional heap growth) or mmap (for large requests > MMAP_THRESHOLD). It uses the given strategy (FIRST_FIT, NEXT_FIT, BEST_FIT) to locate a free block, grows the heap if necessary, splits a larger block to fit exactly, and records debugging metadata (source file, line). For mmap allocations it rounds up to page size and tracks the region in the allocator.

Parameters
[in]allocatorMemory allocator context.
[in]sizeNumber of bytes requested.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
[in]strategyAllocation strategy.
Returns
Pointer to the start of the allocated user region (just past the internal header) on success; an error‐encoded pointer (via PTR_ERR()) on failure.
Return values
ptrValid user pointer on success.
-EINVALallocator is NULL or size is zero.
-ENOMEMOut of memory: heap grow failed, no free block found, or internal metadata allocation (e.g. mmap_t node) failed.
-EIOmmap() I/O error for large allocations.

◆ MEM_callocOp()

static void * MEM_callocOp ( mem_allocator_t *const  allocator,
const size_t  size,
const char *const  file,
const int  line,
const allocation_strategy_t  strategy 
)
static

Allocates and zero‐initializes memory.

This function behaves like calloc(), allocating at least size bytes of zeroed memory via MEM_allocOp() and then setting all bytes to zero. It records debugging metadata (source file, line) and uses the given strategy for allocation.

Parameters
[in]allocatorPointer to the mem_allocator_t context.
[in]sizeNumber of bytes to allocate.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
[in]strategyAllocation strategy to use.
Returns
Pointer to the start of the allocated zeroed region; an error‐encoded pointer via PTR_ERR() on failure.
Return values
ptrValid pointer to size bytes of zeroed memory.
-EINVALallocator is NULL or size is zero.
-ENOMEMOut of memory: allocation failed.
-EIOI/O error for large mmap‐based allocations.

◆ MEM_findBestFit()

static int MEM_findBestFit ( mem_allocator_t *const  allocator,
const size_t  size,
block_header_t **  best_fit 
)
static

Searches for the smallest suitable free memory block in size‐class lists (BEST_FIT).

This function computes the starting size class for the requested size via MEM_getSizeClass(), then scans each free‐list from that class upward. It validates each candidate with MEM_validateBlock() and tracks the smallest free block that is large enough. Once a block in any class is chosen, the search stops.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizeRequested allocation size in bytes.
[out]best_fitOn success, set to the pointer of the free block.
Returns
Integer status code.
Return values
EXIT_SUCCESSSuitable block found successfully.
-EINVALallocator or best_fit is NULL.
-ENOMEMSize calculation failed or no suitable block found.

◆ MEM_findFirstFit()

static int MEM_findFirstFit ( mem_allocator_t *const  allocator,
const size_t  size,
block_header_t **  fit_block 
)
static

Searches for the first suitable free memory block in size‐class lists.

This function computes the starting size class for the requested size via MEM_getSizeClass(), then scans each free‐list from that class upward. For each candidate block, it calls MEM_validateBlock() to ensure integrity, and returns the first block that is marked free and large enough. The found block pointer is stored in fit_block.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizeRequested allocation size in bytes.
[out]fit_blockOn success, set to the pointer of a suitable free block.
Returns
Integer status code.
Return values
EXIT_SUCCESSSuitable block found successfully.
-EINVALallocator or fit_block are NULL;
-ENOMEMSize calculation failed or no suitable block found.

◆ MEM_findNextFit()

static int MEM_findNextFit ( mem_allocator_t *const  allocator,
const size_t  size,
block_header_t **  fit_block 
)
static

Searches for the next suitable free memory block using the NEXT_FIT strategy starting from the last allocated position.

This function attempts to find a free block of at least size bytes by scanning the heap starting at allocator->last_allocated. If last_allocated is NULL, not free, or corrupted, it falls back to First-Fit. It wraps around to the heap start if needed, stopping once it returns to the start.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizeRequested allocation size in bytes.
[out]fit_blockPointer to store the address of the found block.
Returns
Integer status code.
Return values
EXIT_SUCCESSSuitable block found and fit_block set.
-EINVALallocator or fit_block is NULL.
-ENOMEMNo suitable block found in heap.

◆ MEM_freeOp()

static int MEM_freeOp ( mem_allocator_t *const  allocator,
void *const  ptr,
const char *const  file,
const int  line 
)
static

Releases allocated memory back to the heap.

This function frees a pointer previously returned by MEM_allocOp(). It supports both heap‐based and mmap‐based allocations:

  • For mmap regions, it delegates to MEM_mapFree() to unmap and remove metadata.
  • For heap blocks, it validates the block, checks for double frees, marks the block free, merges with adjacent free blocks, and reinserts the merged block into the free list. If the freed block lies at the current heap end, it shrinks the heap via MEM_sbrk().
Parameters
[in]allocatorMemory allocator context.
[in]ptrPointer to memory to free.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
Returns
Integer status code.
Return values
EXIT_SUCCESSMemory freed (and heap possibly shrunk) successfully.
-EINVALallocator or ptr is NULL, ptr not found in allocator, or double free detected.
-ENOMEMmunmap() failed when freeing an mmap region.
-EFAULTBlock lies outside heap and mmap regions.
-EPROTOHeader canary mismatch (block corrupted).
-EOVERFLOWData canary mismatch (buffer overrun detected).
-EFBIGBlock size extends past heap end.
rer<0Errors returned by MEM_validateBlock(), MEM_removeFreeBlock(), MEM_mergeBlocks(), or MEM_insertFreeBlock().

◆ MEM_getSizeClass()

static int MEM_getSizeClass ( mem_allocator_t *const  allocator,
const size_t  size 
)
static

Calculates the size class index for a requested memory size.

This function determines which size class the given allocation request belongs to by dividing the requested size by BYTES_PER_CLASS (rounding up). If the computed index exceeds the maximum available class, it will be clamped to the highest class and a warning emitted.

Parameters
[in]allocatorPointer to the allocator context.
[in]sizeRequested memory size in bytes (must be > 0).
Returns
On success, returns a non-negative integer size class index; on failure, returns a negative error code.
Return values
ret>0Valid size class index.
-EINVALallocator is NULL, or size is zero.

◆ MEM_growUserHeap()

static void * MEM_growUserHeap ( mem_allocator_t *const  allocator,
const intptr_t  inc 
)
static

Expands the user heap by a specified increment.

This function moves the program break by inc bytes via MEM_sbrk(), zeroes the newly allocated region, updates the allocator’s heap_end, and initializes a block_header_t at the start of the new region to record its size, mark it as allocated, and set its free flag to false.

Parameters
[in]allocatorPointer to the allocator context.
[in]incSigned number of bytes to grow (or shrink) the heap.
Returns
Pointer to the previous program break (start of new region) on success; an error-encoded pointer (via PTR_ERR()) on failure.
Return values
(ret>=0)Previous heap end address (new region start).
-EINVALallocator is NULL.
-ENOMEMHeap expansion failed (out of memory).

◆ MEM_insertFreeBlock()

static int MEM_insertFreeBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block 
)
static

Inserts a block into the appropriate free list based on its size.

This function computes the size class index for the given block by calling MEM_getSizeClass(), then pushes the block onto the head of that free list within the allocator. It updates both forward and backward links to maintain the doubly‐linked list of free blocks.

Parameters
[in]allocatorPointer to the allocator context.
[in]blockPointer to the block header to insert.
Returns
Integer status code.
Return values
EXIT_SUCCESSblock successfully inserted.
-EINVALallocator or block is NULL.
-ENOMEMSize class calculation failed (request too large).

◆ MEM_mapAlloc()

static void * MEM_mapAlloc ( mem_allocator_t *const  allocator,
const size_t  total_size 
)
static

Allocates a page-aligned memory region via mmap and registers it in the allocator’s mmap list for later freeing.

This function rounds up total_size to a multiple of the system page size, invokes mmap() to obtain an anonymous read/write region, then allocates an mmap_t metadata node via MEM_allocOp() and links it into allocator->mmap_list. It initializes a block_header_t and trailing canary in the mapped region to integrate with the allocator’s debugging and GC.

Parameters
[in]allocatorPointer to the memory allocator context.
[in]total_sizeNumber of bytes requested.
Returns
On success, returns the address of the mapped region. On failure, returns an error-encoded pointer (via PTR_ERR()).
Return values
ret!=MAP_FAILEDAddress of the mapped region.
-EINVALallocator is NULL.
-EIOmmap() failed.
-ENOMEMAllocation of mmap_t metadata failed.

◆ MEM_mapFree()

static int MEM_mapFree ( mem_allocator_t *const  allocator,
void *const  addr 
)
static

Unmaps a previously mapped memory region and removes its metadata entry from the allocator’s mmap list.

This function searches the allocator’s mmap_list for an entry matching addr, calls munmap() to unmap the region, unlinks the corresponding mmap_t metadata node, and frees it via MEM_freeOp(). Errors during munmap are returned; if metadata freeing fails, an error is logged but success is returned.

Parameters
[in]allocatorMemory allocator context.
[in]addrAddress of the memory region to unmap.
Returns
Integer status code.
Return values
EXIT_SUCCESSRegion unmapped and metadata entry removed.
-EINVALallocator / addr is NULL, or not found in list.
-ENOMEMmunmap() failed to unmap the region.

◆ MEM_mergeBlocks()

static int MEM_mergeBlocks ( mem_allocator_t *const  allocator,
block_header_t block 
)
static

Merges adjacent free memory blocks.

This function removes the specified block from its free list, then checks its immediate neighbor blocks in memory. If the next block is free and valid, it unlinks and combines it with block, updating size, links, and trailing canary. It then checks the previous block; if it is also free and valid, it merges block into the previous block. Finally, the resulting merged block is reinserted into the appropriate free list.

Parameters
[in]allocatorPointer to the allocator context.
[in]blockPointer to the free block header to merge.
Returns
Integer status code.
Return values
EXIT_SUCCESSBlocks merged (or single block reinserted) successfully.
-EINVALallocator or block is NULL.
ret<0Returned by MEM_removeFreeBlock(), MEM_validateBlock(), MEM_insertFreeBlock(), or munmap() in inner calls indicating the specific failure.

◆ MEM_reallocOp()

static void * MEM_reallocOp ( mem_allocator_t *const  allocator,
void *const  ptr,
const size_t  new_size,
const char *const  file,
const int  line,
const allocation_strategy_t  strategy 
)
static

Reallocates memory with safety checks.

This function resizes an existing allocation to new_size bytes:

  • If ptr is NULL, behaves like malloc().
  • If the existing block is already large enough, returns the same pointer.
  • Otherwise, allocates a new block with the specified strategy, copies the lesser of old and new sizes, frees the old block, and returns the new pointer.
Parameters
[in]allocatorMemory allocator context.
[in]ptrPointer to the block to resize, or NULL to allocate.
[in]new_sizeNew requested size in bytes.
[in]fileSource file name for debugging metadata.
[in]lineSource line number for debugging metadata.
[in]strategyAllocation strategy to use.
Returns
Pointer to the reallocated memory region (which may be the same as ptr) on success; an error-encoded pointer (via PTR_ERR()) on failure.
Return values
ptrValid pointer to a block of at least new_size bytes.
-EINVALallocator is NULL, new_size is zero.
-ENOMEMOut of memory (allocation or free failure).
-EIOI/O error for large mmap-based allocations.

◆ MEM_removeFreeBlock()

static int MEM_removeFreeBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block 
)
static

Removes a block from its free list.

This function unlinks the specified block from the free list corresponding to its size class within the allocator. It computes the size‐class index via MEM_getSizeClass(), validates parameters, then adjusts the neighboring blocks’ fl_next and fl_prev pointers (or the list head) to remove block. The block’s own fl_next and fl_prev are then cleared.

Parameters
[in]allocatorMemory allocator context.
[in]blockBlock header to remove.
Returns
Integer status code.
Return values
EXIT_SUCCESSBlock removed successfully.
-EINVALallocator or block is NULL.
-ENOMEMSize‐class calculation failed.

◆ MEM_sbrk()

void * MEM_sbrk ( const intptr_t  increment)

Invokes sbrk-like behavior by moving the program break.

This function reads the current program break, attempts to move it by the signed offset increment via sbrk(), and returns the original break on success. If any call to sbrk() or reading the break fails, it encodes the negative errno into a pointer via PTR_ERR.

Parameters
[in]incrementSigned offset in bytes to move the program break: positive to grow, negative to shrink.
Returns
Original program break address on success; an error-encoded pointer (via PTR_ERR()) on failure.
Return values
ret>-1Previous break on success.
-ENOMEMFailed to read or adjust the break.

◆ MEM_splitBlock()

static int MEM_splitBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block,
const size_t  req_size 
)
static

Splits a memory block into allocated and free portions.

This function takes an existing free block and a requested allocation size req_size, and divides the block into:

  • an allocated portion of size aligned up to ALIGN(req_size) plus header and canary, marked as used;
  • a remaining free portion (if its size ≥ MIN_BLOCK_SIZE) inserted back into the appropriate free list. If the leftover space would be too small (< MIN_BLOCK_SIZE), the entire block is allocated without splitting.
Parameters
[in]allocatorPointer to the mem_allocator_t context.
[in]blockPointer to the block_header_t to split.
[in]req_sizeRequested allocation size in bytes.
Returns
Integer status code.
Return values
EXIT_SUCCESSBlock split (or fully allocated) successfully.
-EINVALnvalid allocator or block pointer.
-EPROTOHeader canary mismatch (block corrupted).
-EOVERFLOWData canary mismatch (buffer overflow detected).
-EFBIGBlock’s size would extend past heap end.
-EFAULTBlock lies outside heap or mmap regions.
-ENOMEMFailed to insert the new free remainder block.
Note
If the remaining space after splitting would be less than MIN_BLOCK_SIZE, this function allocates the entire block no split) and removes it from its free list.

◆ MEM_stackBounds()

static int MEM_stackBounds ( const pthread_t  id,
mem_allocator_t *const  allocator 
)
static

Query and record the bounding addresses of a thread’s stack.

This function retrieves the stack base address, total stack size, and guard size for the specified thread, then computes the usable stack bounds within the allocator object, taking into account whether the stack grows up or down in memory.

Parameters
[in]idThe thread identifier whose stack to inspect.
[in]allocatorPointer to the allocator object where stack_bottom and stack_top will be stored.
Returns
Integer status code.
Return values
EXIT_SUCCESSStack bounds successfully recorded.
-EINVALallocator was NULL.
ret>0Error code from one of the pthread or system calls

◆ MEM_stackGrowsDown()

static bool MEM_stackGrowsDown ( void  )
static

Determine at runtime whether the stack grows downward.

This function places two volatile local variables on the stack and compares their addresses to infer the growth direction:

  • If &addr_1 < &addr_0, the stack grows toward lower addresses.
  • Otherwise, it grows toward higher addresses.
Returns
true if stack grows down (higher addresses → lower), false if it grows up (lower addresses → higher)
Return values
trueStack grows downward (newer frames at lower addresses)
falseStack grows upward (newer frames at higher addresses)

◆ MEM_validateBlock()

static int MEM_validateBlock ( mem_allocator_t *const  allocator,
block_header_t *const  block 
)
static

Validates the integrity and boundaries of a memory block.

This function ensures that the specified block lies within the allocator’s heap or one of its mmap regions, that its header canary matches the expected magic value to detect metadata corruption, that its data canary is intact to catch buffer overruns, and that the block’s size does not extend past the heap’s end. On any failure, an appropriate negative errno is returned.

Parameters
[in]allocatorPointer to the allocator context.
[in]blockPointer to the block header to validate.
Returns
Integer status code.
Return values
EXIT_SUCCESSblock is valid.
-EINVALallocator or block pointer is NULL.
-EFAULTblock lies outside heap and mmap regions.
-EPROTOblock canary does not match expected value.
-EFBIGblock size causes it to extend past heap end.
-EOVERFLOWblock canary indicates buffer overflow.

Variable Documentation

◆ g_allocator

g_allocator
static

Process-wide default allocator instance.

Statically allocated allocator used when the API is called without an explicit mem_allocator_t handle. This instance is initialized exactly once (see g_allocator_inited) and then reused for all subsequent allocation requests routed through the “global” path.

Note
File-scope static grants internal linkage: the symbol is private to this translation unit.
Thread-Safety
Initialization must be synchronized so only one thread performs it (e.g., via pthread_once or equivalent). Normal allocator operations should rely on the allocator’s internal locking.
See also
MEM_allocatorInit(), MEM_allocOp(), MEM_free(), MEM_realloc()

◆ g_allocator_inited

g_allocator_inited = false
static

One-time initialization guard for g_allocator.

Boolean-like flag controlling lazy init of the global allocator. A value of 0 means “not initialized”; 1 means “initialized”. It should be set to 1 only after a successful call to MEM_allocatorInit(&g_allocator).

Warning
This flag is a plain int and is not atomic. In multi-threaded contexts, protect initialization with proper synchronization (e.g., pthread_once, a mutex, or atomic CAS) to avoid races.