Repository navigation
Closed
Labels
package-auditFound by the 2026 package audit: compiling real npm packages from source instead of native bindingsFound by the 2026 package audit: compiling real npm packages from source instead of native bindings
Description
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 && ./mainExpected (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 withcreate_list_from_array_like, then callscall_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 byFunction.prototype.apply. - The same
_ => js_closure_call4shape exists incall_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 pass0for parameters 17+).
Metadata
Metadata
Assignees
Labels
package-auditFound by the 2026 package audit: compiling real npm packages from source instead of native bindingsFound by the 2026 package audit: compiling real npm packages from source instead of native bindings
Activity
proggeramlug commentedon Sep 17, 2026
Fixed on
mainby PR #10532, landed in merge train #10559 (v0.5.1592) — the train closes its source PRs instead of merging them, so theFixes #10425keyword in #10532 never evaluated. Changelog fragmentchangelog.d/10532-*.mdis onmain.