Skip to content

Honor exotic [[Set]] in SetterThatIgnoresPrototypeProperties (Error.stack, Iterator.constructor, Iterator[Symbol.toStringTag]) #185

Description

@pmatos

Deferred from #183: the SetterThatIgnoresPrototypeProperties step 5a (Set(this, p, v, true)) ignores the boolean returned by set_property_value and does not honor exotic [[Set]] semantics for a receiver that reports a writable own data descriptor but whose [[Set]] returns false.

Original feedback by @chatgpt-codex-connector on PR #183 (#183):

Route existing stack writes through [[Set]]

When the receiver already has an own stack descriptor, SetterThatIgnoresPrototypeProperties requires Set(thisValue, "stack", v, true). This branch only checks descriptor bits and then ignores the boolean from set_property_value; for a module namespace object that exports stack, [[GetOwnProperty]] reports a writable own data descriptor but its [[Set]] returns false, so Object.getOwnPropertyDescriptor(Error.prototype, "stack").set.call(ns, "x") incorrectly succeeds instead of throwing. Calling the existing proxy_set/Set path and throwing on false would preserve the exotic [[Set]] behavior.

Context

  • src/interpreter/builtins/mod.rsError.prototype.stack setter, the ordinary own-data-descriptor branch: it calls cell.borrow_mut().set_property_value("stack", v) and discards the boolean.
  • src/interpreter/types.rsset_property_value models exotic [[Set]] = false only for typed-array out-of-bounds indices and non-writable Array.length. For a module namespace (whose [[Set]] always returns false, §10.4.6.9) it is a non-mutating no-op that returns true, so the setter returns normally instead of throwing.
  • The same gap already ships for the sibling SetterThatIgnoresPrototypeProperties setters in src/interpreter/builtins/iterators.rs: Iterator.prototype.constructor and Iterator.prototype[Symbol.toStringTag] use the identical contains_key + set_property_value shortcut.

Why deferred

diminishing-returns — the trigger (Object.getOwnPropertyDescriptor(Error.prototype,'stack').set.call(ns,'x') on a module namespace that exports a binding named stack) is highly contrived, has zero test262 coverage (the 35 built-ins/Error/prototype/stack/ files and the Iterator weird-setter.js files all use ordinary objects / Proxies), and fixing only the Error branch would be incomplete-by-design.

Suggested fix

Factor a shared Set(O, P, V, Throw=true) -> bool path (the dispatch is currently inlined in Reflect.set and Object.assign, including the "module namespace exotic → false" branch) and route all three SetterThatIgnoresPrototypeProperties setters (Error.prototype.stack, Iterator.prototype.constructor, Iterator.prototype[Symbol.toStringTag]) through it, throwing on false.

Filed automatically by pm-autofix-pr after dual-evaluator triage by Claude Opus 4.8 and Codex (codex-cli 0.130.0), which both returned DEFER / diminishing-returns.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions