Skip to content

fix(typescript): lift the per-call budget cap, exit 124 on timeout, guard deep nesting - #2835

Merged
chaliy merged 4 commits into
mainfrom
claude/project-thread-pxlkst-ts-runtime
Nov 5, 2026
Merged

chaliy merged 4 commits into
mainfrom
claude/project-thread-pxlkst-ts-runtime

Conversation

@chaliy

@chaliy chaliy commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Михайло · project thread

What changed

The TypeScript (ZapCode) runtime had the same gaps that a downstream review found in the Python runtime (#2831, #2832, #2833), plus one that crashes the host process:

  • Process abort on deeply nested source (TM-TS-024). ZapCode 1.5.1's parse/lower/compile steps recurse with no depth guard. About 6 KB of nesting, such as [[[...]]] or 1+1+..., overflowed the native stack and aborted the whole host (SIGABRT) in release builds. On a 2 MB debug thread it took only about 100 levels. Bashkit now guards this in two layers:
    • A conservative nesting estimate (typescript_nesting.rs) rejects source estimated deeper than 1000 levels with ts: source is too deeply nested (exit 1).
    • Parse and compile run on a dedicated thread with a 128 MiB stack. This is reserved, not committed. The smallest stack that passed every nesting shape at the cap in a debug build was 32 MiB, so this is a 4x margin. wasm32 runs inline, and the cap still applies there.
  • Call cap. Each ts call reserved max_allocations (1M) budget units up front, so a script hit the default 100M budget after about 95 calls. Each call is now charged a flat 4096 units plus the time the VM actually ran.
  • Timeouts. A ZapCode time-limit hit now exits 124 with ts: execution timed out after Ns, matching python3 and coreutils timeout. The exit code comes from ZapCode's dedicated error variant, so a script's own throw cannot fake it.

Why

Agents run ts many times per script. A crafted few KB of source must never take down a multi-tenant host, and callers need to tell a limit hit apart from a script error.

Before / After

Case Before After
ts -c 'let x = [[[…3000…]]]' (release) host process aborts (stack overflow) rc=1, ts: source is too deeply nested (estimated depth …, limit 1000)
300 × ts -c 'let x = 1' in one script budget exhausted before call 100 all 300 run
while(true){} with a 200 ms limit rc=1, execution time limit exceeded rc=124, ts: execution timed out after 0.2s

Tests:

  • deeply_nested_source_fails_cleanly
  • deep_nesting_at_the_limit_does_not_overflow (18 AST shapes at the deepest accepted size)
  • deep_nesting_past_the_limit_is_rejected
  • many_small_invocations_fit_in_one_script
  • time_limit_exits_124
  • thrown_error_is_not_a_limit
  • Scanner unit tests covering the shapes that must be counted and the ordinary programs that must stay small.

Risk

  • Medium.
  • A single statement with more than about 1000 tokens and no , or ; (for example, a giant string concatenation) is now rejected. Ordinary programs, long arrays and long statement lists score well under 100.
  • Each ts call now spawns one thread, which costs tens of microseconds.
  • Upstream fix wanted: a depth guard in zapcode-core.

Checklist

  • Tests added or updated
  • Backward compatibility considered

Generated by Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

…uard deep nesting

- Each ts call reserved max_allocations (1M) work units, capping a script at
  about 95 calls. Charge 4096 units plus VM time instead.
- ZapCode time limit now exits 124 with 'ts: execution timed out after Ns'.
- ZapCode's parser/compiler recurse without a depth guard; ~6 KB of nested
  source aborted the host process. Add a conservative nesting estimate (cap
  1000) and run parse/compile on a 128 MiB-stack thread (TM-TS-024).
@chaliy chaliy self-assigned this Nov 5, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit d34291c Commit Preview URL

Branch Preview URL
Nov 05 2026, 05:04 AM

@bashkit-pr-reviewer bashkit-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review of the TS timeout/budget/nesting fix. The core fixes look right (exit 124 keyed off TimeLimitExceeded, fixed 4096-unit admission charge instead of the 1M reservation, conservative nesting estimate before ZapCode). Findings below are about holes in the new stack-overflow mitigation.

@bashkit-pr-reviewer

bashkit-pr-reviewer Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Review summary — #2835 fix(typescript): lift per-call budget cap, exit 124 on timeout, guard deep nesting (head d34291ce)

Verdict: Rebase-only push onto new main — the fixed code is unchanged from the previously reviewed head dece4c10. No new findings.

Earlier findings, still resolved

  • ✅ ts-spawn-fallback-inline-stack: on_vm_stack returns Option<T>; thread-start failure yields ts: cannot start execution thread (exit 1) on both the initial-run and resume paths.
  • ✅ ts-resume-small-stack: each snapshot.resume() goes through on_vm_stack (typescript.rs:1034).
  • ✅ ts-wasm-no-large-stack: residual wasm risk documented in knowledge/runtimes/zapcode-runtime.md.

What I checked: verified the on_vm_stack native/wasm variants, both VM_THREAD_ERROR arms, and the knowledge-page wording are all present at the new head; diff hunk layout is identical to the last review. No build/test run per sandbox rules.

…hread

- snapshot.resume after a VFS/external call now runs on the 128 MiB thread too.
- No inline fallback when the thread cannot start: exit 1 with
  'ts: cannot start execution thread'.
- Port TM-TS-024 to the public threat model; document wasm residual risk.
@chaliy
chaliy merged commit 0ffcf7f into main Nov 5, 2026
57 checks passed
@chaliy
chaliy deleted the claude/project-thread-pxlkst-ts-runtime branch November 5, 2026 05:29
@chaliy chaliy mentioned this pull request Nov 10, 2026
2 tasks done
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