Skip to content

ffi: Fast FFI buffer/arraybuffer signatures reject bigint after optimization #64638

Description

@trivikr

Version

main

Platform

macOS 26.5.2

Subsystem

ffi

What steps will reproduce the bug?

repro.c

#include <stdint.h>

__attribute__((visibility("default")))
uintptr_t pointer_to_usize(void* pointer) {
  return (uintptr_t)pointer;
}

Build it by running

$ cc -dynamiclib repro.c -o librepro.dylib

repro.js

import { dlopen } from "node:ffi";

const { lib, functions } = dlopen("./librepro.dylib", {
  pointer_to_usize: {
    arguments: ["buffer"], // Also reproduces with 'arraybuffer'.
    return: "u64",
  },
});

function call(value) {
  return functions.pointer_to_usize(value);
}

console.log("before:", call(0n));

try {
  for (let i = 0; i < 1_000_000; i++)
    call(0n);
  console.log('after:', call(0n));
} catch (error) {
  console.log('after:', error.code, error.message);
}

lib.close();

Run it using

$ node --no-warnings --experimental-ffi --allow-natives-syntax repro.js

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior? Why is that the expected behavior?

before: 0n
after: 0n

Optimization should not change accepted inputs; buffer and arraybuffer signatures should continue accepting documented pointer-like values such as bigint.

What do you see instead?

before: 0n
after: ERR_INVALID_ARG_VALUE Argument 0 must be a buffer or an ArrayBuffer

The initial generic call accepts 0n, but after optimization the same call throws ERR_INVALID_ARG_VALUE

Additional information

No response

Metadata

Metadata

Assignees

Labels

ffiIssues and PRs related to experimental Foreign Function Interface support.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions