Problem
Issue #42 adds the pinned go.starlark.net/lib/json implementation to the fixed worker language surface. Its encoder and decoder recurse in Go without a nesting limit. Work performed inside Go-backed builtins does not debit MaxExecutionSteps, which counts Starlark bytecode only.
A program can therefore construct deeply nested JSON text with a small number of Starlark steps through repeated string doubling, then pass it to json.decode. The upstream recursive parser can reach a Go stack overflow. Go stack exhaustion is a runtime throw, not a recoverable panic, so Engine.Execute cannot classify it. The worker-process boundary contains the failure to one execution, but the worker exits and the caller receives only a coarse protocol/internal failure. json.encode has the analogous risk for deeply nested Starlark containers.
This is deliberately separate from #42. A decode-only guard would leave encode exposed, and applying crossing-value limits to interpreter-local compute would change the meaning of MaxValueDepth or MaxValueBytes.
Desired outcome
- Bound recursive work for both
json.encode and json.decode before entering the upstream recursive implementations.
- Keep the bound fixed across CodeMode servers; do not add a host configuration knob.
- Decide and document whether this is a new fixed internal-compute depth limit or an intentional extension of an existing limit. Do not silently repurpose crossing-value limits.
- Keep ordinary upstream JSON behavior and diagnostics within the accepted bound.
- Preserve worker containment and the existing coarse model-facing error taxonomy.
- Add a regression that exercises the real worker process and proves excessive nesting fails without aborting the worker protocol.
Evidence
Review of pinned go.starlark.net revision 5395d018f003 found recursive calls in lib/json encode and decode. A separate step-accounting spike measured the same Starlark step count for 10-element and 100,000-element JSON operations, confirming builtin-internal work is elapsed-time bounded but not bytecode-step bounded.
Problem
Issue #42 adds the pinned
go.starlark.net/lib/jsonimplementation to the fixed worker language surface. Its encoder and decoder recurse in Go without a nesting limit. Work performed inside Go-backed builtins does not debitMaxExecutionSteps, which counts Starlark bytecode only.A program can therefore construct deeply nested JSON text with a small number of Starlark steps through repeated string doubling, then pass it to
json.decode. The upstream recursive parser can reach a Go stack overflow. Go stack exhaustion is a runtime throw, not a recoverable panic, soEngine.Executecannot classify it. The worker-process boundary contains the failure to one execution, but the worker exits and the caller receives only a coarse protocol/internal failure.json.encodehas the analogous risk for deeply nested Starlark containers.This is deliberately separate from #42. A decode-only guard would leave encode exposed, and applying crossing-value limits to interpreter-local compute would change the meaning of
MaxValueDepthorMaxValueBytes.Desired outcome
json.encodeandjson.decodebefore entering the upstream recursive implementations.Evidence
Review of pinned
go.starlark.netrevision5395d018f003found recursive calls inlib/jsonencode and decode. A separate step-accounting spike measured the same Starlark step count for 10-element and 100,000-element JSON operations, confirming builtin-internal work is elapsed-time bounded but not bytecode-step bounded.