Skip to content

Reflect.apply silently drops every argument after the fourth #10425

Description

@proggeramlug

Found by the package audit (compiling real npm packages from source instead of Perry's native bindings) on
Perry e6dcb62 (v0.5.1587), Linux x64. Reflect.apply(fn, thisArg, args) passes at most the first four elements of
args; the rest are dropped without an error.

Reproduction

main.ts:

console.log(Reflect.apply(Math.max, null, [1, 2, 3, 4, 5, 6]));
function f(...a: number[]) { return a.length + ":" + a.join(","); }
console.log(Reflect.apply(f, null, [1, 2, 3, 4, 5, 6, 7]));
console.log(Reflect.construct(Array, [1, 2, 3, 4, 5, 6]).length);
console.log(f.apply(null, [1, 2, 3, 4, 5, 6, 7]));
node main.ts
PERRY_NO_AUTO_OPTIMIZE=1 perry compile main.ts -o main && ./main

Expected (Node 26.5.1)

6
7:1,2,3,4,5,6,7
6
7:1,2,3,4,5,6,7

Actual (Perry)

4
4:1,2,3,4
6
7:1,2,3,4,5,6,7

Reflect.construct and Function.prototype.apply are correct; only Reflect.apply truncates.

Impact

Silent wrong results in any code that forwards argument lists through Reflect.apply — common in Proxy apply
handlers, decorators/wrappers, instrumentation and polyfills (Reflect.apply(target, thisArg, argumentsList) is the
canonical way to forward a call).

Notes

  • Cause (verified by reading the code): js_reflect_apply (crates/perry-runtime/src/proxy/reflect_misc.rs:99)
    builds the full list with create_list_from_array_like, then calls call_with_this_and_args
    (crates/perry-runtime/src/proxy.rs:902), whose dispatch is
    match args.len() { 0..=3 => js_closure_callN, _ => js_closure_call4(closure, a(0), a(1), a(2), a(3)) } — every
    length ≥ 4 goes through the 4-argument call. It needs the variadic call path used by Function.prototype.apply.
  • The same _ => js_closure_call4 shape exists in call_trap (proxy.rs:720), but Proxy traps take at most four
    arguments, so that site is not affected.
  • Related: Calls with more than 16 arguments: closure-value calls fail to compile ("closure call with 18 args (max 16)"), dynamic calls get 0 for params 17+ #10420 (apply/call/spread pass 0 for parameters 17+).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    package-auditFound by the 2026 package audit: compiling real npm packages from source instead of native bindings

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions