Search topics...
Boot & StartupStack & Heapfoundational

What happens if the stack and heap collide, and how can you prevent it?

0 upvotes
Practice with AISoon
Study the fundamentals first — Boot & Startup topic page

On most bare-metal Cortex-M systems, the stack grows downward from the top of RAM and the heap grows upward from the end of .bss. If neither has a hard boundary enforced in hardware, they grow toward each other, and when they meet, they silently overwrite each other's data. The stack corrupts heap metadata (free-list pointers, block headers), causing malloc to return invalid pointers or crash on the next allocation. The heap corrupts stack frames (return addresses, saved registers, local variables), causing functions to return to random addresses or operate on garbage data. There is no automatic fault or exception — on Cortex-M0 and M3 without MPU configuration, the corruption is completely silent until it causes a secondary failure, often far removed in time and code location from the actual collision.

The debugging difficulty is extreme because the symptoms appear random: a function returns to a wrong address (hard fault with a nonsensical PC value), a local variable changes value between two sequential reads, or malloc returns a pointer inside the stack region. These symptoms may only appear under specific load conditions (maximum interrupt nesting + maximum heap allocation simultaneously) and may vanish when debugging because the debugger's halt-and-inspect cycle changes the timing.

Prevention strategies, in order of effectiveness: (1) MPU guard regions — on Cortex-M3/M4/M7, configure MPU regions as no-access barriers between the stack bottom and heap top. A collision immediately triggers a MemManage fault with a precise address, making the bug trivially diagnosable. (2) Static allocation — eliminate the heap entirely by using fixed-size arrays and memory pools. If heap size is zero, collision is impossible and the only risk is stack overflow (which is easier to detect alone). (3) Linker script enforcement — define explicit _Min_Heap_Size and _Min_Stack_Size in the linker script so the linker fails the build if the sum of all sections exceeds RAM. This catches the problem at build time, though it relies on the engineer choosing correct size values. (4) Runtime monitoring — periodically check the stack pointer against a minimum threshold and the heap high-water mark against a maximum threshold, asserting or logging if either crosses the safety boundary.

Source: Boot & Startup Q&A