rust-embedded/rust-raspberrypi-OS-tutorials · critical

Allocation error: {:?}

Error message

Allocation error: {:?}

What it means

This is the kernel's #[alloc_error_handler]: it panics when a heap allocation via the GlobalAlloc/HeapAllocator fails (e.g. alloc returns null). In this no_std kernel there is no unwinding, so an OOM allocation aborts via panic with the requested Layout printed. It means the kernel heap (a fixed static pool) is exhausted or the requested size is invalid/too large.

Source

Thrown at 20_timer_callbacks/kernel/src/memory/heap_alloc.rs:67

        {}",
        operation,
        size,
        size_h,
        size_unit,
        addr,
        addr + size,
        backtrace::Backtrace
    );
}

//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
use synchronization::interface::Mutex;

#[alloc_error_handler]
fn alloc_error_handler(layout: Layout) -> ! {
    panic!("Allocation error: {:?}", layout)
}

/// Return a reference to the kernel's heap allocator.
pub fn kernel_heap_allocator() -> &'static HeapAllocator {
    &KERNEL_HEAP_ALLOCATOR
}

impl HeapAllocator {
    /// Create an instance.
    pub const fn new() -> Self {
        Self {
            inner: IRQSafeNullLock::new(LinkedListHeap::empty()),
        }
    }

    /// Print the current heap usage.
    pub fn print_usage(&self) {
        let (used, free) = KERNEL_HEAP_ALLOCATOR

View on GitHub (pinned to 644474cc09)

Solutions

  1. Increase the kernel heap size in the heap allocator configuration/pool definition.
  2. Audit allocations for leaks (especially per-tick/per-interrupt paths that never drop).
  3. Handle allocation failure at call sites with fallible APIs (try_reserve, checked constructors) instead of infallible Box/Vec.
  4. Check that the heap is initialized before any allocation happens during boot.
  5. Reduce allocation size or reuse buffers; the panic prints the Layout — use it to find the oversized request.

Example fix

// before
let buf = Vec::with_capacity(user_size);
// after
let mut buf = Vec::new();
buf.try_reserve_exact(user_size).map_err(|_| "heap exhausted")?;
Defensive patterns

Strategy: validation

Validate before calling

fn can_allocate(heap_free: usize, layout: core::alloc::Layout) -> bool {
    layout.size() <= heap_free && layout.align().is_power_of_two()
}

Type guard

fn layout_is_reasonable(layout: core::alloc::Layout, max: usize) -> bool {
    layout.size() > 0 && layout.size() <= max
}

Try / catch

// alloc_error_handler cannot be caught; use fallible APIs:
if let Err(e) = vec.try_reserve(n) {
    log::error!("alloc failed: {:?}", e);
    return Err(OutOfMemory);
}

Prevention

When it happens

Trigger: Allocating (Box, Vec, BTreeMap, Arc, etc.) after the fixed-size kernel heap is full; requesting a Layout whose size/align exceeds the largest supported or pool size; a leak accumulating until exhaustion; allocating before heap init in early boot.

Common situations: Unbounded Vec growth in an interrupt/exception handler that never frees; a leaked allocation per timer tick in this timer-callback kernel; heap pool configured too small for the workload; allocating a huge buffer from user-controlled size.

Related errors


AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06). Data as JSON: /api/errors/7365a4eb3c167368. Report an issue: GitHub.