mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
Fix conversions from JSValue to FFI pointer (#25045)
Fixes this issue, where two identical JS numbers could become two
different FFI pointers:
```c
// gcc -fpic -shared -o main.so
#include <stdio.h>
void* getPtr(void) {
return (void*)123;
}
void printPtr(void* ptr) {
printf("%zu\n", (size_t)ptr);
}
```
```js
import { dlopen, FFIType } from "bun:ffi";
const lib = dlopen("./main.so", {
getPtr: { args: [], returns: FFIType.ptr },
printPtr: { args: [FFIType.ptr], returns: FFIType.void },
});
const ptr = lib.symbols.getPtr();
console.log(`${typeof ptr} ${ptr}`);
const ptr2 = Number(String(ptr));
console.log(`${typeof ptr2} ${ptr2}`);
console.log(`pointers equal? ${ptr === ptr2}`);
lib.symbols.printPtr(ptr);
lib.symbols.printPtr(ptr2);
```
```console
$ bun main.js
number 123
number 123
pointers equal? true
123
18446744073709551615
```
Fixes #20072
(For internal tracking: fixes ENG-22327)
This commit is contained in:
@@ -225,23 +225,26 @@ static void* JSVALUE_TO_PTR(EncodedJSValue val) {
|
||||
return 0;
|
||||
|
||||
if (JSCELL_IS_TYPED_ARRAY(val)) {
|
||||
return JSVALUE_TO_TYPED_ARRAY_VECTOR(val);
|
||||
return JSVALUE_TO_TYPED_ARRAY_VECTOR(val);
|
||||
}
|
||||
|
||||
if (JSVALUE_IS_INT32(val)) {
|
||||
return (void*)(uintptr_t)JSVALUE_TO_INT32(val);
|
||||
}
|
||||
|
||||
// Assume the JSValue is a double
|
||||
val.asInt64 -= DoubleEncodeOffset;
|
||||
size_t ptr = (size_t)val.asDouble;
|
||||
return (void*)ptr;
|
||||
return (void*)(uintptr_t)val.asDouble;
|
||||
}
|
||||
|
||||
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) {
|
||||
EncodedJSValue val;
|
||||
if (ptr == 0)
|
||||
{
|
||||
val.asInt64 = TagValueNull;
|
||||
return val;
|
||||
if (ptr == 0) {
|
||||
val.asInt64 = TagValueNull;
|
||||
return val;
|
||||
}
|
||||
|
||||
val.asDouble = (double)(size_t)ptr;
|
||||
val.asDouble = (double)(uintptr_t)ptr;
|
||||
val.asInt64 += DoubleEncodeOffset;
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -100,16 +100,6 @@ pub inline fn BOOLEAN_TO_JSVALUE(arg_val: @"bool") EncodedJSValue {
|
||||
res.asInt64 = @as(i64, @bitCast(@as(c_longlong, if (@as(c_int, @intFromBool(val)) != 0) (@as(c_int, 2) | @as(c_int, 4)) | @as(c_int, 1) else (@as(c_int, 2) | @as(c_int, 4)) | @as(c_int, 0))));
|
||||
return res;
|
||||
}
|
||||
pub inline fn PTR_TO_JSVALUE(arg_ptr: ?*anyopaque) EncodedJSValue {
|
||||
const ptr = arg_ptr;
|
||||
var val: EncodedJSValue = undefined;
|
||||
val.asInt64 = @as(i64, @intCast(@intFromPtr(ptr))) + (@as(c_longlong, 1) << @as(@import("std").math.Log2Int(c_longlong), @intCast(49)));
|
||||
return val;
|
||||
}
|
||||
pub inline fn JSVALUE_TO_PTR(arg_val: EncodedJSValue) ?*anyopaque {
|
||||
const val = arg_val;
|
||||
return @as(?*anyopaque, @ptrFromInt(val.asInt64 - (@as(c_longlong, 1) << @as(@import("std").math.Log2Int(c_longlong), @intCast(49)))));
|
||||
}
|
||||
pub inline fn JSVALUE_TO_INT32(arg_val: EncodedJSValue) i32 {
|
||||
const val = arg_val;
|
||||
return @as(i32, @bitCast(@as(c_int, @truncate(val.asInt64))));
|
||||
|
||||
Reference in New Issue
Block a user