Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 91

Stack Overflow Detection Techniques

Recommended resources

Hello! Welcome to the next lesson in our "Advanced Debugging and System Profiling" module.

In our previous lesson, we conducted a "digital autopsy" on a crashed system by performing post-mortem analysis of a HardFault. We saw that a common cause for a tricky BusFault, indicated by the STKERR flag, is a stack overflow occurring during the exception entry itself. This is a reactive way of discovering a problem—after it has already happened.

Today, we shift from reaction to prevention. A robust embedded system should be able to detect and handle a stack overflow before it leads to silent data corruption or a catastrophic crash. This is a critical skill for building reliable systems and a frequent topic in interviews for senior embedded roles.

Your learning outcome for this lesson is to: Implement stack overflow detection using stack painting or MPU/MMU-based guard regions.

We will explore two primary techniques: a software-based method known as "stack painting" and a more robust hardware-based method using the Memory Protection Unit (MPU). We'll focus on their implementation, trade-offs, and when to choose one over the other.


1. Software-Based Detection: Stack Painting

The most straightforward way to monitor stack usage is through a software technique called stack painting or creating a software red zone.

The core idea is simple:

  1. Initialization: When a task is created, its entire stack memory is "painted" with a known magic value (e.g., 0xDEADBEEF).
  2. Monitoring: At runtime, a monitoring function (or the OS scheduler) checks how much of this painted area has been overwritten. It starts from the bottom of the stack and searches for the first location that no longer contains the magic value. This determines the "high water mark" of stack usage.
  3. Detection: If the painted values in a special "red zone" at the very end of the stack are overwritten, a stack overflow has occurred.
Stack Overflow Detection using Stack Painting in MCUXpresso IDE
This IDE screenshot illustrates stack painting. The memory view shows the unused portion of the stack filled with the 'DEADBEEF' pattern. A function then calculates the used space by seeing how much of the pattern has been overwritten, printing the result to the console.

This method is useful not only for detecting overflows but also for profiling and optimizing stack sizes during development.

Detecting Stack Overflows (Part 2 of 2)

The article 'Detecting Stack Overflows' by Jean Labrosse, a renowned expert in embedded systems, provides an excellent overview of various detection techniques. Let's start by reading about the software-based methods.

Read the sections titled 'Technique 4: Software-based RED zones' and 'Technique 5: Determining the actual stack usage at run-time'. Focus on: How a software red zone is created and checked. The concept of using a hook function (OSRedzoneHitHook()) to handle the detected overflow. The difference between a red zone for overflow detection and stack painting for usage profiling.

Pros and Cons of Stack Painting

This is a classic interview trade-off question. Given your experience, you can appreciate the system-level implications.

  • Pros:

    • Portability: It's pure software, so it works on any CPU architecture.
    • Simplicity: Relatively easy to implement in an RTOS or even for a bare-metal application's main stack.
    • Provides Usage Data: Excellent for development and testing to determine the high water mark and allocate just enough stack space.
  • Cons:

    • Not Real-Time: Detection is not instantaneous. An overflow might occur, corrupt other memory, and only be detected later when the check is performed (e.g., during a context switch). By then, the system state could be irreversibly damaged.
    • Can Be Bypassed: A large stack allocation within a single function call (e.g., char buffer[2048];) can "jump" over the red zone entirely, causing a massive overflow that goes undetected.
    • Runtime Overhead: The process of checking the stack consumes CPU cycles, which might be undesirable in highly loaded systems.


2. Hardware-Based Detection: MPU Guard Regions

For systems requiring immediate and guaranteed overflow detection, a hardware-assisted approach using the Memory Protection Unit (MPU) is superior. The MPU is a hardware block available on many Cortex-M processors that can enforce access rules on memory regions.

The strategy is to configure a "guard region" in the MPU—a small, no-access zone placed directly at the end of the stack.

Memory Protection Unit (MPU) in ARM Cortex-M
The MPU acts as a hardware guardian for memory. We can configure it to define regions for each task and, crucially, to create 'no-entry' zones like a stack guard region. An illegal access to such a region triggers an immediate hardware fault.

If any code attempts to write to this guard region (which is what happens during a stack overflow), the MPU will instantly block the access and trigger a MemManageFault exception. This stops the corruption before it happens.

This is the most robust method for stack overflow protection. Let's dive into a practical implementation.

Implementing an MPU Stack Guard

The Memfault Interrupt blog provides an excellent, code-heavy guide on using the MPU. We will use it to understand the exact steps needed to configure a stack guard.

Fix Bugs and Secure Firmware with the MPU - Memfault Interrupt

The article 'Fix Bugs and Secure Firmware with the MPU' gives a fantastic deep dive into MPU registers and provides a concrete example of catching a stack overflow. This is exactly the level of detail you'd be expected to know in a semiconductor company interview.

Please study the following sections carefully: 'MPU registers': Familiarize yourself with the key registers: MPU_CTRL (to enable), MPU_RBAR (Region Base Address), and MPU_RASR (Region Attribute and Size). Pay attention to the AP (Access Permissions) and SIZE fields in MPU_RASR. 'Enable MemManage Fault Handler': This is a critical prerequisite. An MPU violation triggers a MemManageFault, which must be enabled to be caught; otherwise, it escalates to a HardFault. 'Catch Stack Overflows with the MPU': This is the core implementation. Follow the code step-by-step to see how they: Find the end of the stack (__StackLimit). Calculate the base address for a 64-byte guard region, respecting alignment rules. Set MPU_RBAR to this address. Set MPU_RASR to define a 64-byte region with no access permissions (AP=0b000). Enable the MPU.

As the article demonstrates, once this is set up, a recursive function that overflows the stack no longer causes silent corruption or a delayed STKERR. Instead, it triggers a precise and immediate MemManageFault, allowing you to halt the system and debug the exact point of failure.

MPU Guard Regions in an RTOS

In a multi-tasking environment, this becomes more complex. Since each task has its own stack, the MPU guard region must be moved on every context switch to protect the stack of the task that is about to run. The Weston Embedded article you reviewed earlier discusses this in its sections on MPU techniques. The RTOS scheduler would be responsible for:

  1. Determining the stack limit of the incoming task.
  2. Updating the MPU_RBAR and MPU_RASR registers to place the guard region at the end of that specific stack.

This adds a small overhead to the context switch but provides unparalleled safety.

Pros and Cons of MPU Guard Regions

  • Pros:

    • Instantaneous Detection: The fault is triggered by the hardware on the exact instruction that overflows, preventing any memory corruption beyond the stack boundary.
    • Zero CPU Overhead (during operation): Once configured, the MPU operates in parallel with the CPU. There are no software checks consuming cycles.
    • Highly Robust: It cannot be bypassed by large stack allocations, as any write into the protected region will be caught.
  • Cons:

    • Hardware Dependent: Requires an MPU, which may not be present on all microcontrollers (especially lower-end ones).
    • Configuration Complexity: Requires careful, low-level programming of CPU-specific registers.
    • Resource Limitation: MPUs have a finite number of configurable regions (typically 8 or 16). In a complex system, these regions are a valuable resource needed for other protections (e.g., protecting peripherals, creating read-only memory).
    • Alignment/Size Constraints: MPU regions often have strict rules, such as sizes being a power of two and base addresses being aligned to the region size. This can lead to wasted memory.


3. Summary and Interview Preparation

Understanding these two techniques and their trade-offs is crucial. An interviewer is likely to ask a question like:

"You are designing a safety-critical automotive system, and you need to prevent stack overflows. What methods would you consider, and how would you choose between them?"

Your answer should demonstrate knowledge of both software and hardware methods, leading to a conclusion like this:

Feature Stack Painting / Software Red Zone MPU Guard Region
Detection Time Delayed (at next check) Instantaneous (at moment of overflow)
Robustness Low (can be bypassed) High (guaranteed catch)
Overhead CPU cycles for checking MPU hardware (no CPU cycles)
Prevents Corruption? No, detects it after the fact Yes, stops the write from occurring
Implementation Simple, portable software Complex, hardware-specific register config
Primary Use Case Development, profiling, non-critical systems Production, real-time, safety-critical systems

For a safety-critical system, the MPU method is the clear choice due to its robustness and immediate, preventative nature, despite its complexity. Stack painting remains a valuable tool for development and for systems without an MPU.



Conclusion

In this lesson, you've learned how to proactively implement two powerful mechanisms for detecting stack overflows. You can now distinguish between the software-based stack painting method, which is excellent for profiling, and the hardware-based MPU guard region method, which offers robust, real-time protection for critical systems.

Key Takeaways:

  • Stack Painting involves filling the stack with a magic value to monitor its high water mark and detect overflows when a red zone is corrupted. It's portable but not real-time.
  • MPU Guard Regions use hardware to define a no-access memory zone at the end of the stack. An overflow triggers an immediate MemManageFault, preventing corruption. It's the most robust method but requires hardware and careful configuration.
  • The choice between these methods is a classic engineering trade-off between portability, performance, and robustness, making it a prime topic for technical interviews.

Preview of the Next Lesson:

We've focused on stack issues common in bare-metal and RTOS environments. Many complex embedded systems, however, run Linux. In our next lesson, we will move up the software stack to explore powerful tools for debugging memory issues in user-space applications: Detect memory bugs in user-space applications using Valgrind or AddressSanitizer (ASan).