Skip to content

Commit a8bc258

Browse files
olwangclaude
andcommitted
docs: mark hardening Tier A/B done in todo
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2b0842b commit a8bc258

1 file changed

Lines changed: 16 additions & 15 deletions

File tree

docs/hardening-todo.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,28 +38,29 @@ prefixes (the enum is intentionally minimal: `Diagnostics` / `Runtime`).
3838

3939
## Tier A — stop the crashes (highest probability for agent code)
4040

41-
- [ ] **A1 Recursion depth limit** (Inv 1). `self.frames.push()` is unbounded
41+
- [x] **A1 Recursion depth limit** (Inv 1) — DONE (`VmLimits.max_depth`, default 16 384, enforced at all frame-push sites → `EvalError::Runtime("recursion depth limit exceeded …")`). `self.frames.push()` was unbounded
4242
(`reg_vm/mod.rs:7523` "bounded only by memory"; pushes at 7538/7974/8019) → a
4343
self-recursive program overflows the native stack = uncatchable SIGSEGV. Add a
4444
configurable `max_depth` (default-on, generous) checked at every frame push →
4545
`EvalError::Runtime("recursion depth limit exceeded …")`. The #1 crash; trivial.
46-
- [ ] **A2 `panic = "abort"`** (Inv 2). Add to workspace `[profile.release]`. One
47-
line. `hostile.rs` uses `catch_unwind` but runs in the dev profile (unwind), so
48-
normal `cargo test` is unaffected; verify fuzz targets still build.
46+
- [x] **A2 `panic = "abort"`** (Inv 2) — DONE (workspace `[profile.release]`).
47+
`hostile.rs`'s `catch_unwind` runs in the dev profile (unwind); the fuzz crate
48+
is workspace-detached, so `cargo +nightly fuzz build` is unaffected. Verified.
4949

5050
## Tier B — stop the hangs
5151

52-
- [ ] **B3 Step budget** (Inv 1). The interpreter loop (`reg_vm/mod.rs:~7927`,
53-
`while let Some(instr) = func.code.get(ip)`) has no fuel; `while true {}` hangs
54-
forever. Add a per-instruction counter + configurable `step_budget: Option<u64>`
55-
`EvalError::Runtime("step budget exceeded …")`. Follow-up (not required this
56-
pass): also poll the existing `CancellationToken` every N steps so cooperative
57-
cancellation can preempt a tight compute loop — the preemption hook structured
58-
cancellation is currently missing (it only works at await points).
59-
- [ ] **B4 Memory ceiling** (Inv 1). Configurable `mem_budget: Option<usize>`;
60-
account live allocation through `ensure_regs` and list/map growth →
61-
`EvalError::Runtime("memory limit exceeded …")`. Harder (≈169 alloc/growth
62-
sites); lands after A/B3. Best-effort byte accounting is fine.
52+
- [x] **B3 Step budget** (Inv 1) — DONE (`VmLimits.step_budget: Option<u64>`,
53+
default OFF; per-instruction `tick()` in BOTH the interpreter loop and the
54+
tier-0 JIT loop → `EvalError::Runtime("step budget exceeded …")`).
55+
- [ ] *Follow-up (not done):* poll the existing `CancellationToken` every N
56+
steps so cooperative cancellation can preempt a tight compute loop — the
57+
preemption hook structured cancellation currently lacks (works only at await
58+
points). The `tick()` counter is the natural place to add it.
59+
- [x] **B4 Memory ceiling** (Inv 1) — DONE (`VmLimits.mem_budget: Option<usize>`,
60+
default OFF; best-effort cumulative `live_bytes` accounting at `ensure_regs`,
61+
list/map construction, and list push/append → `EvalError::Runtime("memory limit
62+
exceeded …")`). Under-counts deeply nested `Rc` containers — documented; goal is
63+
to trip before host OOM, not exact accounting.
6364

6465
## Tier C — longevity (lower urgency)
6566

0 commit comments

Comments
 (0)