Repository navigation
fix(ts): enforce max_memory and wall-clock limit for TypeScript - #2910
Conversation
ZapCode 1.5.1 never reads memory_limit_bytes, and a failed allocation aborts the process with every tenant. Template-literal, concat and spread doubling all aborted the host. Each ts run now gets its own vm_meter (the Monty meter, renamed from python_meter): every instruction stops the run past max_memory, and output-amplifying builtins (join, toString, JSON.stringify, console.log, concat, repeat, split, replace) size their result before allocating. Native ts fails closed without MeteredAllocator. A new multi-tenant stress suite found a host-call loop ran 30 s under a 500 ms limit because ZapCode restarts its clock at every resume. The host-call loop now checks the run's wall-clock deadline, caps callbacks at the remaining time, and yields. TM-TS-026, TM-TS-027.
Mirror the Monty coverage for the vendored ZapCode VM: a ts_fuzz target under the metered allocator (nightly fuzz matrix plus CI compile check), an ASan step for the ts unit, threat-model and stress tests, and a 300-round ts-stress-soak job.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | ec09005 | Commit Preview URL Branch Preview URL |
Nov 10 2026, 10:06 PM |
There was a problem hiding this comment.
Memory-limit + wall-clock enforcement for ts: solid two-layer design (per-instruction heap check plus pre-sizing of fan-out builtins, deadline checked at every host suspension). No blocking issues; two hardening gaps below. I could not run the test suite here (no build in this environment), so this is code reasoning only.
Review summary (head
|
Requested by Михайло · project thread
What changed
TypeScriptLimits::max_memoryis now enforced. ZapCode 1.5.1 stores the limit but never reads it, so one tenant's script could grow until an allocation failed, and Rust aborts the whole process when that happens. Eachtsrun now gets its own heap meter (the one Monty already uses, renamed frompython_metertovm_meter). Every instruction stops the run withmemory limit exceededonce the run's live heap passes the limit.[s, s, s]costs a few pointers butjoin, arraytoString,JSON.stringify,''.concat(...)andconsole.log(...)each produce full copies. These builtins, plusrepeat,splitandreplace/replaceAll, now work out the size of their result and refuse before allocating it.tsrefuses to run unlessMeteredAllocatoris the global allocator. Every binding, example and test harness that enablestypescriptnow installs it.max_durationnow bounds wall-clock time across host calls. Before,while (true) { await writeFile(...) }ran 30 s under a 500 ms limit because ZapCode restarts its clock at every resume. Each host call now checks the run's deadline, callbacks are capped at the time remaining, and the loop yields to the executor so caller timeouts can cancel the run.ts_tenant_stress_tests, 3 rounds on every PR), ats_fuzztarget, a nightly ASan step with--features typescript, and a 300-roundts-stress-soaknightly job.TM-TS-026, TM-TS-027. Every vendor change is a listed
bashkit fork:edit (zapcode_vendor/fork-edits.json), checked in CI byscripts/check_zapcode_vendor.py.Why
This was the hardening asked for before 0.21.0. Probing the ZapCode builtins after #2909 found three more ways to abort the host (template-literal doubling,
concatdoubling, spread doubling). The root cause was that memory limits were never enforced. The stress suite then found the time-limit bypass.Before / After
Before, on main as of #2909, with the default 64 MB limit:
After:
Locally: the full
bashkitlib and integration suite withtypescript,pythonpasses, the TS examples run,cargo clippy --workspace --all-targets --all-features -D warningsis clean, the vendor drift check passes, and a 30-round stress soak passes.Risk
max_memorywhere they used to succeed (or crash). Each host call snapshots the VM heap, so a script holding 8 MiB needs about 3x that during areadFile/writeFilecall.typescriptwithoutbashkit::MeteredAllocatoras the global allocator now get a clear error fromts.Checklist