Skip to main content

SHADOW_STACK_SLOTS

Constant SHADOW_STACK_SLOTS 

Source
pub const SHADOW_STACK_SLOTS: usize = _; // 728_192usize
Expand description

The size of the one shadow-stack reservation, in slots.

Exhaustion is unrepresentable, not handled. One fact bounds the stack, and since ADR-105 it bounds it exactly rather than through a product of two independent worst cases:

  • every generated prologue rejects stack_left < frame_cost(slots) before it pushes anything. A context starts with at most STACK_BUDGET_BYTES — [StackBudget] refuses to make a larger one — and a frame spends at least FRAME_BYTES_BASE, so there are at most MAX_RECURSION_DEPTH live frames; and it spends FRAME_BYTES_PER_SLOT on every slot past REFERENCE_FRAME_SLOTS, so those slots number at most STACK_BUDGET_BYTES / FRAME_BYTES_PER_SLOT. Adding the two: live slots are bounded by budget / FRAME_BYTES_PER_SLOT + MAX_RECURSION_DEPTH × REFERENCE_FRAME_SLOTS.

Reserving that — plus one frame of headroom for the Rust-side push_frame callers, which spend no budget and so are not covered by the argument — means there is no inline bounds check in the prologue, because there is nothing left to check. That is one branch removed from the hottest path in the language.

Sizing this as MAX_RECURSION_DEPTH * MAX_SHADOW_SLOTS would multiply “the deepest recursion” by “the widest frame” as if a program could have both at once. It cannot, and the guard is what says so: a maximum-width frame spends FRAME_BYTES_BASE + 2 × (MAX_SHADOW_SLOTS − REFERENCE_FRAME_SLOTS) bytes, so a stack of them runs out of budget at 2452 frames, not 8000. The reservation is therefore 5.56 MiB of virtual address space per Runtime. SlotStack::new allocates it zeroed, which is an mmap of fresh zero pages: resident memory tracks how deep the program actually recurses, not how deep it is allowed to.