Skip to content

First real 4-shell fuzz run: 6 zsh boundary divergences fixed - #17

Merged
mitchellnemitz merged 3 commits into
mainfrom
impl-2026-08-17-fuzz-boundary-carve
Aug 18, 2026
Merged

mitchellnemitz merged 3 commits into
mainfrom
impl-2026-08-17-fuzz-boundary-carve

Conversation

@mitchellnemitz

Copy link
Copy Markdown
Owner

The fuzzer's four-shell oracle never ran: busybox was missing locally, so the fuzzshell baseline skipped. With busybox built from source (ash-only config), the SC-005 baseline ran for the first time and found six divergences, all one class.

zsh's $(( )) converts an operand's value text with its own number parser, which truncates any magnitude above 2^63-1 after 18 digits and continues with the wrong value (exit unchanged). The existing carve only tracked INT_MIN sources with direct data flow, so it missed two shapes the baseline hit: values that wrap into the boundary at runtime (math.int_max() + 1) and boundary values hidden behind dict.get/unwrap_or.

What changed

  • programReachesBoundaryArith: the oracle now carves zsh for any boundary source (both int64 edge literals, math.int_min()/math.int_max()) with data-flow taint through the IR (bindings, arithmetic, collection literals, dict.get/unwrap_or/index). Everything outside that reach is still compared against all four shells; programReachesIntMinArith stays as the done-signal predicate.
  • Docs corrected in language.md, design-decisions.md, stdlib.md, and the fuzz README: the old "loud zsh error" claim was wrong, zsh warns and returns a wrong value. The comparison-at-boundary note was also verified against the shells and narrowed.
  • Six minimized reproducers curated as regressions, with a new test pinning each curated entry to the detector (regenerated provenance plus stored-source guard).

Verification

  • go test ./... and the four-shell fuzzshell suite (baseline, curated replay, done-signal) green; wisp-fuzz seeded and replay clean.

The first real four-shell baseline run (busybox built locally, so the
fuzzshell oracle finally ran) found six divergences. All six are the
documented zsh residual: zsh's $(( )) truncates operand value text above
2^63-1 to 18 digits and keeps going with the wrong value, exit unchanged.
The existing carve only tracked INT_MIN sources directly; it missed values
that wrap into the boundary at runtime (int_max() + 1) and boundary values
hidden behind dict.get/unwrap_or.

The oracle now carves every boundary source (both int64 edge literals and
math.int_min()/math.int_max()) with data-flow taint through the IR.
programReachesIntMinArith stays untouched as the done-signal predicate.
Six minimized reproducers are curated as regressions, and the docs are
corrected: the old "loud zsh error" claim was wrong, zsh warns and returns
a wrong value.

Gates: go test ./... and the four-shell fuzzshell suite are green; the
seeded baseline and curated replay both come back clean.
The done-signal section named only intmin-via-var.json. Add a paragraph
covering the six boundary-*.json entries: discovered by the first real
four-shell baseline, shrunk, committed with real provenance.
@mitchellnemitz
mitchellnemitz force-pushed the impl-2026-08-17-fuzz-boundary-carve branch from d961f3e to fb03e33 Compare August 18, 2026 14:23
The guide's correction (zsh warns and continues with a truncated value, not
a loud error) applies to the changelog entry too.
@mitchellnemitz
mitchellnemitz merged commit f12d39f into main Aug 18, 2026
8 checks passed
@mitchellnemitz
mitchellnemitz deleted the impl-2026-08-17-fuzz-boundary-carve branch August 18, 2026 15:57
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