4.0 KiB
K06 — MemoryResource and FreeRtosAllocator
Position
- Series: FreeRTOS C++
- Lesson: L05, card K06
- Duration: 30 minutes
- Runtime: FreeRTOS
heap_4.cplus a 256-byte.bssarena 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
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:
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
HeapResource --MemoryResource--> FreeRtosAllocator<uint32_t> -> 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
- Multiply only after the division guard; detecting overflow after wrapping is too late.
- A resource view does not own its context; provider lifetime must dominate.
- Arena
deallocateis not heap free. Reset invalidates all arena allocations at once and therefore needs an external lifetime boundary. - An alignment greater than the provider guarantee must fail explicitly.
- This fallible allocator is not ordinary
newand is not advertised as a complete hosted/STL allocator.
Acceptance
- host ASan/UBSan test validates alignment, overflow and no-op/reset behavior;
MemoryResourceoccupies 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.