Skip to content

Add mutation fuzzer; guard eval_node against stack overflow#105

Closed
InauguralPhysicist wants to merge 1 commit into
mainfrom
claude/explore-repo-o2F9k
Closed

Add mutation fuzzer; guard eval_node against stack overflow#105
InauguralPhysicist wants to merge 1 commit into
mainfrom
claude/explore-repo-o2F9k

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

tools/fuzz.py is a lightweight mutation fuzzer that mutates valid .eigs seed files (from examples/ and tests/) and runs the interpreter under a 3-second timeout. 2000 iterations surfaced two SIGSEGV crashes (saved under tools/fuzz-crashes/) — both unbounded-recursion stack overflows from mutated valid programs.

Fix: add a recursion-depth guard in eval.c. eval_node now dispatches through a thin wrapper that tracks depth and surfaces an eval recursion too deep runtime error at EIGS_MAX_EVAL_DEPTH=500 rather than letting the C stack overflow. Catchable via try/catch.

Regression assertion in test_coverage_gaps.eigs (CG96): a self-calling function wrapped in try/catch must set the catch flag, not SIGSEGV.

Total tests 530 → 531; both fuzz-crash fixtures now exit cleanly.

https://claude.ai/code/session_01F99zPp8QCZJ4cn8ix3e2Je

What does this PR do?

Checklist

  • make test passes locally
  • New builtins have signature comments and docs in docs/BUILTINS.md
  • New library functions follow conventions in docs/STDLIB.md
  • New examples have a comment header explaining what they demonstrate
  • CHANGELOG.md updated (if user-facing change)

tools/fuzz.py is a lightweight mutation fuzzer that mutates valid
.eigs seed files (from examples/ and tests/) and runs the interpreter
under a 3-second timeout. 2000 iterations surfaced two SIGSEGV crashes
(saved under tools/fuzz-crashes/) — both unbounded-recursion stack
overflows from mutated valid programs.

Fix: add a recursion-depth guard in eval.c. eval_node now dispatches
through a thin wrapper that tracks depth and surfaces an eval
recursion too deep runtime error at EIGS_MAX_EVAL_DEPTH=500 rather
than letting the C stack overflow. Catchable via try/catch.

Regression assertion in test_coverage_gaps.eigs (CG96): a self-calling
function wrapped in try/catch must set the catch flag, not SIGSEGV.

Total tests 530 → 531; both fuzz-crash fixtures now exit cleanly.

https://claude.ai/code/session_01F99zPp8QCZJ4cn8ix3e2Je
@InauguralPhysicist InauguralPhysicist deleted the claude/explore-repo-o2F9k branch June 13, 2026 02:01
InauguralPhysicist added a commit that referenced this pull request Jul 10, 2026
n is clamped to >=1 two lines up, so the conjunct was always true.
The two cpp/path-injection alerts on main.c's --step block are the
documented CLI false-positive class (#105/#107) — dismissed per-alert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm
InauguralPhysicist added a commit that referenced this pull request Jul 10, 2026
* feat(debug): --step — the eigsdap v1 CLI tape-stepper (#418)

eigenscript --step <tape> [source.eigs] opens a recorded trace tape in an
interactive time-travel debugger: step forward AND backward over L records,
breakpoints as line filters (c/rc continue both directions), jump-to-line
both ways, bindings reconstructed from A records at any position, and each
binding's observer-trajectory label alongside its value — computed by the
runtime's own #294 value-channel classifier (observer_slot_record_value is
now exported; the stepper feeds reconstructed histories through a real
ObserverSlot, so a label is by construction what report_value would have
said at that moment). Stepping back rewinds the diagnosis, not just values.

Pure tape reader — nothing executes; step-back is an index decrement. The
#411 version rule is enforced exactly like replay (refuse-on-mismatch,
exit 3). src/step.c is a CLI-only translation unit (Makefile CLI_ONLY),
excluded from the embed/LSP/freestanding profiles; freestanding-check green.

Suite section [42f] (tests/test_step.sh, 16 checks): stepping, the
acceptance label-flip on back-step, breakpoints, jumps, all three #411
refusal classes, EOF quit, and driving a --test --trace-on-fail tape.
Ships docs/DEBUGGING.md — failure→replay→interrogate, the stepper, and
the temporal interrogatives unified — linked from both READMEs + TRACE.md.

Release suite 2722/2722; ASan+detect_leaks 2722/2722, leak tally 0.

Closes #418

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm

* build: read SOURCES/CLI_ONLY from the Makefile in build.sh + amalgamate.sh

build.sh carried its own copy of the source list and fell behind when
step.c landed (third instance of the class — the install.sh/bench/matrix
CI legs fail at link while make is green). Both scripts now read SOURCES
and the CLI_ONLY drop set from the Makefile, the single source of truth,
so a new translation unit cannot silently miss any build path again.
Verified locally: build.sh, build.sh lsp, tools/amalgamate.sh (step.c
correctly excluded from the embed amalgamation), make, freestanding-check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm

* fix(step): drop dead n>0 condition (CodeQL cpp/constant-comparison)

n is clamped to >=1 two lines up, so the conjunct was always true.
The two cpp/path-injection alerts on main.c's --step block are the
documented CLI false-positive class (#105/#107) — dismissed per-alert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

2 participants