Skip to content

Spread call of a native-module method silently no-ops (js_closure_call_apply_with_spread bypasses bound-native dispatch) #6668

Description

@proggeramlug

Summary

A spread call of a native-module method silently no-ops — no dispatch, no throw, callback never invoked, returns undefined:

const crypto = require("crypto");
const args = ["sha256", ikm, salt, info, 64];

crypto.hkdf("sha256", ikm, salt, info, 64, cb); // ✓ works (direct)
const h = crypto.hkdf; h(...allArgs, cb);        // ✓ works (value call)
crypto.hkdf(...args, cb);                        // ✗ SILENT NO-OP under perry

The spread lowering routes through js_closure_call_apply_with_spreadjs_closure_call_array, which treats the callee as a plain closure; a bound-native-callable box has no valid closure func_ptr, so the per-arity dispatch degrades to returning undefined without ever reaching the module dispatcher — and without an error. (Depending on the callee shape, a sibling route through js_closure_unbox_callee_checked throws value is not a function instead.)

Found alongside #6667 while root-causing the Auth.js credentials-login failure (jose's node-HKDF wrapper is exactly Z.hkdf(...args, cb)); with #6667 fixed, this becomes the next blocker on that path.

Suggested direction

js_closure_call_apply_with_spread (and the checked-unbox spread route) should detect a non-plain-closure callee and delegate to js_native_call_value with the flattened args — that dispatcher already owns the bound-native/proxy/class-object arms. Silent undefined on a failed dispatch is the worst outcome; if delegation is out of scope, at minimum throw.

Observed on main @ 5eb2bc4, macOS arm64.

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