Summary
When spreading a non-empty array into a function call site, the callee receives 5e-324 (a single denormal double) for each spread slot instead of the actual element values. Spreading an empty array works. Direct positional args work.
Looks like a NaN-box leak similar in shape to #16 / #540, but on the call-site spread path. Both of those are closed; this is a separate occurrence.
Found while running @perryts/redis's benchmark suite under perry compile.
Environment
- perry 0.5.772
- macOS 26.4 / Apple M1 Max
Minimal repro
// repro.ts
function f(name: string, ...args: string[]): string[] {
return [name, ...args];
}
const empty: string[] = [];
const one: string[] = ['x'];
const two: string[] = ['x', 'y'];
console.log('direct: ', f('a'));
console.log('spread empty: ', f('a', ...empty));
console.log('spread 1: ', f('a', ...one));
console.log('spread 2: ', f('a', ...two));
$ perry compile repro.ts -o repro && ./repro
direct: [ 'a' ]
spread empty: [ 'a' ]
spread 1: [ 'a', 5e-324 ]
spread 2: [ 'a', 5e-324 ]
Expected (matches Node + Bun):
direct: [ 'a' ]
spread empty: [ 'a' ]
spread 1: [ 'a', 'x' ]
spread 2: [ 'a', 'x', 'y' ]
Impact
Any call shape like conn.command('HELLO', ...args) — common in TCP drivers / RPC clients building a positional argument list — sends garbage to the callee. The original strings in args still exist, they just don't make it through the spread.
Workaround: avoid the spread by passing the array directly through a non-rest parameter. That's what @perryts/redis is doing for now (commandArray(name, args) instead of command(name, ...args)).
Related (closed)
Same family of NaN-box leakage on the spread path; this one is the array-into-rest-arg variant.
Summary
When spreading a non-empty array into a function call site, the callee receives
5e-324(a single denormal double) for each spread slot instead of the actual element values. Spreading an empty array works. Direct positional args work.Looks like a NaN-box leak similar in shape to #16 / #540, but on the call-site spread path. Both of those are closed; this is a separate occurrence.
Found while running
@perryts/redis's benchmark suite underperry compile.Environment
Minimal repro
Expected (matches Node + Bun):
Impact
Any call shape like
conn.command('HELLO', ...args)— common in TCP drivers / RPC clients building a positional argument list — sends garbage to the callee. The original strings inargsstill exist, they just don't make it through the spread.Workaround: avoid the spread by passing the array directly through a non-rest parameter. That's what
@perryts/redisis doing for now (commandArray(name, args)instead ofcommand(name, ...args)).Related (closed)
[...map]with undefined valuesSame family of NaN-box leakage on the spread path; this one is the array-into-rest-arg variant.