Skip to content

feat: add stack guard pages so overflow faults instead of corrupting memory - #7

Merged
itsakeyfut merged 5 commits into
mainfrom
feat/stack-guard-pages
Jul 23, 2026
Merged

feat: add stack guard pages so overflow faults instead of corrupting memory#7
itsakeyfut merged 5 commits into
mainfrom
feat/stack-guard-pages

Conversation

@itsakeyfut

@itsakeyfut itsakeyfut commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

Give every fiber stack a no-access guard page below it, so a stack overflow faults cleanly (SIGSEGV / access violation) at the point of overflow instead of silently corrupting adjacent memory. (Phase C sub-project C3 — the robustness centerpiece.)

Changes

  • src/stack.zig — a guard-paged stack allocator. Linux: mmap the region read/write, then a raw mprotect turns the low page into a no-access guard; munmap frees it. Windows: NtAllocateVirtualMemory reserves the whole region and commits only the usable part, leaving the low guard page reserved-but-uncommitted (any access → access violation); NtFreeVirtualMemory releases it. @compileError on other targets — guard-paged stacks are x86_64 Linux/Windows only.
  • create/destroy now allocate/free the stack via stack.zig; the passed allocator backs only the small Fiber struct. reset is unchanged. min_stack_size is re-exported from root.zig.
  • Fault proof — a standalone overflow-probe exe overflows a guarded fiber; a test spawns it and asserts abnormal termination. The probe is fail-closed (any non-fault outcome exits 0, which the test treats as failure), so a setup error can never masquerade as a guard fault.
  • README + CHANGELOG updated.

Notes

The stack no longer uses the passed allocator, so the OOM test was reduced to the struct-allocation case. Fiber.stack.len is now page-rounded (≥ the requested stack_size). The Windows guard fault is verified locally; the Linux mmap/mprotect runtime and Linux guard fault are proven only by CI (ubuntu-latest).

Test Plan

  • zig build test passes across all four optimize modes locally (Windows), including the guard-fault test (the probe genuinely crashes on the guard page)
  • Linux compile verified by cross-compiling from Windows; zig build examples, zig fmt --check . pass
  • CI green (8-cell optimize matrix + fmt) — the ubuntu cells are the only runtime proof of the Linux guard page

New src/stack.zig maps a fiber stack with one no-access guard page immediately
below the usable region, so a stack overflow faults instead of silently
corrupting memory. Linux uses mmap + a raw mprotect syscall; Windows reserves
the whole region and commits only the usable part, leaving the guard page
reserved-but-uncommitted (any access faults). Supported on Linux and Windows;
compileError elsewhere.
create now allocates the stack via src/stack.zig (guard-paged) instead of the
passed allocator, which now backs only the Fiber struct; destroy frees it via
stack.zig. Revise the OOM test (the stack no longer uses the allocator, so only
the struct allocation can fail) and re-export min_stack_size from root.
Add a standalone overflow-probe exe that overflows a guarded fiber, and a test
that spawns it and asserts abnormal termination (a signal on POSIX, a non-zero
exit on Windows). The probe is fail-closed: any non-fault outcome exits 0, which
the test treats as failure, so a setup error cannot masquerade as a guard fault.
build.zig installs the probe and passes its path via FIBER_OVERFLOW_PROBE.
Consume the per-frame buffer after the recursive call so the frame must outlive
it, provably defeating tail-call optimization. Otherwise an optimized build could
turn the overflow recursion into a non-growing loop and the guard page would
never fault, silently invalidating the proof.
@itsakeyfut itsakeyfut self-assigned this Jul 23, 2026
@itsakeyfut
itsakeyfut merged commit 39a525a into main Jul 23, 2026
9 checks passed
@itsakeyfut
itsakeyfut deleted the feat/stack-guard-pages branch July 23, 2026 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant