Stack Overflow Protection
The firmware
crate in which we developed our advanced workshop solutions (i.e. advanced/firmware
) uses our open-source flip-link
tool for zero-cost stack overflow protection.
This means that your application will warn you by crashing if you accidentally overreach the boundaries of your application's stack instead of running into undefined behavior and behaving erratically in irreproducible ways. This memory protection mechanism comes at no additional computational or memory-usage cost.
🔎 For a detailed description of how flip-link
and Stack Overflows in bare metal Rust in general work, please refer to the flip-link
README.
You can see this in action in the stack_overflow.rs
file that can be found in advanced/firmware/src/bin/
:
#![no_main] #![no_std] use cortex_m::asm; use cortex_m_rt::entry; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; #[entry] fn main() -> ! { // board initialization dk::init().unwrap(); fib(100); loop { asm::bkpt(); } } #[inline(never)] fn fib(n: u32) -> u32 { // allocate and initialize one kilobyte of stack memory to provoke stack overflow let use_stack = [0xAA; 1024]; defmt::println!("allocating [{}; 1024]; round #{}", use_stack[1023], n); if n < 2 { 1 } else { fib(n - 1) + fib(n - 2) // recursion } }
The spam()
function allocates data on the stack until the stack boundaries are reached.
✅ Run stack_overflow.rs
You should see output similar to this (the program output between the horizontal bars might be missing):
(HOST) INFO flashing program (35.25 KiB)
(HOST) INFO success!
────────────────────────────────────────────────────────────────────────────────
INFO:stack_overflow -- provoking stack overflow...
INFO:stack_overflow -- address of current `use_stack` at recursion depth 0: 0x2003aec0
INFO:stack_overflow -- address of current `use_stack` at recursion depth 1: 0x20039e50
(...)
INFO:stack_overflow -- address of current `use_stack` at recursion depth 10: 0x20030a60
INFO:stack_overflow -- address of current `use_stack` at recursion
────────────────────────────────────────────────────────────────────────────────
stack backtrace:
0: HardFaultTrampoline
<exception entry>
(HOST) WARN call stack was corrupted; unwinding could not be completed
(HOST) ERROR the program has overflowed its stack
❗️ flip-link
is a third-party tool, so make sure you've installed it through cargo install flip-link
To see how we've activated flip-link
, take a look at advanced/firmware/.cargo/config.toml
:
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# (..)
rustflags = [
"-C", "linker=flip-link", # adds stack overflow protection
"-C", "link-arg=-Tdefmt.x", # defmt support
# (..)
]
There, we've configured flip-link
as the linker to be used for all ARM targets.
If you'd like to use flip-link
in your own projects, this is all you need to add!
🔎 Note: if you try to run stack_overflow.rs
without flip-link
enabled, you might see varying behavior depending on the rustc
version you're using, timing and pure chance. This is because undefined behavior triggered by the program may change between rustc
releases.