# K06 — MemoryResource and FreeRtosAllocator ## Position - Series: FreeRTOS C++ - Lesson: L05, card K06 - Duration: 30 minutes - Runtime: FreeRTOS `heap_4.c` plus a 256-byte `.bss` arena on Hazard3 - C++ mode: freestanding C++17, no exceptions, RTTI, vtables or hosted allocator K05 selected and measured one kernel heap. K06 adds an explicit runtime resource boundary so identical typed code can use either that heap or caller owned static storage. ## Outcome After 30 minutes the student can draw the three-word resource object, explain why it is not virtual inheritance, implement overflow-safe `count*sizeof(T)`, classify addresses by storage domain, and state the different release policies of a general heap and monotonic arena. ## Lesson plan — 30 minutes | Time | Mode | Evidence | | --- | --- | --- | | 0–5 | contract | draw context + allocate/deallocate functions | | 5–10 | typed count | complete and justify the overflow guard | | 10–16 | two resources | allocate 16 `uint32_t` values from heap and arena | | 16–21 | address proof | classify `ucHeap` versus `.bss`; check alignment | | 21–26 | failure | overflow and capacity failures change no storage state | | 26–30 | release | compare heap free, arena no-op deallocate and reset | ## Runtime dispatch without vtable ```cpp struct MemoryResource { void* context; void* (*allocate)(void*, size_t, size_t) noexcept; void (*deallocate)(void*, void*, size_t, size_t) noexcept; }; ``` The provider owns state; the view stores a non-owning context. `HeapResource` counts attempts and delegates to FreeRTOS. `StaticArenaResource` stores base, capacity and current offset. The ELF must have no vtable/typeinfo. ## Typed overflow contract For `T` and `count`: ```text count == 0 -> nullptr count > SIZE_MAX / sizeof(T) -> nullptr, resource not called otherwise bytes=count*sizeof(T) -> resource.allocate(bytes, alignof(T)) ``` The failure must not wrap to a small allocation. Both resource counters and storage state are captured before and after the overflow request. ## Canonical experiment ```text HeapResource --MemoryResource--> FreeRtosAllocator -> 16 values address inside ucHeap; deallocate -> baseline immediately StaticArenaResource --MemoryResource--> same typed allocator -> 16 values address inside g_static_arena_storage (.bss) deallocate -> used remains 64 reset -> used becomes 0 ``` Both addresses satisfy `address % alignof(uint32_t) == 0` and both buffers produce the predicted sums. ## Stable evidence | Evidence | Required relation | | --- | --- | | resource representation | context and function pointers are non-null; allocate functions differ | | heap address | lies inside `ucHeap`, aligned for `uint32_t` | | arena address | lies in global arena range, outside `ucHeap`, aligned | | overflow | both return null before provider failure counters increase | | capacity failure | heap available and arena used remain unchanged | | heap policy | successful=1, failed=1, deallocations=1; final free=baseline | | arena policy | successful=1, failed=1; used 64 after deallocate, 0 after reset | ## Main traps 1. Multiply only after the division guard; detecting overflow after wrapping is too late. 2. A resource view does not own its context; provider lifetime must dominate. 3. Arena `deallocate` is not heap free. Reset invalidates all arena allocations at once and therefore needs an external lifetime boundary. 4. An alignment greater than the provider guarantee must fail explicitly. 5. This fallible allocator is not ordinary `new` and is not advertised as a complete hosted/STL allocator. ## Acceptance - host ASan/UBSan test validates alignment, overflow and no-op/reset behavior; - `MemoryResource` occupies three pointers and all resource classes are non-polymorphic; - ABI has no vtable, RTTI, unwind, dynamic initializer or global new/delete; - Hazard3 proves two storage domains and identical 16-element operations; - all failure and release relations pass at checkpoint 7.