Skip to content

Proxy receivers: remaining Array.prototype mutators fall through silently; prototype thunks lose their receiver as plain values (follow-up to #6907) #6908

Description

@proggeramlug

Follow-ups from #6907 (Array.prototype mutators on Proxy receivers). That PR trap-routes push/pop/shift/unshift in array_proto_mutator; two adjacent gaps remain:

1. Remaining mutators fall through silently on Proxy receivers

reverse / sort / splice / fill / copyWithin on a Proxy receiver reaching the generic dispatch still hit the pre-#6907 fall-through: as_real_array rejects the handle-band id (correctly — deref is the #6279 segfault class), run_object_mutator rejects non-plain-objects, and the call returns undefined without firing a trap. Extend proxy_array_mutator (crates/perry-runtime/src/array/push_pop.rs) with the spec loops for the rest of the family — all primitives (js_proxy_get/js_proxy_set/js_proxy_delete + proxy_array_length) are already in place.

Repro:

const t: any = [3, 1, 2];
const p: any = new Proxy(t, {});
p.reverse();
console.log(t.join(","));   // node: 2,1,3 — perry: 3,1,2 (silent no-op)

2. Prototype thunks lose their receiver when called as plain values

Array.prototype method thunks resolve their receiver from IMPLICIT_THIS at call time, so a thunk called as a plain value silently mutates nothing:

const t: any = [1, 2];
const f: any = t["push"];   // typeof f === "function" ✓
f(3);                        // node: TypeError (this === undefined) — perry: silent no-op
console.log(t.join(","));    // node: unreachable — perry: "1,2"

The decomposed proxy form hits the same class (const g = proxy.push; g(3) — node binds this through the call, perry no-ops). The #4661 comment in native_call_method.rs claims the decomposed form works via js_proxy_get; the method VALUE resolves fine, but the receiver binding is lost at the call. Correct semantics: bind the receiver at property-read time (bound-method materialization) or throw the spec TypeError when a receiver-less builtin thunk is invoked — silent no-op is the worst of both.

Discovered while root-causing the release-gate failure proxy_array_push_via_member_routes_through_traps (see #6907 for the full mechanism chain: #6397 exposed it, #6759 ended the x86_64 classification luck, arm64 was broken from #6397 on).

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