Valid programs that node runs, and zig-js segfaults on
Every row was executed against node and the current test262 --eval binary in each execution mode. These are flat sources — no nesting in the text — so they are not adversarial nesting; a large template literal or a long generated string concatenation reaches them.
| valid program | size | tree mode | default | vm | node |
|---|---|---|---|---|---|
template literal with 2,000 ${1} substitutions | ~8 KB | SIGSEGV | OK | OK | runs |
| template literal with 8,000 substitutions | ~32 KB | SIGSEGV | SIGSEGV | SIGSEGV | runs |
'a'+'a'+… with 8,000 terms | ~32 KB | SIGSEGV | OK | OK | runs |
1+1+… with 16,000 terms | ~32 KB | SIGSEGV | SIGSEGV | SIGSEGV | runs |
o.a.a.a… member chain, 8,000 deep | ~16 KB | SIGSEGV | OK | OK | RangeError |
The tree-walker row matters most: Context.scriptTreeWalkPolicy sends any source containing let , const , catch, switch and similar to the tree-walker, which covers most real code, and that is exactly the mode that fails first.
Mechanism
The parser builds a left-associative chain iteratively (the parseBinary loop), producing a left-deep tree ((a+b)+c)+d. Consumers then recurse down the left spine, one native frame per term:
- tree-walker:
eval>evalBinary>eval(confirmed by crash backtrace, about 3,475 iterations to overflow); - compiler:
compileExpr>compileExprat the.binaryarm'sb.left(confirmed by backtrace, about 12,000 frames); - a template literal desugars to a left-deep
+/to-string chain and fails the same way.
Why this needs a different fix from the rest of #934
node runs these. A stack guard would only turn a crash into a RangeError on code node accepts — still an incompatibility. The fix is to walk the left spine iteratively: descend the .left links collecting the chain, evaluate or emit the leftmost operand, then fold the right operands in order. That preserves exact left-to-right evaluation order, coercion order and abrupt-completion order, which is what the recursive form does now. The member-chain row is the exception, since node throws RangeError there; it belongs with the guard work.
Scope
Binary operators including string concatenation, template literals, and the other left-associative shapes that the parser builds iteratively and that no test here exercised yet: logical &&, || and ?? chains, and comma sequences. Each must be measured and pinned, not assumed.