zephyr-cp: don't build the heap control structure in an undersized region - #11230
Open
mikeysklar wants to merge 1 commit into
Open
zephyr-cp: don't build the heap control structure in an undersized region#11230mikeysklar wants to merge 1 commit into
mikeysklar wants to merge 1 commit into
Conversation
…gion tlsf_create_with_pool() forwards its max_bytes argument to tlsf_create(), so control_construct() dimensions the control structure from the maximum heap size and checks that maximum against itself, not against the region it is writing into. A region too small for the structure is overrun rather than rejected. On a SiWx917-DK2605A the port skips the large SRAM region because Zephyr's malloc arena owns it (CONFIG_COMMON_LIBC_MALLOC with ARENA_SIZE=-1), leaving a 1 KB DMA buffer as the first candidate. With circuitpy_max_ram_size of 8 MB the control structure is 2412 bytes, so it overran that region by 1388 bytes. Require the region that hosts the control structure to be at least 8 KB, and handle tlsf_create_with_pool() returning NULL by moving to the next region instead of leaving heap NULL for the first allocation to trip over. The bound applies only to the region hosting the control structure. Region order is unchanged and smaller regions are still eligible as additional pools, so boards whose first region already works are unaffected.
mikeysklar
force-pushed
the
zephyr-heap/tlsf-largest-region
branch
from
August 23, 2026 02:03
b3fafd4 to
fa10182
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
tlsf_create_with_pool()can write TLSF's control structure past the end of theregion it is given. This makes
port_heap_init()skip a region that is toosmall to host it instead of handing it over.
Why
tlsf_create()passes that argument tocontrol_construct(), which dimensionsthe control structure from it and performs both of its size checks against it.
So the checks test the maximum heap size, not the space actually available in
mem. Whenport_heap_init()calls this withcircuitpy_max_ram_sizeand asmall region, the structure is sized for the maximum and written into the small
region.
On a SiWx917-DK2605A the port skips the large SRAM region because Zephyr's
malloc arena owns it (
CONFIG_COMMON_LIBC_MALLOCwithARENA_SIZE=-1), so thefirst candidate is a 1 KB DMA buffer:
With an 8 MB maximum the control structure is 2412 bytes, so it overran that
1 KB region by 1388 bytes. Measured on the board:
heap = 0x24061c00andtlsf_get_pool(heap) = 0x2406256c, a difference of0x96c= 2412.Scope of the change
The bound applies only to the region that hosts the control structure:
size < 1024guard is unchanged, so smaller regions are stilleligible as additional pools.
sees no behavioural change at all.
The only boards affected are those where the current code would overrun the
region, which it does silently today.
How to reproduce
Flash, attach, and read the heap state. No test program needed:
Before:
heapis inside the 1 KB DMA buffer, andpools[2] = 0x4is the NWP-reservedregion. After:
The control structure is in the 8 MB PSRAM region.
Hardware tested
Two SiWx917-DK2605A boards (Zephyr board
siwx917_dk2605a, SoCSiWG917M111MGTBA), one on macOS 15 and one on Ubuntu 24.04, each with its own
J-Link. Built on top of the board definition from #11218, which is not yet
merged.
heap=0x24061c00heap=0x0a000000heap=0x24061c00heap=0x0a000000Board B's unpatched image was also caught halted in
arch_system_haltwithreason=4(K_ERR_KERNEL_PANIC), reached fromport_heap_init()viatlsf_add_pool()for the PSRAM region. That panic is not reliably reproducible;the heap layout above is, on both boards.
Not tested on any other zephyr-cp board. I do not have the vendor blobs to build
the NXP or STM32 targets locally, which is part of why the change is scoped as
narrowly as it is.
Scope
8 KB is a round number comfortably above the 2412-byte structure measured here;
it is not computed from
tlsf_size(), which needs an already-constructedinstance. Keeping the NWP-reserved and DMA regions out of the heap entirely is a
separate board-level concern and is not addressed here.
AI assistance
Written with Claude Code. I ran the before/after captures above myself on the
hardware listed.