Skip to content
This repository was archived by the owner on Jan 24, 2022. It is now read-only.
This repository was archived by the owner on Jan 24, 2022. It is now read-only.

(Zero cost) stack overflow protection #34

Closed
@japaric

Description

@japaric

Today, the layout of RAM looks like this (assuming no heap and a single RAM region):

today

With this layout when a stack overflow occurs static variables end up being overwritten /
corrupted silently.

This scenario can be avoided by simply changing the memory layout to look like this:

ideal

In this new scenario a stack overflow will hit the lower RAM boundary. Trying to write beyond the
RAM boundaries raises a HardFault exception. Thus, in theory, the HardFault exception handler
could be used as a stack overflow handler.

In systems where heap memory, which by default starts where the static region ends and grows
upwards, exists a similar reordering of the regions can be applied.

Implementation

To my knowledge this can't be implement using only linker scripts. With a linker script you can
instruct the linker where to start a memory region but you can't specify the end address of the
region.

The related bits of the linker script we use are shown below:

PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));

SECTIONS
{
  /* .. */
  .bss : ALIGN(4)
  {
    _sbss = .;
    *(.bss .bss.*);
    . = ALIGN(4);
    _ebss = .;
  } > RAM

  .data : ALIGN(4)
  {
    _sidata = LOADADDR(.data);
    _sdata = .;
    *(.data .data.*);
    . = ALIGN(4);
    _edata = .;
  } > RAM AT > FLASH

  /* The heap starts right after the .bss + .data section ends */
  _sheap = _edata;

  /* .. */
}

A C implementation of this region reordering uses a two step linking process. See
this StackOverflow answer for details.

Other options for stack overflow protection

Assuming that we can't change the memory layout. We could:

  • Use the MPU (Memory Protection Unit) to mark the upper boundary of the static region as
    read-only. In this scenario when a stack overflow occurs a MemManage exception is raised. This has
    an initialization cost but no runtime cost. The downside is that not all microcontrollers have a
    MPU.

  • Implement stack probes for the Cortex-M targets. I believe enabling stack probes carries a runtime
    cost (per function call?) but I'm not sure.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions