Skip to content

feat: validate minimum stack size and guard destroy against a running fiber - #6

Merged
itsakeyfut merged 3 commits into
mainfrom
feat/input-validation-hardening
Jul 23, 2026
Merged

feat: validate minimum stack size and guard destroy against a running fiber#6
itsakeyfut merged 3 commits into
mainfrom
feat/input-validation-hardening

Conversation

@itsakeyfut

@itsakeyfut itsakeyfut commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

Harden the API against two misuse cases that previously led to silent memory corruption or UB: a stack size too small to hold a fiber, and destroying a running fiber. Pure Zig — no assembly changes. (Phase C sub-project C1.)

Changes

  • Minimum stack sizepub const min_stack_size = 4096 (one page). create now returns error.StackTooSmall when options.stack_size < min_stack_size, checked before any allocation. A too-small stack previously made initStack write past the low end of the allocation (~280 bytes of setup frame on Windows) and silently corrupt the heap. The error is additive to create's inferred error set — no existing caller passes a sub-page stack, so nothing breaks.
  • destroy guardstd.debug.assert(self.state != .running); freeing the stack of a running fiber is UB. .ready/.suspended/.done remain valid to destroy.
  • Documented preconditions — doc comments on create, destroy, resumeFiber, and yield stating the state contract the debug asserts enforce.
  • README API table + CHANGELOG updated.

Notes

Out of scope (later sub-projects): a runtime guard page for overflow detection is C3 — min_stack_size guards setup, not a fiber overrunning its stack while running. In ReleaseFast/ReleaseSmall the asserts are compiled out (standard Zig contract for misuse guards); Debug and ReleaseSafe (both in CI) keep them.

Test Plan

  • zig build test passes across all four optimize modes locally (Windows)
  • zig build examples, zig fmt --check . pass
  • New tests: sub-minimum sizes rejected (with a FailingAllocator proving the check precedes allocation); the minimum size runs a fiber to .done
  • CI green (8-cell optimize matrix + fmt gate)

A stack_size below the initial setup frame made initStack write past the low
end of the allocation and silently corrupt the heap. Add a public
min_stack_size (one page) and return error.StackTooSmall before allocating
anything when options.stack_size is below it. The error is additive to create's
inferred error set; no existing caller passes a sub-page stack.
Assert a fiber is not .running before destroy frees its stack (freeing the
in-use stack is undefined). Document the state preconditions of create,
destroy, resumeFiber, and yield so callers know the contract the debug asserts
enforce.
@itsakeyfut itsakeyfut self-assigned this Jul 23, 2026
@itsakeyfut
itsakeyfut merged commit 4af3c7e into main Jul 23, 2026
9 checks passed
@itsakeyfut
itsakeyfut deleted the feat/input-validation-hardening branch July 23, 2026 11:42
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