Skip to content

Harden JSON stdlib recursion inside the worker #45

Description

@jmgilman

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions