Skip to content

fix(runtime): Promise(data) branch missing symbol_descriptors accessor check in get_computed_property_impl #418

Description

@dowdiness

Context

PR #413 fixed the Array(arr) branch in interpreter/runtime/property.mbt's get_computed_property_impl — it was checking symbol_properties directly without first consulting symbol_descriptors for getter-type (accessor) entries. The same gap exists in the Promise(data) branch and was not addressed in that PR.

Identified during the PR #413 post-merge analysis.

Problem

In interpreter/runtime/property.mbt, the per-variant dispatch in get_computed_property_impl follows this two-step protocol for own symbol property lookup:

  1. Check symbol_descriptors for an accessor descriptor (getter). If a getter is present, call it.
  2. Check symbol_properties for a data value.

The Object, Map, and Set branches all follow this protocol. The Array branch was fixed in PR #413. The Promise(data) branch (currently around line 1031) only performs step 2 — it reads data.bag.symbol_properties directly and skips data.bag.symbol_descriptors entirely:

Promise(data) => {
  match data.bag.symbol_properties.get(sym.id) {  // step 2 only — missing step 1
    Some(v) => return v
    None => ()
  }
  ...
}

This means if a Promise instance has an accessor-type own symbol property (e.g., a getter installed on its bag.symbol_descriptors), the getter will be silently skipped and the property will read as absent.

Current severity: Low — no code path in the engine currently installs getter-type symbol properties on individual Promise instances. However, this will become exploitable as Proxy wrapping and future spec features (Observable, async iterator protocol extensions) create Promise-like objects with intercepted symbol access.

Suggested work

Mirror the fix applied to Array(arr) in PR #413. Before the existing symbol_properties lookup in the Promise(data) branch, add a symbol_descriptors accessor check:

Promise(data) => {
  // Check for accessor descriptor (getter) on own symbol property.
  match data.bag.symbol_descriptors.get(sym.id) {
    Some(desc) =>
      match desc.getter {
        Some(getter) => return self.call_value(getter, obj, [], loc)
        None => ()
      }
    None => ()
  }
  // Check promise's own symbol property bag.
  match data.bag.symbol_properties.get(sym.id) {
    Some(v) => return v
    None => ()
  }
  ...
}

Also audit whether the has_property path for Promise(data) has the same gap (line ~665 area — the hasOwnProperty implementation), and whether set_computed_property_impl needs a matching fix for the setter side.

Acceptance criteria

  • get_computed_property_impl Promise(data) branch checks symbol_descriptors before symbol_properties
  • All existing Promise tests still pass (1272/1272)
  • moon test clean
  • A whitebox test in interpreter/runtime/ pins the behavior: a Promise instance with a getter-type symbol descriptor correctly fires the getter

Metadata

Metadata

Assignees

No one assigned

    Labels

    conformanceECMAScript conformance

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions