diff --git a/Cargo.lock b/Cargo.lock index d00508e5e..ed7a312a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1625,9 +1625,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libffi" -version = "4.1.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838" +checksum = "0498fe5655f857803e156523e644dcdcdc3b3c7edda42ea2afdae2e09b2db87b" dependencies = [ "libc", "libffi-sys", @@ -1635,9 +1635,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "3.3.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3" +checksum = "71d4f1d4ce15091955144350b75db16a96d4a63728500122706fb4d29a26afbb" dependencies = [ "cc", ] diff --git a/Cargo.toml b/Cargo.toml index 39801345b..d0bb1ef45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,7 +94,7 @@ parking_lot = "0.12.4" crossterm = { version = "0.28.1", optional = true } ctrlc = { version = "3.4.4", optional = true } hostname = { version = "0.4.0", optional = true } -libffi = { version = "4.0.0", optional = true } +libffi = { version = "5.1.0", optional = true } native-tls = { version = "0.2.12", optional = true } # the version requirement of reqwest is kept low for compatibility with old deno versions # that pin reqwest to 0.11.20 diff --git a/src/ffi.rs b/src/ffi.rs index c1762fb62..e7957dece 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -26,7 +26,7 @@ use crate::machine::machine_errors::DomainErrorType; use crate::parser::ast::{Fixnum, MightNotFitInFixnum}; use dashu::Integer; -use libffi::middle::{Arg, Cif, CodePtr, Type}; +use libffi::middle::{Arg, Cif, CodePtr, Ret, Type}; use libloading::{Library, Symbol}; use ordered_float::OrderedFloat; use std::alloc::{self, Layout}; @@ -36,7 +36,6 @@ use std::ffi::{c_char, c_void, CStr, CString}; use std::fmt::Debug; use std::marker::PhantomData; use std::mem::ManuallyDrop; -use std::ops::Deref; use std::ptr::NonNull; pub struct FunctionDefinition { @@ -55,7 +54,7 @@ pub struct FunctionImpl { impl FunctionImpl { unsafe fn call_void(&self, args: &[Arg], _: &mut Arena) -> Result { - self.cif.call::<()>(self.code_ptr, args); + self.cif.call_return_into(self.code_ptr, args, Ret::void()); Ok(Value::Number(Number::Fixnum(Fixnum::build_with(0)))) } @@ -114,12 +113,8 @@ impl FunctionImpl { let alloc = FfiStruct::new(layout, FfiAllocator::Rust)?; unsafe { - libffi::raw::ffi_call( - self.cif.as_raw_ptr(), - Some(*self.code_ptr.as_safe_fun()), - alloc.ptr.as_ptr(), - args.as_ptr() as *mut *mut c_void, - ) + self.cif + .call_return_into(self.code_ptr, args, alloc.as_ret()) }; let struct_val = @@ -336,7 +331,9 @@ impl StructImpl { substruct_type.read(field_ptr, *substruct, struct_table, arena)?; Ok(struct_val) } - FfiType::Void => return Err(FfiError::VoidArgumentType), + FfiType::Void => { + return Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))) + } }; returns.push(val?); } @@ -345,48 +342,6 @@ impl StructImpl { } } -struct PointerArgs<'a, 'val> { - memory: Vec, - phantom: PhantomData<&'a mut ArgValue<'val>>, -} - -impl<'args, 'val> PointerArgs<'args, 'val> { - fn new(args: &'args [ArgValue<'val>]) -> Self { - let args = args - .iter() - .map(|arg| match arg { - ArgValue::U8(a) => libffi::middle::arg(a), - ArgValue::I8(a) => libffi::middle::arg(a), - ArgValue::U16(a) => libffi::middle::arg(a), - ArgValue::I16(a) => libffi::middle::arg(a), - ArgValue::U32(a) => libffi::middle::arg(a), - ArgValue::I32(a) => libffi::middle::arg(a), - ArgValue::U64(a) => libffi::middle::arg(a), - ArgValue::I64(a) => libffi::middle::arg(a), - ArgValue::F32(a) => libffi::middle::arg(a), - ArgValue::F64(a) => libffi::middle::arg(a), - ArgValue::Ptr(ptr, _) => Arg::new(ptr), - ArgValue::Struct(s) => unsafe { - std::mem::transmute::<*mut c_void, Arg>(s.ptr.as_ptr()) - }, - }) - .collect(); - - PointerArgs { - memory: args, - phantom: PhantomData, - } - } -} - -impl Deref for PointerArgs<'_, '_> { - type Target = [Arg]; - - fn deref(&self) -> &Self::Target { - &self.memory - } -} - #[derive(Debug, Clone, Copy)] enum FfiType { Void, @@ -543,7 +498,7 @@ impl<'val> ArgValue<'val> { args, )?)) } - FfiType::Void => Err(FfiError::VoidArgumentType), + FfiType::Void => Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))), } } @@ -568,6 +523,28 @@ impl<'val> ArgValue<'val> { .map(|(arg, arg_type)| ArgValue::new(arg, arg_type, structs_table)) .collect::, _>>() } + + fn as_arg<'res, 'this: 'res>(&'this self) -> Arg<'res> + where + 'val: 'res, + { + match self { + ArgValue::U8(a) => libffi::middle::arg(a), + ArgValue::I8(a) => libffi::middle::arg(a), + ArgValue::U16(a) => libffi::middle::arg(a), + ArgValue::I16(a) => libffi::middle::arg(a), + ArgValue::U32(a) => libffi::middle::arg(a), + ArgValue::I32(a) => libffi::middle::arg(a), + ArgValue::U64(a) => libffi::middle::arg(a), + ArgValue::I64(a) => libffi::middle::arg(a), + ArgValue::F32(a) => libffi::middle::arg(a), + ArgValue::F64(a) => libffi::middle::arg(a), + ArgValue::Ptr(ptr, _) => Arg::new(ptr), + ArgValue::Struct(s) => unsafe { + std::mem::transmute::<*mut c_void, Arg>(s.ptr.as_ptr()) + }, + } + } } struct FfiStruct { @@ -628,6 +605,10 @@ impl FfiStruct { allocator, }) } + + fn as_ret(&self) -> libffi::middle::Ret<'_> { + unsafe { std::mem::transmute::<*mut c_void, Ret>(self.ptr.as_ptr()) } + } } impl Drop for FfiStruct { @@ -727,7 +708,7 @@ impl ForeignFunctionTable { &self.structs, )?; - let args = PointerArgs::new(&args); + let args: Vec<_> = args.iter().map(|v| v.as_arg()).collect(); fn_impl.call(&args, arena, &self.structs) } @@ -755,7 +736,7 @@ impl ForeignFunctionTable { } match FfiType::from_atom(&kind) { - FfiType::Void => Err(FfiError::VoidArgumentType), + FfiType::Void => Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))), FfiType::Bool => { let val = args.as_int::()?; let init = match val { @@ -819,7 +800,7 @@ impl ForeignFunctionTable { }; match FfiType::from_atom(&kind) { - FfiType::Void => Err(FfiError::VoidArgumentType), + FfiType::Void => Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))), FfiType::U8 => Ok(unsafe { read_int::(ptr, arena) }), FfiType::Bool | FfiType::I8 => Ok(unsafe { read_int::(ptr, arena) }), FfiType::U16 => Ok(unsafe { read_int::(ptr, arena) }), @@ -869,7 +850,7 @@ impl ForeignFunctionTable { }; match FfiType::from_atom(&kind) { - FfiType::Void => return Err(FfiError::VoidArgumentType), + FfiType::Void => return Err(FfiError::UnsupportedArgumentType(Some(atom!("void")))), FfiType::Bool => deallocate_primitive::(allocator, ptr), FfiType::U8 => deallocate_primitive::(allocator, ptr), FfiType::I8 => deallocate_primitive::(allocator, ptr), @@ -966,10 +947,11 @@ impl Value { } #[derive(Debug)] +#[non_exhaustive] pub enum FfiError { ValueCast(Atom, Atom), ValueOutOfRange(DomainErrorType, Value), - VoidArgumentType, + UnsupportedArgumentType(Option), FunctionNotFound(Atom, usize), StructNotFound(Atom), ArgCountMismatch { @@ -987,6 +969,9 @@ pub enum FfiError { UnsupportedAbi, CStrFieldType, NullPtr, + #[doc(hidden)] + #[non_exhaustive] + Other, } #[derive(Debug)] @@ -1008,6 +993,8 @@ impl From for FfiError { match value { libffi::low::Error::Typedef => FfiError::UnsupportedTypedef, libffi::low::Error::Abi => FfiError::UnsupportedAbi, + libffi::low::Error::ArgType => FfiError::UnsupportedArgumentType(None), + _ => FfiError::Other, } } } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 2dccd1c87..52a87dfea 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -737,10 +737,13 @@ impl MachineState { FfiError::LayoutError => self.representation_error(RepFlag::FfiLayout), FfiError::UnsupportedTypedef => self.representation_error(RepFlag::FfiLayout), FfiError::UnsupportedAbi => self.representation_error(RepFlag::FfiAbi), - FfiError::VoidArgumentType => self.domain_error( + FfiError::UnsupportedArgumentType(None) => self.domain_error( DomainErrorType::FfiArgumentType, - atom_as_cell!(atom!("void")), + atom_as_cell!(atom!("unknown")), ), + FfiError::UnsupportedArgumentType(Some(kind)) => { + self.domain_error(DomainErrorType::FfiArgumentType, atom_as_cell!(kind)) + } FfiError::CStrFieldType => self.domain_error( DomainErrorType::NonCStrFfiArgumentType, atom_as_cell!(atom!("cstr")), @@ -749,6 +752,7 @@ impl MachineState { DomainErrorType::NonNullPtr, fixnum_as_cell!(Fixnum::build_with(0)), ), + FfiError::Other => self.unreachable_error(), } }