Parent: #493 Related: #515 (the same class, fixed for JSON only), #932 (where this surfaced)
A small source crashes the process
Every row was executed. zig-js is the current test262 --eval binary; exit -11 is a SIGSEGV kill with no output. Found while timing #932 at depth 8000, where both the pre- and post-fix binaries crashed identically — so it predates that fix.
| shape | zig-js @ 8000 | zig-js @ 16000 | zig-js @ 32000 | node @ 16000 and 100000 |
|---|---|---|---|---|
((…(1)…)) parentheses, top level | OK | SIGSEGV | SIGSEGV | RangeError: Maximum call stack size exceeded |
[[…[]…]] arrays, top level | OK | SIGSEGV | SIGSEGV | RangeError: Maximum call stack size exceeded |
{ { … } } blocks, top level | OK | SIGSEGV | SIGSEGV | RangeError: Maximum call stack size exceeded |
{ { … } } blocks, inside a function | OK | SIGSEGV | SIGSEGV | — |
destructuring catch, top level | OK | SIGSEGV | SIGSEGV | — |
destructuring catch, inside a function | SIGSEGV | SIGSEGV | SIGSEGV | — |
The parentheses case is 32 KB of ( and ) around a 1. An embedder evaluating untrusted source cannot catch this: it is a process crash, not a JavaScript exception, and it is the kind of input #493 exists to bound.
What is and is not established
- Established: zig-js crashes where node throws a catchable RangeError, on every nesting shape tried, from a source linear in depth.
- Established: the depth that crashes varies by shape — 8000 for destructuring catch in a function, between 8000 and 16000 for everything else. Shapes that do more native work per level overflow sooner, which is consistent with a fixed native stack and no depth guard.
- Not established: which phase overflows. Parsing is the one thing every shape shares, so the recursive-descent parser is the likeliest first site, but the compiler (recursing through
compileStmt, as #932's profile showed) and the tree-walker may each overflow independently at other depths. The fix must cover whichever phases can overflow, not just the first one found.
Precedent
#515 fixed exactly this class for JSON.parse: reject hostile nesting before the native stack overflows. No equivalent guard exists for the parser, compiler or evaluator — there is no depth or stack-limit check in src/parser.zig or src/compiler.zig.
Suggested order
- Pin the table above as a regression probe that asserts a catchable error instead of a crash, and find the overflowing frame per shape (a crash cannot be
sampled; run under a debugger, or bisect depth with a ReleaseSafe build). - Decide the contract: node reports
RangeError: Maximum call stack size exceeded. Match that for evaluation depth, and pick an explicit, documented error for parse depth. - Guard by measured native stack headroom rather than a fixed depth constant where possible, since the safe depth differs per shape and per build mode; re-run the #926/#928 frozen workloads to confirm the guard costs nothing on normal code.