Skip to content

AOT: spread of non-empty typed array passes denormal placeholders to callee #653

Description

@proggeramlug

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.

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