Skip to content

VM: unify safe parameter binding across functions and generators #60

Description

@TheUncharted

Summary

Parameter binding is implemented through separate paths for normal functions and generators. PR #56 correctly improves flat array/object destructuring for normal functions and arrow callbacks, but the generator path still supports only identifiers/rest and contains an unchecked rest slice. The new destructuring binder also deep-clones compound values without recursive resource accounting.

This issue tracks the broader work needed to make parameter binding consistent, fallible, and resource-bounded across all callable forms.

Context

PR #56 (d484ac1e9fc6cd7a7d14224f502f349f8ea71e9e) adds per-name flat destructuring in bind_params and fixes the normal-function rest slice by using args.get(i..). Its submitted tests pass for:

  • flat array destructuring
  • flat object destructuring
  • Object.entries(...).map(([key, value]) => ...)

Those improvements should be treated separately from the broader deficiencies below.

Verified generator failures

Generator destructuring is ignored

function* values([item]) {
  yield item;
}
values([7]).next().value;

Expected: 7

Actual at PR #56 head: undefined

Generator creation has a separate parameter loop that ignores destructuring patterns.

Omitted arguments can panic the Rust host

function* values(prefix, ...rest) {
  yield rest.length;
}
values();

Verified panic:

range start index 1 out of range for slice of length 0

The generator binder still uses args[i..].to_vec() rather than a checked slice. This panic is pre-existing and was not introduced by PR #56, but it remains guest-triggerable.

Destructuring semantics

Nullish or incompatible destructuring inputs currently bind names to undefined rather than returning a controlled TypeError:

const read = ({ item }) => item;
let caught = false;
try { read(); } catch (error) { caught = true; }
caught;

Expected JavaScript result: true

Actual: false

The supported subset should either implement the JavaScript behavior or explicitly reject/document the divergence.

Resource impact

The binder clones the full argument and then clones each extracted field. Since arrays and objects are owned recursive Values, repeated aliases can duplicate a large nested value several times inside one call without charging the complete clone size to ResourceTracker.

Example shape:

function fanout({
  payload: first,
  payload: second,
  payload: third
}) {
  return 0;
}
fanout({ payload: largeNestedArray });

This is an accidental memory-exhaustion risk, not evidence of malicious contributor code or a filesystem/network/native-code sandbox escape.

Proposed design

  • Use one shared, recursive, fallible parameter binder for normal functions, arrows, methods, constructors, and generators.
  • Have the binder return Result<Vec<Value>> so type and resource failures propagate.
  • Use checked rest slicing everywhere.
  • Define supported behavior for object/array destructuring of undefined, null, and incompatible values.
  • Support or explicitly reject nested patterns, defaults, holes, aliases, and rest properties/elements.
  • Charge deep clones against allocation/memory limits before creating local bindings, or move compound values to shared/COW storage.
  • Ensure local-slot ordering exactly matches compiler-declared parameter names.

Acceptance criteria

  • Normal and generator calls use the same binding semantics.
  • Omitted generator rest arguments return an empty array and never panic.
  • Generator array/object destructuring binds expected values.
  • Nullish destructuring either throws a controlled TypeError or is rejected at parse/compile time with documented behavior.
  • Defaults and subsequent parameter slots remain aligned.
  • Nested/unsupported patterns return a controlled error rather than silently binding incorrect values.
  • Deep-value binding respects configured resource limits before allocation.
  • Regression tests cover normal functions, arrows, methods, constructors, generators, omitted arguments, defaults, rest, nullish values, aliases, and nested patterns.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions