summaryrefslogtreecommitdiff
path: root/ext/ffi/lib.rs
diff options
context:
space:
mode:
authorAapo Alasuutari <aapo.alasuutari@gmail.com>2022-07-24 13:41:11 +0300
committerGitHub <noreply@github.com>2022-07-24 16:11:11 +0530
commitf8fee6cd21cce82d6c34e539d39da86df7b036f7 (patch)
tree8099527951e4b532934a00c25797758aeb496ab6 /ext/ffi/lib.rs
parente1cbd2364f536a1cef817961967e1738b89be734 (diff)
feat(ext/ffi): Safe number pointers (#15173)
Diffstat (limited to 'ext/ffi/lib.rs')
-rw-r--r--ext/ffi/lib.rs948
1 files changed, 562 insertions, 386 deletions
diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs
index 396affdb3..6d0315964 100644
--- a/ext/ffi/lib.rs
+++ b/ext/ffi/lib.rs
@@ -48,6 +48,9 @@ thread_local! {
static LOCAL_ISOLATE_POINTER: RefCell<*const v8::Isolate> = RefCell::new(ptr::null());
}
+const MAX_SAFE_INTEGER: isize = 9007199254740991;
+const MIN_SAFE_INTEGER: isize = -9007199254740991;
+
pub struct Unstable(pub bool);
fn check_unstable(state: &OpState, api_name: &str) {
@@ -93,7 +96,7 @@ struct PtrSymbol {
}
impl PtrSymbol {
- fn new(fn_ptr: u64, def: &ForeignFunction) -> Self {
+ fn new(fn_ptr: usize, def: &ForeignFunction) -> Self {
let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _);
let cif = libffi::middle::Cif::new(
def
@@ -175,6 +178,7 @@ pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension {
op_ffi_read_u32::decl::<P>(),
op_ffi_read_i32::decl::<P>(),
op_ffi_read_u64::decl::<P>(),
+ op_ffi_read_i64::decl::<P>(),
op_ffi_read_f32::decl::<P>(),
op_ffi_read_f64::decl::<P>(),
op_ffi_unsafe_callback_create::decl::<P>(),
@@ -323,21 +327,46 @@ impl NativeValue {
NativeType::U32 => Value::from(self.u32_value),
NativeType::I32 => Value::from(self.i32_value),
NativeType::U64 => {
- json!(U32x2::from(self.u64_value))
+ let value = self.u64_value;
+ if value > MAX_SAFE_INTEGER as u64 {
+ json!(U32x2::from(self.u64_value))
+ } else {
+ Value::from(value)
+ }
}
NativeType::I64 => {
- json!(U32x2::from(self.i64_value as u64))
+ let value = self.i64_value;
+ if value > MAX_SAFE_INTEGER as i64 || value < MIN_SAFE_INTEGER as i64 {
+ json!(U32x2::from(self.i64_value as u64))
+ } else {
+ Value::from(value)
+ }
}
NativeType::USize => {
- json!(U32x2::from(self.usize_value as u64))
+ let value = self.usize_value;
+ if value > MAX_SAFE_INTEGER as usize {
+ json!(U32x2::from(self.usize_value as u64))
+ } else {
+ Value::from(value)
+ }
}
NativeType::ISize => {
- json!(U32x2::from(self.isize_value as u64))
+ let value = self.isize_value;
+ if value > MAX_SAFE_INTEGER || value < MIN_SAFE_INTEGER {
+ json!(U32x2::from(self.isize_value as u64))
+ } else {
+ Value::from(value)
+ }
}
NativeType::F32 => Value::from(self.f32_value),
NativeType::F64 => Value::from(self.f64_value),
NativeType::Pointer | NativeType::Function => {
- json!(U32x2::from(self.pointer as u64))
+ let value = self.pointer as usize;
+ if value > MAX_SAFE_INTEGER as usize {
+ json!(U32x2::from(value as u64))
+ } else {
+ Value::from(value)
+ }
}
}
}
@@ -385,23 +414,44 @@ impl NativeValue {
local_value.into()
}
NativeType::U64 => {
+ let value = self.u64_value;
let local_value: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, self.u64_value).into();
+ if value > MAX_SAFE_INTEGER as u64 {
+ v8::BigInt::new_from_u64(scope, value).into()
+ } else {
+ v8::Number::new(scope, value as f64).into()
+ };
local_value.into()
}
NativeType::I64 => {
+ let value = self.i64_value;
let local_value: v8::Local<v8::Value> =
- v8::BigInt::new_from_i64(scope, self.i64_value).into();
+ if value > MAX_SAFE_INTEGER as i64 || value < MIN_SAFE_INTEGER as i64
+ {
+ v8::BigInt::new_from_i64(scope, self.i64_value).into()
+ } else {
+ v8::Number::new(scope, value as f64).into()
+ };
local_value.into()
}
NativeType::USize => {
+ let value = self.usize_value;
let local_value: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, self.usize_value as u64).into();
+ if value > MAX_SAFE_INTEGER as usize {
+ v8::BigInt::new_from_u64(scope, value as u64).into()
+ } else {
+ v8::Number::new(scope, value as f64).into()
+ };
local_value.into()
}
NativeType::ISize => {
+ let value = self.isize_value;
let local_value: v8::Local<v8::Value> =
- v8::BigInt::new_from_i64(scope, self.isize_value as i64).into();
+ if value > MAX_SAFE_INTEGER || value < MIN_SAFE_INTEGER {
+ v8::BigInt::new_from_i64(scope, self.isize_value as i64).into()
+ } else {
+ v8::Number::new(scope, value as f64).into()
+ };
local_value.into()
}
NativeType::F32 => {
@@ -415,8 +465,13 @@ impl NativeValue {
local_value.into()
}
NativeType::Pointer | NativeType::Function => {
+ let value = self.pointer as u64;
let local_value: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, self.pointer as u64).into();
+ if value > MAX_SAFE_INTEGER as u64 {
+ v8::BigInt::new_from_u64(scope, value).into()
+ } else {
+ v8::Number::new(scope, value as f64).into()
+ };
local_value.into()
}
}
@@ -677,10 +732,11 @@ impl From<&NativeType> for fast_api::Type {
NativeType::F32 => fast_api::Type::Float32,
NativeType::F64 => fast_api::Type::Float64,
NativeType::Void => fast_api::Type::Void,
- NativeType::I64 | NativeType::ISize => fast_api::Type::Int64,
- NativeType::U64 | NativeType::USize => fast_api::Type::Uint64,
- NativeType::Function | NativeType::Pointer => {
- panic!("Cannot be fast api")
+ NativeType::I64 => fast_api::Type::Int64,
+ NativeType::U64 => fast_api::Type::Uint64,
+ NativeType::ISize => fast_api::Type::Int64,
+ NativeType::USize | NativeType::Function | NativeType::Pointer => {
+ fast_api::Type::Uint64
}
}
}
@@ -699,11 +755,6 @@ fn is_fast_api_rv(rv: NativeType) -> bool {
)
}
-#[cfg(not(target_os = "windows"))]
-fn is_fast_api_arg(rv: NativeType) -> bool {
- !matches!(rv, NativeType::Function | NativeType::Pointer)
-}
-
// Create a JavaScript function for synchronous FFI call to
// the given symbol.
fn make_sync_fn<'s>(
@@ -719,10 +770,7 @@ fn make_sync_fn<'s>(
#[cfg(not(target_os = "windows"))]
let mut fast_allocations: Option<*mut ()> = None;
#[cfg(not(target_os = "windows"))]
- if !sym.can_callback
- && !sym.parameter_types.iter().any(|t| !is_fast_api_arg(*t))
- && is_fast_api_rv(sym.result_type)
- {
+ if !sym.can_callback && is_fast_api_rv(sym.result_type) {
let ret = fast_api::Type::from(&sym.result_type);
let mut args = sym
@@ -792,6 +840,228 @@ fn make_sync_fn<'s>(
weak.to_local(scope).unwrap()
}
+#[inline]
+fn ffi_parse_u8_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let u8_value = v8::Local::<v8::Uint32>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI u8 type, expected unsigned integer"))?
+ .value() as u8;
+ Ok(NativeValue { u8_value })
+}
+
+#[inline]
+fn ffi_parse_i8_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let i8_value = v8::Local::<v8::Int32>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI i8 type, expected integer"))?
+ .value() as i8;
+ Ok(NativeValue { i8_value })
+}
+
+#[inline]
+fn ffi_parse_u16_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let u16_value = v8::Local::<v8::Uint32>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI u16 type, expected unsigned integer"))?
+ .value() as u16;
+ Ok(NativeValue { u16_value })
+}
+
+#[inline]
+fn ffi_parse_i16_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let i16_value = v8::Local::<v8::Int32>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI i16 type, expected integer"))?
+ .value() as i16;
+ Ok(NativeValue { i16_value })
+}
+
+#[inline]
+fn ffi_parse_u32_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let u32_value = v8::Local::<v8::Uint32>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI u32 type, expected unsigned integer"))?
+ .value() as u32;
+ Ok(NativeValue { u32_value })
+}
+
+#[inline]
+fn ffi_parse_i32_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let i32_value = v8::Local::<v8::Int32>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI i32 type, expected integer"))?
+ .value() as i32;
+ Ok(NativeValue { i32_value })
+}
+
+#[inline]
+fn ffi_parse_u64_arg(
+ scope: &mut v8::HandleScope,
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ // Order of checking:
+ // 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
+ // 2. Number: Common, supported by Fast API, so let that be the optimal case.
+ let u64_value: u64 = if let Ok(value) = v8::Local::<v8::BigInt>::try_from(arg)
+ {
+ value.u64_value().0
+ } else if let Ok(value) = v8::Local::<v8::Number>::try_from(arg) {
+ value.integer_value(scope).unwrap() as u64
+ } else {
+ return Err(type_error(
+ "Invalid FFI u64 type, expected unsigned integer",
+ ));
+ };
+ Ok(NativeValue { u64_value })
+}
+
+#[inline]
+fn ffi_parse_i64_arg(
+ scope: &mut v8::HandleScope,
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ // Order of checking:
+ // 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
+ // 2. Number: Common, supported by Fast API, so let that be the optimal case.
+ let i64_value: i64 = if let Ok(value) = v8::Local::<v8::BigInt>::try_from(arg)
+ {
+ value.i64_value().0
+ } else if let Ok(value) = v8::Local::<v8::Number>::try_from(arg) {
+ value.integer_value(scope).unwrap() as i64
+ } else {
+ return Err(type_error("Invalid FFI i64 type, expected integer"));
+ };
+ Ok(NativeValue { i64_value })
+}
+
+#[inline]
+fn ffi_parse_usize_arg(
+ scope: &mut v8::HandleScope,
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ // Order of checking:
+ // 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
+ // 2. Number: Common, supported by Fast API, so let that be the optimal case.
+ let usize_value: usize =
+ if let Ok(value) = v8::Local::<v8::BigInt>::try_from(arg) {
+ value.u64_value().0 as usize
+ } else if let Ok(value) = v8::Local::<v8::Number>::try_from(arg) {
+ value.integer_value(scope).unwrap() as usize
+ } else {
+ return Err(type_error("Invalid FFI usize type, expected integer"));
+ };
+ Ok(NativeValue { usize_value })
+}
+
+#[inline]
+fn ffi_parse_isize_arg(
+ scope: &mut v8::HandleScope,
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ // Order of checking:
+ // 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
+ // 2. Number: Common, supported by Fast API, so let that be the optimal case.
+ let isize_value: isize =
+ if let Ok(value) = v8::Local::<v8::BigInt>::try_from(arg) {
+ value.i64_value().0 as isize
+ } else if let Ok(value) = v8::Local::<v8::Number>::try_from(arg) {
+ value.integer_value(scope).unwrap() as isize
+ } else {
+ return Err(type_error("Invalid FFI isize type, expected integer"));
+ };
+ Ok(NativeValue { isize_value })
+}
+
+#[inline]
+fn ffi_parse_f32_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let f32_value = v8::Local::<v8::Number>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI f32 type, expected number"))?
+ .value() as f32;
+ Ok(NativeValue { f32_value })
+}
+
+#[inline]
+fn ffi_parse_f64_arg(
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ let f64_value = v8::Local::<v8::Number>::try_from(arg)
+ .map_err(|_| type_error("Invalid FFI f64 type, expected number"))?
+ .value() as f64;
+ Ok(NativeValue { f64_value })
+}
+
+#[inline]
+fn ffi_parse_pointer_arg(
+ scope: &mut v8::HandleScope,
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ // Order of checking:
+ // 1. ArrayBufferView: Common and not supported by Fast API, optimise this case.
+ // 2. BigInt: Uncommon and not supported by Fast API, optimise this case as second.
+ // 3. Number: Common and supported by Fast API, optimise the common case third.
+ // 4. ArrayBuffer: Fairly common and not supported by Fast API.
+ // 5. Null: Very uncommon / can be represented by a 0.
+ let pointer = if let Ok(value) =
+ v8::Local::<v8::ArrayBufferView>::try_from(arg)
+ {
+ let byte_offset = value.byte_offset();
+ let backing_store = value
+ .buffer(scope)
+ .ok_or_else(|| {
+ type_error("Invalid FFI ArrayBufferView, expected data in the buffer")
+ })?
+ .get_backing_store();
+ if byte_offset > 0 {
+ &backing_store[byte_offset..] as *const _ as *const u8
+ } else {
+ &backing_store[..] as *const _ as *const u8
+ }
+ } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(arg) {
+ value.u64_value().0 as usize as *const u8
+ } else if let Ok(value) = v8::Local::<v8::Number>::try_from(arg) {
+ value.integer_value(scope).unwrap() as usize as *const u8
+ } else if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(arg) {
+ let backing_store = value.get_backing_store();
+ &backing_store[..] as *const _ as *const u8
+ } else if arg.is_null() {
+ ptr::null()
+ } else {
+ return Err(type_error("Invalid FFI pointer type, expected null, integer, BigInt, ArrayBuffer, or ArrayBufferView"));
+ };
+ Ok(NativeValue { pointer })
+}
+
+#[inline]
+fn ffi_parse_function_arg(
+ scope: &mut v8::HandleScope,
+ arg: v8::Local<v8::Value>,
+) -> Result<NativeValue, AnyError> {
+ // Order of checking:
+ // 1. BigInt: Uncommon and not supported by Fast API, optimise this case.
+ // 2. Number: Common and supported by Fast API, optimise this case as second.
+ // 3. Null: Very uncommon / can be represented by a 0.
+ let pointer = if let Ok(value) = v8::Local::<v8::BigInt>::try_from(arg) {
+ value.u64_value().0 as usize as *const u8
+ } else if let Ok(value) = v8::Local::<v8::Number>::try_from(arg) {
+ value.integer_value(scope).unwrap() as usize as *const u8
+ } else if arg.is_null() {
+ ptr::null()
+ } else {
+ return Err(type_error(
+ "Invalid FFI function type, expected null, integer, or BigInt",
+ ));
+ };
+ Ok(NativeValue { pointer })
+}
+
fn ffi_parse_args<'scope>(
scope: &mut v8::HandleScope<'scope>,
args: serde_v8::Value<'scope>,
@@ -812,155 +1082,50 @@ where
for (index, native_type) in parameter_types.iter().enumerate() {
let value = args.get_index(scope, index as u32).unwrap();
match native_type {
- NativeType::Void => {
- unreachable!();
- }
NativeType::U8 => {
- let value = value
- .uint32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI u8 type, expected number"))?
- as u8;
- ffi_args.push(NativeValue { u8_value: value });
+ ffi_args.push(ffi_parse_u8_arg(value)?);
}
NativeType::I8 => {
- let value = value
- .int32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI i8 type, expected number"))?
- as i8;
- ffi_args.push(NativeValue { i8_value: value });
+ ffi_args.push(ffi_parse_i8_arg(value)?);
}
NativeType::U16 => {
- let value = value
- .uint32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI u16 type, expected number"))?
- as u16;
- ffi_args.push(NativeValue { u16_value: value });
+ ffi_args.push(ffi_parse_u16_arg(value)?);
}
NativeType::I16 => {
- let value = value
- .int32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI i16 type, expected number"))?
- as i16;
- ffi_args.push(NativeValue { i16_value: value });
+ ffi_args.push(ffi_parse_i16_arg(value)?);
}
NativeType::U32 => {
- let value = value
- .uint32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI u32 type, expected number"))?
- as u32;
- ffi_args.push(NativeValue { u32_value: value });
+ ffi_args.push(ffi_parse_u32_arg(value)?);
}
NativeType::I32 => {
- let value = value
- .int32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI i32 type, expected number"))?
- as i32;
- ffi_args.push(NativeValue { i32_value: value });
+ ffi_args.push(ffi_parse_i32_arg(value)?);
}
NativeType::U64 => {
- let value: u64 =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.u64_value().0
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI u64 type, expected number")
- })? as u64
- };
- ffi_args.push(NativeValue { u64_value: value });
+ ffi_args.push(ffi_parse_u64_arg(scope, value)?);
}
NativeType::I64 => {
- let value: i64 =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.i64_value().0
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI i64 type, expected number")
- })? as i64
- };
- ffi_args.push(NativeValue { i64_value: value });
+ ffi_args.push(ffi_parse_i64_arg(scope, value)?);
}
NativeType::USize => {
- let value: usize =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.u64_value().0 as usize
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI usize type, expected number")
- })? as usize
- };
- ffi_args.push(NativeValue { usize_value: value });
+ ffi_args.push(ffi_parse_usize_arg(scope, value)?);
}
NativeType::ISize => {
- let value: isize =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.i64_value().0 as isize
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI isize type, expected number")
- })? as isize
- };
- ffi_args.push(NativeValue { isize_value: value });
+ ffi_args.push(ffi_parse_isize_arg(scope, value)?);
}
NativeType::F32 => {
- let value = value
- .number_value(scope)
- .ok_or_else(|| type_error("Invalid FFI f32 type, expected number"))?
- as f32;
- ffi_args.push(NativeValue { f32_value: value });
+ ffi_args.push(ffi_parse_f32_arg(value)?);
}
NativeType::F64 => {
- let value = value
- .number_value(scope)
- .ok_or_else(|| type_error("Invalid FFI f64 type, expected number"))?
- as f64;
- ffi_args.push(NativeValue { f64_value: value });
+ ffi_args.push(ffi_parse_f64_arg(value)?);
}
NativeType::Pointer => {
- if value.is_null() {
- let value: *const u8 = ptr::null();
- ffi_args.push(NativeValue { pointer: value })
- } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- let value = value.u64_value().0 as *const u8;
- ffi_args.push(NativeValue { pointer: value });
- } else if let Ok(value) =
- v8::Local::<v8::ArrayBufferView>::try_from(value)
- {
- let byte_offset = value.byte_offset();
- let backing_store = value
- .buffer(scope)
- .ok_or_else(|| {
- type_error(
- "Invalid FFI ArrayBufferView, expected data in the buffer",
- )
- })?
- .get_backing_store();
- let pointer = if byte_offset > 0 {
- &backing_store[byte_offset..] as *const _ as *const u8
- } else {
- &backing_store[..] as *const _ as *const u8
- };
- ffi_args.push(NativeValue { pointer });
- } else if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(value)
- {
- let backing_store = value.get_backing_store();
- let pointer = &backing_store[..] as *const _ as *const u8;
- ffi_args.push(NativeValue { pointer });
- } else {
- return Err(type_error("Invalid FFI pointer type, expected null, BigInt, ArrayBuffer, or ArrayBufferView"));
- }
+ ffi_args.push(ffi_parse_pointer_arg(scope, value)?);
}
NativeType::Function => {
- if value.is_null() {
- let value: *const u8 = ptr::null();
- ffi_args.push(NativeValue { pointer: value })
- } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- let value = value.u64_value().0 as *const u8;
- ffi_args.push(NativeValue { pointer: value });
- } else {
- return Err(type_error(
- "Invalid FFI function type, expected null, or BigInt",
- ));
- }
+ ffi_args.push(ffi_parse_function_arg(scope, value)?);
+ }
+ NativeType::Void => {
+ unreachable!();
}
}
}
@@ -990,169 +1155,50 @@ where
for (index, native_type) in parameter_types.iter().enumerate() {
let value = args.get(index as i32);
match native_type {
- NativeType::Void => {
- unreachable!();
- }
NativeType::U8 => {
- let value = value
- .uint32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI u8 type, expected number"))?
- as u8;
- ffi_args.push(NativeValue { u8_value: value });
+ ffi_args.push(ffi_parse_u8_arg(value)?);
}
NativeType::I8 => {
- let value = value
- .int32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI i8 type, expected number"))?
- as i8;
-
- ffi_args.push(NativeValue { i8_value: value });
+ ffi_args.push(ffi_parse_i8_arg(value)?);
}
NativeType::U16 => {
- let value = value
- .uint32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI u16 type, expected number"))?
- as u16;
-
- ffi_args.push(NativeValue { u16_value: value });
+ ffi_args.push(ffi_parse_u16_arg(value)?);
}
NativeType::I16 => {
- let value = value
- .int32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI i16 type, expected number"))?
- as i16;
-
- ffi_args.push(NativeValue { i16_value: value });
+ ffi_args.push(ffi_parse_i16_arg(value)?);
}
NativeType::U32 => {
- let value = value
- .uint32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI u32 type, expected number"))?
- as u32;
-
- ffi_args.push(NativeValue { u32_value: value });
+ ffi_args.push(ffi_parse_u32_arg(value)?);
}
NativeType::I32 => {
- let value = value
- .int32_value(scope)
- .ok_or_else(|| type_error("Invalid FFI i32 type, expected number"))?
- as i32;
-
- ffi_args.push(NativeValue { i32_value: value });
+ ffi_args.push(ffi_parse_i32_arg(value)?);
}
NativeType::U64 => {
- let value: u64 =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.u64_value().0
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI u64 type, expected number")
- })? as u64
- };
-
- ffi_args.push(NativeValue { u64_value: value });
+ ffi_args.push(ffi_parse_u64_arg(scope, value)?);
}
NativeType::I64 => {
- let value: i64 =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.i64_value().0
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI i64 type, expected number")
- })? as i64
- };
-
- ffi_args.push(NativeValue { i64_value: value });
+ ffi_args.push(ffi_parse_i64_arg(scope, value)?);
}
NativeType::USize => {
- let value: usize =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.u64_value().0 as usize
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI usize type, expected number")
- })? as usize
- };
-
- ffi_args.push(NativeValue { usize_value: value });
+ ffi_args.push(ffi_parse_usize_arg(scope, value)?);
}
NativeType::ISize => {
- let value: isize =
- if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- value.i64_value().0 as isize
- } else {
- value.integer_value(scope).ok_or_else(|| {
- type_error("Invalid FFI isize type, expected number")
- })? as isize
- };
-
- ffi_args.push(NativeValue { isize_value: value });
+ ffi_args.push(ffi_parse_isize_arg(scope, value)?);
}
NativeType::F32 => {
- let value = value
- .number_value(scope)
- .ok_or_else(|| type_error("Invalid FFI f32 type, expected number"))?
- as f32;
-
- ffi_args.push(NativeValue { f32_value: value });
+ ffi_args.push(ffi_parse_f32_arg(value)?);
}
NativeType::F64 => {
- let value = value
- .number_value(scope)
- .ok_or_else(|| type_error("Invalid FFI f64 type, expected number"))?
- as f64;
- ffi_args.push(NativeValue { f64_value: value });
+ ffi_args.push(ffi_parse_f64_arg(value)?);
}
NativeType::Pointer => {
- if value.is_null() {
- let value: *const u8 = ptr::null();
-
- ffi_args.push(NativeValue { pointer: value })
- } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- let value = value.u64_value().0 as *const u8;
-
- ffi_args.push(NativeValue { pointer: value });
- } else if let Ok(value) =
- v8::Local::<v8::ArrayBufferView>::try_from(value)
- {
- let byte_offset = value.byte_offset();
- let backing_store = value
- .buffer(scope)
- .ok_or_else(|| {
- type_error(
- "Invalid FFI ArrayBufferView, expected data in the buffer",
- )
- })?
- .get_backing_store();
- let pointer = if byte_offset > 0 {
- &backing_store[byte_offset..] as *const _ as *const u8
- } else {
- &backing_store[..] as *const _ as *const u8
- };
-
- ffi_args.push(NativeValue { pointer });
- } else if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(value)
- {
- let backing_store = value.get_backing_store();
- let pointer = &backing_store[..] as *const _ as *const u8;
-
- ffi_args.push(NativeValue { pointer });
- } else {
- return Err(type_error("Invalid FFI pointer type, expected null, BigInt, ArrayBuffer, or ArrayBufferView"));
- }
+ ffi_args.push(ffi_parse_pointer_arg(scope, value)?);
}
NativeType::Function => {
- if value.is_null() {
- let value: *const u8 = ptr::null();
- ffi_args.push(NativeValue { pointer: value })
- } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- let value = value.u64_value().0 as *const u8;
- ffi_args.push(NativeValue { pointer: value });
- } else {
- return Err(type_error(
- "Invalid FFI function type, expected null, or BigInt",
- ));
- }
+ ffi_args.push(ffi_parse_function_arg(scope, value)?);
+ }
+ NativeType::Void => {
+ unreachable!();
}
}
}
@@ -1373,8 +1419,8 @@ unsafe fn do_ffi_callback(
// it somehow cannot change the values that the loop sees, even if they both
// refer the same `let bool_value`.
let mut cb_scope = v8::CallbackScope::new(context);
- let mut scope = v8::HandleScope::new(&mut cb_scope);
- let func = callback.open(&mut scope);
+ let scope = &mut v8::HandleScope::new(&mut cb_scope);
+ let func = callback.open(scope);
let result = result as *mut c_void;
let repr: &[*mut ffi_type] =
std::slice::from_raw_parts(cif.arg_types, cif.nargs as usize);
@@ -1386,45 +1432,62 @@ unsafe fn do_ffi_callback(
let value: v8::Local<v8::Value> = match (*(*repr)).type_ as _ {
FFI_TYPE_FLOAT => {
let value = *((*val) as *const f32);
- v8::Number::new(&mut scope, value as f64).into()
+ v8::Number::new(scope, value as f64).into()
}
FFI_TYPE_DOUBLE => {
let value = *((*val) as *const f64);
- v8::Number::new(&mut scope, value).into()
+ v8::Number::new(scope, value).into()
}
FFI_TYPE_SINT8 => {
let value = *((*val) as *const i8);
- v8::Integer::new(&mut scope, value as i32).into()
+ v8::Integer::new(scope, value as i32).into()
}
FFI_TYPE_UINT8 => {
let value = *((*val) as *const u8);
- v8::Integer::new_from_unsigned(&mut scope, value as u32).into()
+ v8::Integer::new_from_unsigned(scope, value as u32).into()
}
FFI_TYPE_SINT16 => {
let value = *((*val) as *const i16);
- v8::Integer::new(&mut scope, value as i32).into()
+ v8::Integer::new(scope, value as i32).into()
}
FFI_TYPE_UINT16 => {
let value = *((*val) as *const u16);
- v8::Integer::new_from_unsigned(&mut scope, value as u32).into()
+ v8::Integer::new_from_unsigned(scope, value as u32).into()
}
FFI_TYPE_INT | FFI_TYPE_SINT32 => {
let value = *((*val) as *const i32);
- v8::Integer::new(&mut scope, value).into()
+ v8::Integer::new(scope, value).into()
}
FFI_TYPE_UINT32 => {
let value = *((*val) as *const u32);
- v8::Integer::new_from_unsigned(&mut scope, value).into()
+ v8::Integer::new_from_unsigned(scope, value).into()
}
FFI_TYPE_SINT64 => {
let result = *((*val) as *const i64);
- v8::BigInt::new_from_i64(&mut scope, result).into()
+ if result > MAX_SAFE_INTEGER as i64 || result < MIN_SAFE_INTEGER as i64
+ {
+ v8::BigInt::new_from_i64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ }
}
- FFI_TYPE_POINTER | FFI_TYPE_STRUCT | FFI_TYPE_UINT64 => {
+ FFI_TYPE_UINT64 => {
let result = *((*val) as *const u64);
- v8::BigInt::new_from_u64(&mut scope, result).into()
+ if result > MAX_SAFE_INTEGER as u64 {
+ v8::BigInt::new_from_u64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ }
}
- FFI_TYPE_VOID => v8::undefined(&mut scope).into(),
+ FFI_TYPE_POINTER | FFI_TYPE_STRUCT => {
+ let result = *((*val) as *const u64);
+ if result > MAX_SAFE_INTEGER as u64 {
+ v8::BigInt::new_from_u64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ }
+ }
+ FFI_TYPE_VOID => v8::undefined(scope).into(),
_ => {
unreachable!()
}
@@ -1432,8 +1495,8 @@ unsafe fn do_ffi_callback(
params.push(value);
}
- let recv = v8::undefined(&mut scope);
- let call_result = func.call(&mut scope, recv.into(), &params);
+ let recv = v8::undefined(scope);
+ let call_result = func.call(scope, recv.into(), &params);
std::mem::forget(callback);
if call_result.is_none() {
@@ -1461,7 +1524,7 @@ unsafe fn do_ffi_callback(
}
FFI_TYPE_POINTER | FFI_TYPE_STRUCT | FFI_TYPE_UINT64
| FFI_TYPE_SINT64 => {
- *(result as *mut u64) = 0;
+ *(result as *mut usize) = 0;
}
FFI_TYPE_VOID => {
// nop
@@ -1477,87 +1540,134 @@ unsafe fn do_ffi_callback(
match (*cif.rtype).type_ as _ {
FFI_TYPE_INT | FFI_TYPE_SINT32 => {
- *(result as *mut i32) = value
- .int32_value(&mut scope)
- .expect("Unable to deserialize result parameter.")
- as i32;
+ let value = if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ value.value() as i32
+ } else {
+ // Fallthrough, probably UB.
+ value
+ .int32_value(scope)
+ .expect("Unable to deserialize result parameter.") as i32
+ };
+ *(result as *mut i32) = value;
}
FFI_TYPE_FLOAT => {
- *(result as *mut f32) = value
- .number_value(&mut scope)
- .expect("Unable to deserialize result parameter.")
- as f32;
+ let value = if let Ok(value) = v8::Local::<v8::Number>::try_from(value) {
+ value.value() as f32
+ } else {
+ // Fallthrough, probably UB.
+ value
+ .number_value(scope)
+ .expect("Unable to deserialize result parameter.") as f32
+ };
+ *(result as *mut f32) = value;
}
FFI_TYPE_DOUBLE => {
- *(result as *mut f64) = value
- .number_value(&mut scope)
- .expect("Unable to deserialize result parameter.");
+ let value = if let Ok(value) = v8::Local::<v8::Number>::try_from(value) {
+ value.value()
+ } else {
+ // Fallthrough, probably UB.
+ value
+ .number_value(scope)
+ .expect("Unable to deserialize result parameter.")
+ };
+ *(result as *mut f64) = value;
}
FFI_TYPE_POINTER | FFI_TYPE_STRUCT => {
- if let Ok(value) = v8::Local::<v8::ArrayBufferView>::try_from(value) {
+ let pointer = if let Ok(value) =
+ v8::Local::<v8::ArrayBufferView>::try_from(value)
+ {
let byte_offset = value.byte_offset();
let backing_store = value
- .buffer(&mut scope)
+ .buffer(scope)
.expect("Unable to deserialize result parameter.")
.get_backing_store();
- let pointer = if byte_offset > 0 {
+ if byte_offset > 0 {
&backing_store[byte_offset..] as *const _ as *const u8
} else {
&backing_store[..] as *const _ as *const u8
- };
- *(result as *mut *const u8) = pointer;
+ }
+ } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
+ value.u64_value().0 as usize as *const u8
} else if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(value) {
let backing_store = value.get_backing_store();
- let pointer = &backing_store[..] as *const _ as *const u8;
- *(result as *mut *const u8) = pointer;
- } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
- *(result as *mut u64) = value.u64_value().0;
+ &backing_store[..] as *const _ as *const u8
+ } else if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ value.value() as usize as *const u8
} else if value.is_null() {
- *(result as *mut *const c_void) = ptr::null();
+ ptr::null()
} else {
// Fallthrough: Probably someone returned a number but this could
// also be eg. a string. This is essentially UB.
- *(result as *mut u64) = value
- .integer_value(&mut scope)
- .expect("Unable to deserialize result parameter.")
- as u64;
- }
+ value
+ .integer_value(scope)
+ .expect("Unable to deserialize result parameter.") as usize
+ as *const u8
+ };
+ *(result as *mut *const u8) = pointer;
}
FFI_TYPE_SINT8 => {
- *(result as *mut i8) = value
- .int32_value(&mut scope)
- .expect("Unable to deserialize result parameter.")
- as i8;
+ let value = if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ value.value() as i8
+ } else {
+ // Fallthrough, essentially UB.
+ value
+ .int32_value(scope)
+ .expect("Unable to deserialize result parameter.") as i8
+ };
+ *(result as *mut i8) = value;
}
FFI_TYPE_UINT8 => {
- *(result as *mut u8) = value
- .uint32_value(&mut scope)
- .expect("Unable to deserialize result parameter.")
- as u8;
+ let value = if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ value.value() as u8
+ } else {
+ // Fallthrough, essentially UB.
+ value
+ .uint32_value(scope)
+ .expect("Unable to deserialize result parameter.") as u8
+ };
+ *(result as *mut u8) = value;
}
FFI_TYPE_SINT16 => {
- *(result as *mut i16) = value
- .int32_value(&mut scope)
- .expect("Unable to deserialize result parameter.")
- as i16;
+ let value = if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ value.value() as i16
+ } else {
+ // Fallthrough, essentially UB.
+ value
+ .int32_value(scope)
+ .expect("Unable to deserialize result parameter.") as i16
+ };
+ *(result as *mut i16) = value;
}
FFI_TYPE_UINT16 => {
- *(result as *mut u16) = value
- .uint32_value(&mut scope)
- .expect("Unable to deserialize result parameter.")
- as u16;
+ let value = if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ value.value() as u16
+ } else {
+ // Fallthrough, essentially UB.
+ value
+ .uint32_value(scope)
+ .expect("Unable to deserialize result parameter.") as u16
+ };
+ *(result as *mut u16) = value;
}
FFI_TYPE_UINT32 => {
- *(result as *mut u32) = value
- .uint32_value(&mut scope)
- .expect("Unable to deserialize result parameter.");
+ let value = if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ value.value() as u32
+ } else {
+ // Fallthrough, essentially UB.
+ value
+ .uint32_value(scope)
+ .expect("Unable to deserialize result parameter.")
+ };
+ *(result as *mut u32) = value;
}
FFI_TYPE_SINT64 => {
if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
*(result as *mut i64) = value.i64_value().0;
+ } else if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ *(result as *mut i64) = value.value();
} else {
*(result as *mut i64) = value
- .integer_value(&mut scope)
+ .integer_value(scope)
.expect("Unable to deserialize result parameter.")
as i64;
}
@@ -1565,9 +1675,11 @@ unsafe fn do_ffi_callback(
FFI_TYPE_UINT64 => {
if let Ok(value) = v8::Local::<v8::BigInt>::try_from(value) {
*(result as *mut u64) = value.u64_value().0;
+ } else if let Ok(value) = v8::Local::<v8::Integer>::try_from(value) {
+ *(result as *mut u64) = value.value() as u64;
} else {
*(result as *mut u64) = value
- .integer_value(&mut scope)
+ .integer_value(scope)
.expect("Unable to deserialize result parameter.")
as u64;
}
@@ -1629,15 +1741,19 @@ where
);
let closure = libffi::middle::Closure::new(cif, deno_ffi_callback, info);
- let ptr = *closure.code_ptr() as usize as u64;
+ let ptr = *closure.code_ptr() as usize;
let resource = UnsafeCallbackResource { closure, info };
let rid = state.resource_table.add(resource);
let rid_local = v8::Integer::new_from_unsigned(scope, rid);
- let ptr_local = v8::BigInt::new_from_u64(scope, ptr);
+ let ptr_local: v8::Local<v8::Value> = if ptr > MAX_SAFE_INTEGER as usize {
+ v8::BigInt::new_from_u64(scope, ptr as u64).into()
+ } else {
+ v8::Number::new(scope, ptr as f64).into()
+ };
let array = v8::Array::new(scope, 2);
array.set_index(scope, 0, rid_local.into());
- array.set_index(scope, 1, ptr_local.into());
+ array.set_index(scope, 1, ptr_local);
let array_value: v8::Local<v8::Value> = array.into();
Ok(array_value.into())
@@ -1647,7 +1763,7 @@ where
fn op_ffi_call_ptr<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>,
state: Rc<RefCell<deno_core::OpState>>,
- pointer: u64,
+ pointer: usize,
def: ForeignFunction,
parameters: serde_v8::Value<'scope>,
) -> Result<serde_v8::Value<'scope>, AnyError>
@@ -1690,7 +1806,7 @@ fn op_ffi_unsafe_callback_ref(state: &mut deno_core::OpState, inc_dec: bool) {
fn op_ffi_call_ptr_nonblocking<'scope, FP>(
scope: &mut v8::HandleScope<'scope>,
state: Rc<RefCell<deno_core::OpState>>,
- pointer: u64,
+ pointer: usize,
def: ForeignFunction,
parameters: serde_v8::Value<'scope>,
) -> Result<impl Future<Output = Result<Value, AnyError>>, AnyError>
@@ -1781,30 +1897,46 @@ fn op_ffi_get_static<'scope>(
NativeType::U64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u64) };
- let big_int: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, result).into();
- big_int.into()
+ let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 {
+ v8::BigInt::new_from_u64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ };
+ integer.into()
}
NativeType::I64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i64) };
- let big_int: v8::Local<v8::Value> =
- v8::BigInt::new_from_i64(scope, result).into();
- big_int.into()
+ let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as i64
+ || result < MIN_SAFE_INTEGER as i64
+ {
+ v8::BigInt::new_from_i64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ };
+ integer.into()
}
NativeType::USize => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const usize) };
- let big_int: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, result as u64).into();
- big_int.into()
+ let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as usize
+ {
+ v8::BigInt::new_from_u64(scope, result as u64).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ };
+ integer.into()
}
NativeType::ISize => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const isize) };
- let big_int: v8::Local<v8::Value> =
- v8::BigInt::new_from_i64(scope, result as i64).into();
- big_int.into()
+ let integer: v8::Local<v8::Value> =
+ if result > MAX_SAFE_INTEGER || result < MIN_SAFE_INTEGER {
+ v8::BigInt::new_from_i64(scope, result as i64).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ };
+ integer.into()
}
NativeType::F32 => {
// SAFETY: ptr is user provided
@@ -1821,9 +1953,12 @@ fn op_ffi_get_static<'scope>(
}
NativeType::Pointer | NativeType::Function => {
let result = data_ptr as u64;
- let big_int: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, result).into();
- big_int.into()
+ let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 {
+ v8::BigInt::new_from_u64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ };
+ integer.into()
}
})
}
@@ -1908,9 +2043,13 @@ where
));
};
- let big_int: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, pointer as u64).into();
- Ok(big_int.into())
+ let integer: v8::Local<v8::Value> =
+ if pointer as usize > MAX_SAFE_INTEGER as usize {
+ v8::BigInt::new_from_u64(scope, pointer as u64).into()
+ } else {
+ v8::Number::new(scope, pointer as usize as f64).into()
+ };
+ Ok(integer.into())
}
unsafe extern "C" fn noop_deleter_callback(
@@ -1935,9 +2074,14 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
- let value = v8::Local::<v8::BigInt>::try_from(src.v8_value)
- .map_err(|_| type_error("Invalid FFI pointer value, expected BigInt"))?;
- let ptr = value.u64_value().0 as usize as *mut c_void;
+ let ptr = if let Ok(value) = v8::Local::<v8::Number>::try_from(src.v8_value) {
+ value.value() as usize as *mut c_void
+ } else if let Ok(value) = v8::Local::<v8::BigInt>::try_from(src.v8_value) {
+ value.u64_value().0 as usize as *mut c_void
+ } else {
+ return Err(type_error("Invalid FFI pointer value, expected BigInt"));
+ };
+
if std::ptr::eq(ptr, std::ptr::null()) {
return Err(type_error("Invalid FFI pointer value, got nullptr"));
}
@@ -1960,7 +2104,7 @@ where
#[op]
fn op_ffi_buf_copy_into<FP>(
state: &mut deno_core::OpState,
- src: u64,
+ src: usize,
mut dst: ZeroCopyBuf,
len: usize,
) -> Result<(), AnyError>
@@ -1989,7 +2133,7 @@ where
fn op_ffi_cstr_read<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>,
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<serde_v8::Value<'scope>, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2013,7 +2157,7 @@ where
#[op]
fn op_ffi_read_u8<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<u8, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2030,7 +2174,7 @@ where
#[op]
fn op_ffi_read_i8<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<i8, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2047,7 +2191,7 @@ where
#[op]
fn op_ffi_read_u16<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<u16, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2064,7 +2208,7 @@ where
#[op]
fn op_ffi_read_i16<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<i16, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2081,7 +2225,7 @@ where
#[op]
fn op_ffi_read_u32<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<u32, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2098,7 +2242,7 @@ where
#[op]
fn op_ffi_read_i32<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<i32, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2116,7 +2260,7 @@ where
fn op_ffi_read_u64<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>,
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<serde_v8::Value<'scope>, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2130,15 +2274,47 @@ where
// SAFETY: ptr is user provided.
let result = unsafe { ptr::read_unaligned(ptr as *const u64) };
- let big_int: v8::Local<v8::Value> =
- v8::BigInt::new_from_u64(scope, result).into();
- Ok(big_int.into())
+ let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 {
+ v8::BigInt::new_from_u64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ };
+
+ Ok(integer.into())
+}
+
+#[op(v8)]
+fn op_ffi_read_i64<FP, 'scope>(
+ scope: &mut v8::HandleScope<'scope>,
+ state: &mut deno_core::OpState,
+ ptr: usize,
+) -> Result<serde_v8::Value<'scope>, AnyError>
+where
+ FP: FfiPermissions + 'static,
+ 'scope: 'scope,
+{
+ check_unstable(state, "Deno.UnsafePointerView#getBigUint64");
+
+ let permissions = state.borrow_mut::<FP>();
+ permissions.check(None)?;
+
+ // SAFETY: ptr is user provided.
+ let result = unsafe { ptr::read_unaligned(ptr as *const i64) };
+
+ let integer: v8::Local<v8::Value> =
+ if result > MAX_SAFE_INTEGER as i64 || result < MIN_SAFE_INTEGER as i64 {
+ v8::BigInt::new_from_i64(scope, result).into()
+ } else {
+ v8::Number::new(scope, result as f64).into()
+ };
+
+ Ok(integer.into())
}
#[op]
fn op_ffi_read_f32<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<f32, AnyError>
where
FP: FfiPermissions + 'static,
@@ -2155,7 +2331,7 @@ where
#[op]
fn op_ffi_read_f64<FP>(
state: &mut deno_core::OpState,
- ptr: u64,
+ ptr: usize,
) -> Result<f64, AnyError>
where
FP: FfiPermissions + 'static,