Skip to content

feat(fuzz): add semantic property invariants to all fuzz targets + global stdout cap#159

Closed
thieman wants to merge 2 commits intomainfrom
thieman/semantic-property-fuzzing
Closed

feat(fuzz): add semantic property invariants to all fuzz targets + global stdout cap#159
thieman wants to merge 2 commits intomainfrom
thieman/semantic-property-fuzzing

Conversation

@thieman
Copy link
Copy Markdown
Collaborator

@thieman thieman commented Mar 27, 2026

Summary

Two safety enhancements to make RULES.md invariants machine-checked:

  • Global 10 MiB stdout cap (interp/api.go, interp/runner_expand.go): wraps the runner's stdout with a limitWriter so no script run can emit more than 10 MiB of output total, regardless of what builtins do individually. Complementary to the existing per-variable (1 MiB) and per-cmdsubst (1 MiB) caps.
  • Semantic property invariants in every fuzz target (16 files across builtins/tests/ and interp/tests/): each fuzz target now asserts:
    1. Output boundedlen(stdout) <= 10 MiB
    2. Determinism — same input run twice produces byte-identical stdout and exit code (skipped for commands that read live kernel state: ss, ps, ip addr/link)
    3. Exit code validity — only 0, 1, or 2 are acceptable
    4. No panic — explicit comment confirming the deferred recover in api.go means reaching the assertion means no panic occurred

Note: The two commits of substance are da0e1b77 and 9f867531. The other commits visible in this branch are unrelated in-progress work that was on local main; they will drop off as origin/main catches up.

Test plan

  • go test ./interp/... ./builtins/... passes
  • Fuzz seed corpus runs pass: go test ./builtins/tests/head/ -run FuzzHead
  • Hardening test for global cap: go test ./interp/tests/ -run TestGlobalStdoutCap
  • Verify determinism check catches actual non-determinism if introduced

🤖 Generated with Claude Code

thieman and others added 2 commits March 27, 2026 11:47
Wrap the runner's stdout writer with a limitWriter at the start of each
Run() call. Bytes beyond maxStdoutBytes (10 MiB) are silently discarded
so that Write() never returns an error and script execution continues
normally. This prevents unbounded memory growth from runaway loops or
commands that produce excessive output.

Also adds TestGlobalStdoutCapSilentlyDrops to verify the cap fires and
does not truncate output below the limit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add four invariants to every non-differential fuzz target:

1. Output bounded: assert stdout <= 10 MiB (exercises the new global
   cap and acts as a redundant safety net).
2. Determinism: run each script twice with identical filesystem state
   and assert byte-identical stdout and exit code.
3. Exit code validity: assert only 0, 1, (or 2 for commands that use
   it) are ever returned.
4. No panic: document that reaching the end of the fuzz body proves
   no panic escaped Runner.Run().

Invariant 2 is skipped for ss, ps, ip addr/link (live kernel state)
and differential fuzz targets (bash comparison, not rshell vs rshell).
ip route fuzz targets hold the procNetRouteMu mutex for both runs,
ensuring the mocked /proc/net/route content is identical.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@thieman thieman force-pushed the thieman/semantic-property-fuzzing branch from 9f86753 to 48322a2 Compare March 27, 2026 15:47
@thieman
Copy link
Copy Markdown
Collaborator Author

thieman commented Mar 27, 2026

Splitting into two separate PRs. The global stdout cap is in #161. The fuzz invariant changes are being dropped.

@thieman thieman closed this Mar 27, 2026
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