Files
bun.sh/test/regression/issue/25231.test.ts
robobun 2ab6efeea3 fix(ffi): restore CString constructor functionality (#25257)
## Summary
- Fix regression where `new Bun.FFI.CString(ptr)` throws "function is
not a constructor"
- Pass the same function as both call and constructor callbacks for
CString

## Root Cause
PR #24910 replaced `jsc.createCallback` with `jsc.JSFunction.create` for
all FFI functions. However, `JSFunction.create` doesn't allow
constructor calls by default (it uses `callHostFunctionAsConstructor`
which throws). The old `createCallback` used `JSFFIFunction` which
allowed the same function to be called with `new`.

## Fix
Pass the same function as both the `implementation` and `constructor`
option to `JSFunction.create` for CString specifically. This allows `new
CString(ptr)` to work while keeping the refactoring from #24910.

Additionally, the `bun:ffi` module now replaces `Bun.FFI.CString` with
the proper JS CString class after loading, so users get the full class
with `.ptr`, `.byteOffset`, etc. properties.

## Test plan
- [x] Added regression test `test/regression/issue/25231.test.ts`
- [x] Test fails with `USE_SYSTEM_BUN=1` (v1.3.3), passes with fix
- [x] Verified reproduction case from issue works

Fixes #25231

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-01 15:47:27 -08:00

33 lines
938 B
TypeScript

// https://github.com/oven-sh/bun/issues/25231
// Bun.FFI.CString should be callable as a constructor (new CString(ptr))
import { expect, test } from "bun:test";
test("Bun.FFI.CString is callable with new", () => {
const { CString, ptr } = Bun.FFI;
// Create a buffer with a null-terminated string
const buf = Buffer.from("hello\0");
const ptrValue = ptr(buf);
// CString should be callable with new
const result = new CString(ptrValue, 0, 5);
// The result should be the string "hello"
expect(String(result)).toBe("hello");
});
test("Bun.FFI.CString can be called without new", () => {
const { CString, ptr } = Bun.FFI;
// Create a buffer with a null-terminated string
const buf = Buffer.from("hello\0");
const ptrValue = ptr(buf);
// CString should also be callable without new
const result = CString(ptrValue, 0, 5);
// The result should be the string "hello"
expect(result).toBe("hello");
});