Skip to main content
The kernel heap is a 1 MiB coalescing allocator that sits on top of a VMM-backed virtual address region. Every allocated block is protected by a header and footer canary so that out-of-bounds writes are detected immediately at the next allocation or free. Freed blocks are poisoned with a fixed byte pattern, causing any use-after-free to produce predictably wrong data rather than silently corrupting live state. The heap also tracks invalid-free attempts — passing an unrecognized pointer to kfree triggers a kernel panic rather than silently corrupting internal metadata.

Data Types

The heap_stats_t struct captures a snapshot of heap state at the moment heap_get_stats is called. Its definition from mvh/memory.h is:

Functions

heap_init

Initializes the kernel heap, maps the 1 MiB heap region through the VMM, and writes the initial free-block header. You must call this once, after both pmm_init and vmm_init, and before any call to kmalloc or kfree.
int
0 on success. A non-zero value indicates that the VMM could not map the heap region — this is a fatal condition and the kernel should halt.

kmalloc

Allocates at least size bytes from the kernel heap and returns a pointer to the first usable byte of the block. The allocator searches for the first free block large enough to satisfy the request (first-fit), splits it if the remainder is large enough to hold a minimum-sized free block, and writes canary values into the block header and footer before returning. Adjacent free blocks are coalesced eagerly during every allocation pass.
uint64_t
required
Number of bytes to allocate. Must be greater than zero. The allocator rounds this up internally to satisfy any alignment requirements. Passing 0 returns NULL.
void *
Pointer to the start of the allocated region on success. NULL if the allocation fails — either because no single free block is large enough (check largest_free_block in heap_stats_t) or because the heap has not been initialized. The pointer is always aligned to at least 8 bytes.
Every block returned by kmalloc carries a canary in both its header and footer. The canary is verified on every subsequent kmalloc and kfree call. If a write overflows the block and corrupts the footer canary, the corruption is detected at the next heap operation and the kernel panics with a diagnostic message — before the corrupted metadata can cause further damage.

kfree

Returns the block at address to the heap’s free pool. Before marking the block free, kfree verifies both the header and footer canaries; if either is corrupt the kernel panics immediately. After the canary check passes, the block’s payload is overwritten with a poison byte pattern so that any subsequent read through a stale pointer produces recognizable garbage rather than valid-looking data. Adjacent free blocks are then coalesced with the newly freed block.
void *
required
A pointer that was previously returned by kmalloc and has not yet been freed. Passing NULL is a no-op. Passing any other pointer that was not returned by kmalloc — including a pointer into the middle of an allocation, a stack pointer, or an already-freed pointer — triggers a kernel panic.
Passing an invalid pointer (one not returned by kmalloc, or one that has already been freed) to kfree triggers a kernel panic. There is no way to recover from this at runtime. Always pair every kmalloc with exactly one kfree, and set the pointer to NULL after freeing to prevent accidental double-free.

heap_total_bytes

Returns the total capacity of the kernel heap in bytes (always 1 MiB minus internal overhead for the heap’s own bookkeeping structures).
uint64_t
Total heap capacity in bytes.

heap_used_bytes

Returns the number of bytes currently held by live (non-freed) allocations, excluding block header/footer overhead.
uint64_t
Bytes currently in use by caller-allocated blocks.

heap_allocation_count

Returns the cumulative number of successful kmalloc calls since heap_init. This counter is never decremented by kfree.
uint64_t
Total number of successful allocations since initialization.

heap_get_stats

Fills the heap_stats_t structure pointed to by stats with a consistent snapshot of all heap counters and current block inventory. Use this for diagnostic output, memory-pressure monitoring, or assertions in test code.
heap_stats_t *
required
Pointer to a caller-allocated heap_stats_t struct. Must not be NULL. All fields are overwritten on return.
uint64_t
Total heap capacity in bytes.
uint64_t
Bytes currently held by live allocations (payload only, not including block metadata).
uint64_t
Bytes available for future allocations across all free blocks combined.
uint64_t
The size in bytes of the single largest contiguous free block. If kmalloc(size) returns NULL, compare size against this value to distinguish between total-heap-exhaustion and fragmentation.
uint64_t
Cumulative count of successful kmalloc calls since heap_init.
uint64_t
Cumulative count of kmalloc calls that returned NULL.
uint64_t
Cumulative count of kfree calls that received a pointer not recognized as a valid heap block. Each such call also panics, so in practice this counter will be at most 1 for any given boot.
uint32_t
Current total number of blocks tracked by the heap (both free and allocated).
uint32_t
Current number of free (coalesced) blocks. A large value relative to blocks indicates significant fragmentation.

heap_validate

Walks every block in the heap and verifies its header and footer canaries, the consistency of block sizes, and the integrity of the free-block list. Use this in test and debug builds to assert heap health at any point in time.
int
0 if the entire heap structure and all canaries are intact. Non-zero if any corruption is detected; the kernel serial log will contain a description of the first violation found.
Call heap_validate before and after any subsystem that performs a large number of allocations to quickly isolate which call site is causing corruption during development.

heap_self_test

Executes the heap’s built-in self-test suite. The tests cover single allocations, multiple simultaneous allocations, fragmentation and coalescing, boundary-size requests, and canary integrity. All blocks allocated by the test are freed before the function returns, leaving the heap in the same state as before.
int
0 if all self-test cases pass. Non-zero indicates the index of the first failing sub-test; check the kernel serial log for a human-readable description.
Run heap_self_test immediately after heap_init in debug builds to validate the allocator on every boot before any real allocations are made.

Usage Example

The following example demonstrates the standard kmalloc / kfree pattern alongside heap statistics inspection.