diff --git a/libffi-rs/src/high/call.rs b/libffi-rs/src/high/call.rs index e0685802..7f9d18cb 100644 --- a/libffi-rs/src/high/call.rs +++ b/libffi-rs/src/high/call.rs @@ -17,6 +17,7 @@ //! assert!((result - 5f32).abs() < 0.0001); //! ``` +use std::convert::TryInto; use std::marker::PhantomData; use crate::middle; @@ -78,7 +79,13 @@ pub unsafe fn call(fun: CodePtr, args: &[Arg]) -> R { let cif = middle::Cif::new(types, R::reify().into_middle()); let values = args.iter().map(|arg| arg.value.clone()).collect::>(); - cif.call(fun, &values) + // If `R` is a small integer type, libffi implicitly extends it to + // `ffi_arg` or `ffi_sarg`. To account for this, use `R::RetType` + // as return type for the low-level call, and convert the result back. + cif.call::(fun, &values) + .try_into() + .ok() + .unwrap() } /// Performs a dynamic call to a C function. diff --git a/libffi-rs/src/high/mod.rs b/libffi-rs/src/high/mod.rs index 3209b31b..fb156a3e 100644 --- a/libffi-rs/src/high/mod.rs +++ b/libffi-rs/src/high/mod.rs @@ -199,7 +199,7 @@ macro_rules! define_closure_mod { } } - impl<'a, $( $T, )* R> $closure<'a, $( $T, )* R> { + impl<'a, $( $T, )* R: CType> $closure<'a, $( $T, )* R> { /// Gets the C code pointer that is used to invoke the /// closure. pub fn code_ptr(&self) -> & $fnptr <'a, $( $T, )* R> { @@ -221,12 +221,14 @@ macro_rules! define_closure_mod { /// Constructs a typed closure callable from C from a CIF /// describing the calling convention for the resulting /// function, a callback for the function to call, and - /// userdata to pass to the callback. + /// userdata to pass to the callback. Note that the return + /// type of the callback must follow the libffi implicit + /// extension rules. pub fn from_parts(cif: $cif<$( $T, )* R>, - callback: $callback, + callback: $callback, userdata: &'a U) -> Self { - let callback: middle::Callback + let callback: middle::Callback = unsafe { mem::transmute(callback) }; let closure = middle::Closure::new(cif.untyped, @@ -239,7 +241,7 @@ macro_rules! define_closure_mod { } } - impl<'a, $( $T: Copy, )* R> $closure<'a, $( $T, )* R> { + impl<'a, $( $T: Copy, )* R: CType> $closure<'a, $( $T, )* R> { /// Constructs a typed closure callable from C from a CIF /// describing the calling convention for the resulting /// function and the Rust closure to call. @@ -255,7 +257,7 @@ macro_rules! define_closure_mod { #[allow(non_snake_case)] extern "C" fn static_callback (_cif: &low::ffi_cif, - result: &mut R, + result: &mut R::RetType, &($( &$T, )*): &($( &$T, )*), userdata: &Callback) @@ -263,7 +265,7 @@ macro_rules! define_closure_mod { { abort_on_panic!("Cannot panic inside FFI callback", { unsafe { - ptr::write(result, userdata($( $T, )*)); + ptr::write(result, userdata($( $T, )*).into()); } }); } @@ -295,7 +297,7 @@ macro_rules! define_closure_mod { } } - impl<'a, $( $T, )* R> $closure_mut<'a, $( $T, )* R> { + impl<'a, $( $T, )* R: CType> $closure_mut<'a, $( $T, )* R> { /// Gets the C code pointer that is used to invoke the /// closure. pub fn code_ptr(&self) -> & $fnptr <'a, $( $T, )* R> { @@ -307,12 +309,14 @@ macro_rules! define_closure_mod { /// Constructs a typed closure callable from C from a CIF /// describing the calling convention for the resulting /// function, a callback for the function to call, and - /// userdata to pass to the callback. + /// userdata to pass to the callback. Note that the return + /// type of the callback must follow the libffi implicit + /// extension rules. pub fn from_parts(cif: $cif<$( $T, )* R>, - callback: $callback_mut, + callback: $callback_mut, userdata: &'a mut U) -> Self { - let callback: middle::CallbackMut + let callback: middle::CallbackMut = unsafe { mem::transmute(callback) }; let closure = middle::Closure::new_mut(cif.untyped, @@ -325,7 +329,7 @@ macro_rules! define_closure_mod { } } - impl<'a, $( $T: Copy, )* R> $closure_mut<'a, $( $T, )* R> { + impl<'a, $( $T: Copy, )* R: CType> $closure_mut<'a, $( $T, )* R> { /// Constructs a typed closure callable from C from a CIF /// describing the calling convention for the resulting /// function and the Rust closure to call. @@ -342,7 +346,7 @@ macro_rules! define_closure_mod { #[allow(non_snake_case)] extern "C" fn static_callback (_cif: &low::ffi_cif, - result: &mut R, + result: &mut R::RetType, &($( &$T, )*): &($( &$T, )*), userdata: &mut Callback) @@ -350,7 +354,7 @@ macro_rules! define_closure_mod { { abort_on_panic!("Cannot panic inside FFI callback", { unsafe { - ptr::write(result, userdata($( $T, )*)); + ptr::write(result, userdata($( $T, )*).into()); } }); } @@ -377,7 +381,7 @@ macro_rules! define_closure_mod { } } - impl<$( $T: Copy, )* R> $closure_once<$( $T, )* R> { + impl<$( $T: Copy, )* R: CType> $closure_once<$( $T, )* R> { /// Constructs a one-shot closure callable from C from a CIF /// describing the calling convention for the resulting /// function and the Rust closure to call. @@ -393,7 +397,7 @@ macro_rules! define_closure_mod { #[allow(non_snake_case)] extern "C" fn static_callback (_cif: &low::ffi_cif, - result: &mut R, + result: &mut R::RetType, &($( &$T, )*): &($( &$T, )*), userdata: &mut Option) @@ -402,7 +406,7 @@ macro_rules! define_closure_mod { if let Some(userdata) = userdata.take() { abort_on_panic!("Cannot panic inside FFI callback", { unsafe { - ptr::write(result, userdata($( $T, )*)); + ptr::write(result, userdata($( $T, )*).into()); } }); } else { @@ -414,7 +418,7 @@ macro_rules! define_closure_mod { } } - impl<$( $T, )* R> $closure_once<$( $T, )* R> { + impl<$( $T, )* R: CType> $closure_once<$( $T, )* R> { /// Gets the C code pointer that is used to invoke the /// closure. pub fn code_ptr(&self) -> & $fnptr <'_, $( $T, )* R> { @@ -426,14 +430,16 @@ macro_rules! define_closure_mod { /// Constructs a one-shot closure callable from C from a CIF /// describing the calling convention for the resulting /// function, a callback for the function to call, and - /// userdata to pass to the callback. + /// userdata to pass to the callback. Note that the return + /// type of the callback must follow the libffi implicit + /// extension rules. pub fn from_parts( cif: $cif<$( $T, )* R>, - callback: $callback_once, + callback: $callback_once, userdata: U) -> Self { - let callback: middle::CallbackOnce + let callback: middle::CallbackOnce = unsafe { mem::transmute(callback) }; let closure = middle::ClosureOnce::new(cif.untyped, diff --git a/libffi-rs/src/high/types.rs b/libffi-rs/src/high/types.rs index f698b033..9babb43e 100644 --- a/libffi-rs/src/high/types.rs +++ b/libffi-rs/src/high/types.rs @@ -2,6 +2,7 @@ use std::marker::PhantomData; +use super::super::low; use super::super::middle; /// Represents a C type statically associated with a Rust type. @@ -43,34 +44,44 @@ pub unsafe trait CType: Copy { /// We can use the resulting object to assemble a CIF to set up /// a call that uses type `T`. fn reify() -> Type; + /// The low-level libffi library implicitly extends small integer + /// return values to `ffi_arg` or `ffi_sarg`. Track the possibly + /// extended variant of `T` as an associated type here. + type RetType: std::convert::From + std::convert::TryInto; } macro_rules! impl_ffi_type { - ($type_:ty, $cons:ident) => { + ($type_:ty, $ret_:ty, $cons:ident) => { unsafe impl CType for $type_ { fn reify() -> Type { Type::make(middle::Type::$cons()) } + type RetType = $ret_; } }; + ($type_:ident, $ret_:ty) => { + impl_ffi_type!($type_, $ret_, $type_); + }; ($type_:ident) => { - impl_ffi_type!($type_, $type_); + impl_ffi_type!($type_, $type_, $type_); }; } -impl_ffi_type!(u8); -impl_ffi_type!(i8); -impl_ffi_type!(u16); -impl_ffi_type!(i16); -impl_ffi_type!(u32); -impl_ffi_type!(i32); +// We assume that `ffi_arg` and `ffi_sarg` are either 32-bit or 64-bit +// integer types on all supported platforms here. +impl_ffi_type!(u8, low::ffi_arg); +impl_ffi_type!(i8, low::ffi_sarg); +impl_ffi_type!(u16, low::ffi_arg); +impl_ffi_type!(i16, low::ffi_sarg); +impl_ffi_type!(u32, low::ffi_arg); +impl_ffi_type!(i32, low::ffi_sarg); impl_ffi_type!(u64); impl_ffi_type!(i64); impl_ffi_type!(f32); impl_ffi_type!(f64); impl_ffi_type!(usize); impl_ffi_type!(isize); -impl_ffi_type!((), void); +impl_ffi_type!((), (), void); // Why is the complex stuff even here? It doesn’t work yet because // libffi doesn’t support it, so it should probably go away and come @@ -118,10 +129,12 @@ unsafe impl CType for *const T { fn reify() -> Type { Type::make(middle::Type::pointer()) } + type RetType = *const T; } unsafe impl CType for *mut T { fn reify() -> Type { Type::make(middle::Type::pointer()) } + type RetType = *mut T; } diff --git a/libffi-rs/src/low.rs b/libffi-rs/src/low.rs index 65158ee4..18427727 100644 --- a/libffi-rs/src/low.rs +++ b/libffi-rs/src/low.rs @@ -120,7 +120,9 @@ impl CodePtr { } } -pub use raw::{ffi_abi, ffi_abi_FFI_DEFAULT_ABI, ffi_cif, ffi_closure, ffi_status, ffi_type}; +pub use raw::{ + ffi_abi, ffi_abi_FFI_DEFAULT_ABI, ffi_arg, ffi_cif, ffi_closure, ffi_sarg, ffi_status, ffi_type, +}; /// Re-exports the [`ffi_type`] objects used to describe the types of /// arguments and results.