eheap has several interesting features that help to find usage errors, tune performance, and improve resiliency.
Direct eheap Calls
eheap code can be called directly if only a single task uses the target heap. It is the heap, itself, that must be protected from reentrancy, not the code. Direct access improves performance, especially for partitions written in C++ that are using the integrated block pools [Ref 2]. In the diagram, eheap code has been put into ucom_code so that it can be directly accessed by App1 and App2. The red line illustrates that it can also be directly accessed from pmode. This is possible if App3 has the ucom_code region in its MPA. xheap can access eheap if ucom_code is included in the sys_code region.
Scans
The heap and its bins can be scanned with:
eh_Scan (CCB_PTR cp, u32 fnum, u32 bnum, u32 hn=0)
eh_BinScan (u32 binno, u32 fnum, u32 bnum, u32 hn=0)
For eh_Scan(), cp is the chunk pointer at which to begin a heap scan, fnum is the number of chunks to scan forward, each time, in order to check for breaks, bnum is the number of chunks to scan backward, each time, in order to repair a break, and hn is the heap number. bnum is usually much larger than fnum in order to achieve speedy repairs. eh_Scan() is normally called from the idle task to process a few chunks, at a time. For eh_BinScan(), binno is the bin to scan and fnum, bnum, and hn are the same as for the eh_Scan.
Heap and bin linkage breaks are rare unless there is a latent bug or malware causing them. Consequently scans can progress slowly, as little as one chunk at a time. However, scanning more frequently increases the likelihood that a break will be fixed before it causes a problem. See Ref 1 for more discussion of heap scan and repair.
Fill Mode
Sometimes there is no alternative but to look directly at the heap via the debugger memory window in order to track down a heap usage bug. eheap has a fill mode, in which unique patterns are used to fill different kinds chunks. Fill mode is selective, like debug mode [Ref 3], so it can be applied only to chunks of interest. The heap fill patterns are as follows:
EH_DATA_FILL 0xDDDDDDDD
EH_FREE_FILL 0xEEEEEEEE
EH_FENCE_FILL 0xAAAAAAA3
EH_DTC_FILL 0xCCCCCCCC
When fill mode is on:
- The data blocks of inuse and debug chunks are filled with EH_DATA_FILL when they are allocated. After a data block has been in use, the remaining fill shows how much of a data block has actually been used. This helps to decide if to resize it.
- Fences in debug chunks are filled with EH_FENCE_FILL to show overflow patterns and to help delineate data blocks.
- The free space of a free chunk is filled with EH_FREE_FILL when the chunk is freed.
- During initialization, DC and TC[1] are filled with EH_DTC_FILL and when a chunk is released to DC or TC it is filled with EH_DTC_FILL. This helps to decide if DC or TC should be resized.
Having different fills enables easily identifying chunks types. However, filling reduces performance and is not recommended for release. Since it is selective, it is helpful for debugging heap problems in new code without impacting the operation of other parts of a system.
Heap Statistics
The following heap statistics are accumulated per heap:
- hhwm Heap high water mark for number of bytes allocated.
- hused Number of bytes of currently allocated.
- bnum[] Number of chunks in each bin.
- bsum[] Sum of chunk sizes in each bin.
These can be viewed through a debugger watch window. hhwm is useful to decide if the heap size should be increased or decreased. The bin statistics are useful to achieve optimum bin structures.
Error Checks
As a further aid for debugging and to improve system reliability, all heap service parameters are checked and invalid parameters are reported. In most cases, services abort if an invalid parameter is found. eheap has a 3-level error reporting system:
- none
- all but allocation and free
- all
During debugging, error reporting level 2 is recommended. It is also recommended to put a breakpoint at the start of eh_error() in order to catch heap errors the moment they occur. Then, the call stack window can be used to pinpoint the cause of the error. Using eheap built-in error detection can save wasted debug time chasing what appear to be application errors, while, in fact, they are just heap utilization errors.
Peeking
Two peek functions are provided:
eh_ChunkPeek(cp, par, hn)
eh_BinPeek(binno, par, hn)
The first returns information selected by par for the chunk selected by cp in heap hn. This includes information such as chunk type, previous chunk, next chunk, chunk owner, chunk size, time allocated, bin number, etc. as appropriate for the chunk type. The second returns information defined by par for the bin selected by binno in heap hn. This includes information such as number of chunks in the bin, first, last, minimum size, and total free space. These functions are useful to watch heaps in action with system monitoring software in order to detect anomalies that might indicate malware breaches or latent bugs.
Auto Recovery
Auto recovery is enabled by the auto_rec flag in an eheap variable array, EHV. If an allocation fails when auto_rec is set, eh_Recover() is automatically called to search the heap for adjacent free chunks that can be combined to satisfy the request for the allocation. If found, the free chunks are removed from their bins, merged, and the resulting chunk put into the bin for its size, DC, or TC, as appropriate. Then EH_RECOVER is reported and the allocation is retried. Auto recovery provides a bailout if chunk merging has been disabled for too long.
Heap Extension
If auto recovery fails, the heap can be extended into reserve memory using:
eh_Extend(xsz, xp, hn)
where xsz is the size of the extension, xp is its location, and hn is the heap number. The extension may be adjacent to the present heap or elsewhere above the current heap in memory. If there is a gap, it is covered by an artificial inuse chunk and the extension becomes the new TC. If there is no gap, the extension is added to the current TC.
A heap extension might be to slower memory, in which case, access to chunks in the extension would be slower, but that is better than a system failure. The need for heap extension might occur when operating with debug chunks, due to their larger size; it might not occur in the released system using only inuse chunks. If it did, performance might suffer for only a few unlucky tasks. Requesting blocks aligned on cache-lines would improve data block access times if in DRAM.
Reserve memory could also be memory that is available in some systems and not in others. For example, the system used for debugging might have more memory than production systems. In this case, if no reserve memory is used after long runs it could be assumed that production systems have enough memory.
Bin Seed
Without a boost, heap bins may be slow to start operating. This function can be used to get them going sooner:
eh_BinSeed(u32 num, u32 bsz, u32 hn)
Where num is the number of blocks of bsz bytes to add to the bin determined by bsz. During initialization, this function can be called for each important block size in order to get bins off to a faster start.
Large Bin Sort
Large bin sort is done during idle by:
eh_BinSort(binno, fnum, hn)
where binno is the bin to sort, fnum is the number of chunks to process, and hn is the heap number. Bin sorting is necessary only for large bins. It can improve their performance considerably.
The bin sort map, bsmap, determines which bin to sort next. eh_Free() puts a chunk at the start of a bin free list if it is smaller than the first chunk in the list. Otherwise, it is put at the end of the bin free list and the bin’s bsmap flag is set. When the bin sort is started, the flag is reset. Since sorting is incremental, it is possible that eh_Free() will put another chunk at the end of the bin free list while it is being sorted. If so, the bsmap flag is set and the sort starts over. Starting over is not detrimental, because the sorting already done is preserved. Otherwise each run starts from where the last run left off.
The sort algorithm is bubble sort with last-turtle insertion. It the last chunk in a bin free list is smaller than some chunk ahead of it, it is called a “turtle” because it moves forward very slowly in a bubble sort. Last-turtle insertion fixes this problem by inserting the last turtle ahead of the first larger chunk found and the chunk that was ahead of the last turtle becomes the new last turtle. A full sort requires multiple passes through a bin free list. A bin sort is done when no chunks have been moved during a complete pass through the bin free list.
Conclusion
eheap has many special features to aid debugging, increase heap resiliency, and optimize heap performance in embedded systems. The is the last article in this series. The full source code for eheap can be found in eheap.c and eheap.h at www.github.com/Micro-Digital/SecureSMX.
References
- “eheap Part 1: Basics”, LinkedIn, Ralph Moore, April 2026.
- “eheap Part 3: Allocations”, LinkedIn, Ralph Moore, May 2026.
- “eheap Part 4: Chunks”, LinkedIn, Ralph Moore, May 2026.
Notes
[1] Donor Chunk and Top Chunk, see Ref 2.