blob: 38f518be73d67a40b5b4c79335fbd7361d6d585c [file] [log] [blame] [edit]
//! A low-level wrapping of libffi, this layer makes no attempts at safety,
//! but tries to provide a somewhat more idiomatic interface.
//!
//! This module also re-exports types and constants necessary for using the
//! library, so it should not be generally necessary to use the `raw` module.
//! While this is a bit “Rustier” than [`raw`](crate::raw), I’ve
//! avoided drastic renaming in favor of hewing close to the libffi API.
//! See [`middle`](crate::middle) for an easier-to-use approach.
use std::mem;
use std::os::raw::{c_uint, c_void};
use crate::raw;
/// The two kinds of errors reported by libffi.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Error {
/// Given a bad or unsupported type representation.
Typedef,
/// Given a bad or unsupported ABI.
Abi,
}
/// The [`std::result::Result`] type specialized for libffi [`Error`]s.
pub type Result<T> = ::std::result::Result<T, Error>;
// Converts the raw status type to a `Result`.
fn status_to_result<R>(status: raw::ffi_status, good: R) -> Result<R> {
if status == raw::ffi_status_FFI_OK {
Ok(good)
} else if status == raw::ffi_status_FFI_BAD_TYPEDEF {
Err(Error::Typedef)
}
// If we don't recognize the status, that is an ABI error:
else {
Err(Error::Abi)
}
}
/// Wraps a function pointer of unknown type.
///
/// This is used to make the API a bit easier to understand, and as a
/// simple type lint. As a `repr(C)` struct of one element, it should
/// be safe to transmute between `CodePtr` and `*mut c_void`, or between
/// collections thereof.
#[derive(Clone, Copy, Debug, Hash)]
#[repr(C)]
pub struct CodePtr(pub *mut c_void);
// How useful is this type? Does it need all the methods?
impl CodePtr {
/// Initializes a code pointer from a function pointer.
///
/// This is useful mainly for talking to C APIs that take untyped
/// callbacks specified in the API as having type `void(*)()`.
pub fn from_fun(fun: unsafe extern "C" fn()) -> Self {
CodePtr(fun as *mut c_void)
}
/// Initializes a code pointer from a void pointer.
///
/// This is the other common type used in APIs (or at least in
/// libffi) for untyped callback arguments.
pub fn from_ptr(fun: *const c_void) -> Self {
CodePtr(fun as *mut c_void)
}
/// Gets the code pointer typed as a C function pointer.
///
/// This is useful mainly for talking to C APIs that take untyped
/// callbacks specified in the API as having type `void(*)()`.
///
/// # Safety
///
/// There is no checking that the returned type reflects the actual
/// parameter and return types of the function. Unless the C
/// function actually has type `void(*)()`, it will need to be
/// cast before it is called.
pub fn as_fun(&self) -> &unsafe extern "C" fn() {
unsafe { self.as_any_ref_() }
}
/// Gets the code pointer typed as a “safe” C function pointer.
///
/// This is useful mainly for talking to C APIs that take untyped
/// callbacks specified in the API as having type `void(*)()`.
///
/// # Safety
///
/// There isn’t necessarily anything actually safe about the resulting
/// function pointer—it’s up to the caller to know what they’re
/// doing within the unsafety boundary, or undefined behavior may
/// result. In particular,
/// there is no checking that the returned type reflects the actual
/// parameter and return types of the function. Unless the C
/// function actually has type `void(*)()`, it will need to be
/// cast before it is called.
pub unsafe fn as_safe_fun(&self) -> &extern "C" fn() {
self.as_any_ref_()
}
pub(crate) unsafe fn as_any_ref_<T>(&self) -> &T {
&*(&self.0 as *const _ as *const T)
}
/// Gets the code pointer typed as a `const void*`.
///
/// This is the other common type used in APIs (or at least in
/// libffi) for untyped callback arguments.
pub fn as_ptr(self) -> *const c_void {
self.0
}
/// Gets the code pointer typed as a `void*`.
///
/// This is the other common type used in APIs (or at least in
/// libffi) for untyped callback arguments.
pub fn as_mut_ptr(self) -> *mut c_void {
self.0
}
}
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.
///
/// These are from [the raw layer](crate::raw), but are renamed by
/// removing the `ffi_type_` prefix. For example, [`raw::ffi_type_void`]
/// becomes [`types::void`].
pub mod types {
pub use crate::raw::{
ffi_type_double as double, ffi_type_float as float, ffi_type_pointer as pointer,
ffi_type_sint16 as sint16, ffi_type_sint32 as sint32, ffi_type_sint64 as sint64,
ffi_type_sint8 as sint8, ffi_type_uint16 as uint16, ffi_type_uint32 as uint32,
ffi_type_uint64 as uint64, ffi_type_uint8 as uint8, ffi_type_void as void,
};
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
pub use crate::raw::ffi_type_longdouble as longdouble;
#[cfg(feature = "complex")]
pub use crate::raw::{
ffi_type_complex_double as complex_double, ffi_type_complex_float as complex_float,
};
#[cfg(feature = "complex")]
#[cfg(not(all(target_arch = "arm")))]
pub use crate::raw::ffi_type_complex_longdouble as complex_longdouble;
}
/// Type tags used in constructing and inspecting [`ffi_type`]s.
///
/// For atomic types this tag doesn’t matter because libffi predeclares
/// [an instance of each one](mod@types). However, for composite
/// types (structs and complex numbers), we need to create a new
/// instance of the [`ffi_type`] struct. In particular, the `type_` field
/// contains a value that indicates what kind of type is represented,
/// and we use these values to indicate that that we are describing a
/// struct or complex type.
///
/// # Examples
///
/// Suppose we have the following C struct:
///
/// ```c
/// struct my_struct {
/// uint16_t f1;
/// uint64_t f2;
/// };
/// ```
///
/// To pass it by value to a C function we can construct an
/// `ffi_type` as follows using `type_tag::STRUCT`:
///
/// ```
/// use std::ptr;
/// use libffi::low::{ffi_type, types, type_tag};
///
/// let mut elements = unsafe {
/// [ &mut types::uint16,
/// &mut types::uint64,
/// ptr::null_mut::<ffi_type>() ]
/// };
///
/// let mut my_struct: ffi_type = Default::default();
/// my_struct.type_ = type_tag::STRUCT;
/// my_struct.elements = elements.as_mut_ptr();
/// ```
pub mod type_tag {
use crate::raw;
use std::os::raw::c_ushort;
/// Indicates a structure type.
pub const STRUCT: c_ushort = raw::ffi_type_enum_STRUCT as c_ushort;
/// Indicates a complex number type.
///
/// This item is enabled by `#[cfg(feature = "complex")]`.
#[cfg(feature = "complex")]
pub const COMPLEX: c_ushort = raw::ffi_type_enum_COMPLEX as c_ushort;
}
/// Initalizes a CIF (Call Interface) with the given ABI
/// and types.
///
/// We need to initialize a CIF before we can use it to call a function
/// or create a closure. This function lets us specify the calling
/// convention to use and the argument and result types. For varargs
/// CIF initialization, see [`prep_cif_var`].
///
///
/// # Safety
///
/// The CIF `cif` retains references to `rtype` and `atypes`, so if
/// they are no longer live when the CIF is used then the behavior is
/// undefined.
///
/// # Arguments
///
/// - `cif` — the CIF to initialize
/// - `abi` — the calling convention to use
/// - `nargs` — the number of arguments
/// - `rtype` — the result type
/// - `atypes` — the argument types (length must be at least `nargs`)
///
/// # Result
///
/// `Ok(())` for success or `Err(e)` for failure.
///
/// # Examples
///
/// ```
/// use libffi::low::*;
///
/// let mut args: [*mut ffi_type; 2] = unsafe {
/// [ &mut types::sint32,
/// &mut types::uint64 ]
/// };
/// let mut cif: ffi_cif = Default::default();
///
/// unsafe {
/// prep_cif(&mut cif, ffi_abi_FFI_DEFAULT_ABI, 2,
/// &mut types::pointer, args.as_mut_ptr())
/// }.unwrap();
/// ```
pub unsafe fn prep_cif(
cif: *mut ffi_cif,
abi: ffi_abi,
nargs: usize,
rtype: *mut ffi_type,
atypes: *mut *mut ffi_type,
) -> Result<()> {
let status = raw::ffi_prep_cif(cif, abi, nargs as c_uint, rtype, atypes);
status_to_result(status, ())
}
/// Initalizes a CIF (Call Interface) for a varargs function.
///
/// We need to initialize a CIF before we can use it to call a function
/// or create a closure. This function lets us specify the calling
/// convention to use and the argument and result types. For non-varargs
/// CIF initialization, see [`prep_cif`].
///
/// # Safety
///
/// The CIF `cif` retains references to `rtype` and `atypes`, so if
/// they are no longer live when the CIF is used then the behavior is
/// undefined.
///
/// # Arguments
///
/// - `cif` — the CIF to initialize
/// - `abi` — the calling convention to use
/// - `nfixedargs` — the number of fixed arguments
/// - `ntotalargs` — the total number of arguments, including fixed and
/// var args
/// - `rtype` — the result type
/// - `atypes` — the argument types (length must be at least `nargs`)
///
/// # Result
///
/// `Ok(())` for success or `Err(e)` for failure.
///
pub unsafe fn prep_cif_var(
cif: *mut ffi_cif,
abi: ffi_abi,
nfixedargs: usize,
ntotalargs: usize,
rtype: *mut ffi_type,
atypes: *mut *mut ffi_type,
) -> Result<()> {
let status = raw::ffi_prep_cif_var(
cif,
abi,
nfixedargs as c_uint,
ntotalargs as c_uint,
rtype,
atypes,
);
status_to_result(status, ())
}
/// Calls a C function as specified by a CIF.
///
/// # Arguments
///
/// * `cif` — describes the argument and result types and the calling
/// convention
/// * `fun` — the function to call
/// * `args` — the arguments to pass to `fun`
///
/// # Result
///
/// The result of calling `fun` with `args`.
///
/// # Examples
///
/// ```
/// use std::os::raw::c_void;
/// use libffi::low::*;
///
/// extern "C" fn c_function(a: u64, b: u64) -> u64 { a + b }
///
/// let result = unsafe {
/// let mut args: Vec<*mut ffi_type> = vec![ &mut types::uint64,
/// &mut types::uint64 ];
/// let mut cif: ffi_cif = Default::default();
///
/// prep_cif(&mut cif, ffi_abi_FFI_DEFAULT_ABI, 2,
/// &mut types::uint64, args.as_mut_ptr()).unwrap();
///
/// call::<u64>(&mut cif, CodePtr(c_function as *mut _),
/// vec![ &mut 4u64 as *mut _ as *mut c_void,
/// &mut 5u64 as *mut _ as *mut c_void ].as_mut_ptr())
/// };
///
/// assert_eq!(9, result);
/// ```
pub unsafe fn call<R>(cif: *mut ffi_cif, fun: CodePtr, args: *mut *mut c_void) -> R {
let mut result = mem::MaybeUninit::<R>::uninit();
raw::ffi_call(
cif,
Some(*fun.as_safe_fun()),
result.as_mut_ptr() as *mut c_void,
args,
);
result.assume_init()
}
/// Allocates a closure.
///
/// Returns a pair of the writable closure object and the function
/// pointer for calling it. The former acts as a handle to the closure,
/// and is used to configure and free it. The latter is the code pointer
/// used to invoke the closure. Before it can be invoked, it must be
/// initialized with [`prep_closure`] and [`prep_closure_mut`]. The
/// closure must be deallocated using [`closure_free`], after which
/// point the code pointer should not be used.
///
/// # Examples
///
/// ```
/// use libffi::low::*;
///
/// let (closure_handle, code_ptr) = closure_alloc();
/// ```
pub fn closure_alloc() -> (*mut ffi_closure, CodePtr) {
unsafe {
let mut code_pointer = mem::MaybeUninit::<*mut c_void>::uninit();
let closure =
raw::ffi_closure_alloc(mem::size_of::<ffi_closure>(), code_pointer.as_mut_ptr());
(
closure as *mut ffi_closure,
CodePtr::from_ptr(code_pointer.assume_init()),
)
}
}
/// Frees a closure.
///
/// Closures allocated with [`closure_alloc`] must be deallocated with
/// [`closure_free`].
///
/// # Examples
///
/// ```
/// use libffi::low::*;
///
/// let (closure_handle, code_ptr) = closure_alloc();
///
/// // ...
///
/// unsafe {
/// closure_free(closure_handle);
/// }
/// ```
pub unsafe fn closure_free(closure: *mut ffi_closure) {
raw::ffi_closure_free(closure as *mut c_void);
}
/// The type of function called by a closure.
///
/// `U` is the type of the user data captured by the closure and passed
/// to the callback, and `R` is the type of the result. The parameters
/// are not typed, since they are passed as a C array of `void*`.
pub type Callback<U, R> =
unsafe extern "C" fn(cif: &ffi_cif, result: &mut R, args: *const *const c_void, userdata: &U);
/// The type of function called by a mutable closure.
///
/// `U` is the type of the user data captured by the closure and passed
/// to the callback, and `R` is the type of the result. The parameters
/// are not typed, since they are passed as a C array of `void*`.
pub type CallbackMut<U, R> = unsafe extern "C" fn(
cif: &ffi_cif,
result: &mut R,
args: *const *const c_void,
userdata: &mut U,
);
/// The callback type expected by [`raw::ffi_prep_closure_loc`].
pub type RawCallback = unsafe extern "C" fn(
cif: *mut ffi_cif,
result: *mut c_void,
args: *mut *mut c_void,
userdata: *mut c_void,
);
/// Initializes a closure with a callback function and userdata.
///
/// After allocating a closure with [`closure_alloc`], it needs to be
/// initialized with a function `callback` to call and a pointer
/// `userdata` to pass to it. Invoking the closure’s code pointer will
/// then pass the provided arguments and the user data pointer to the
/// callback.
///
/// For mutable userdata use [`prep_closure_mut`].
///
/// # Safety
///
/// The closure retains a reference to CIF `cif`, so that must
/// still be live when the closure is used lest undefined behavior
/// result.
///
/// # Arguments
///
/// - `closure` — the closure to initialize
/// - `cif` — the calling convention and types for calling the closure
/// - `callback` — the function that the closure will invoke
/// - `userdata` — the closed-over value, stored in the closure and
/// passed to the callback upon invocation
/// - `code` — the closure’s code pointer, *i.e.*, the second component
/// returned by [`closure_alloc`].
///
/// # Result
///
/// `Ok(())` for success or `Err(e)` for failure.
///
/// # Examples
///
/// ```
/// use libffi::low::*;
///
/// use std::mem;
/// use std::os::raw::c_void;
///
/// unsafe extern "C" fn callback(_cif: &ffi_cif,
/// result: &mut u64,
/// args: *const *const c_void,
/// userdata: &u64)
/// {
/// let args: *const &u64 = mem::transmute(args);
/// *result = **args + *userdata;
/// }
///
/// fn twice(f: extern "C" fn(u64) -> u64, x: u64) -> u64 {
/// f(f(x))
/// }
///
/// unsafe {
/// let mut cif: ffi_cif = Default::default();
/// let mut args = [&mut types::uint64 as *mut _];
/// let mut userdata: u64 = 5;
///
/// prep_cif(&mut cif, ffi_abi_FFI_DEFAULT_ABI, 1, &mut types::uint64,
/// args.as_mut_ptr()).unwrap();
///
/// let (closure, code) = closure_alloc();
/// let add5: extern "C" fn(u64) -> u64 = mem::transmute(code);
///
/// prep_closure(closure,
/// &mut cif,
/// callback,
/// &mut userdata,
/// CodePtr(add5 as *mut _)).unwrap();
///
/// assert_eq!(11, add5(6));
/// assert_eq!(12, add5(7));
///
/// assert_eq!(22, twice(add5, 12));
/// }
/// ```
pub unsafe fn prep_closure<U, R>(
closure: *mut ffi_closure,
cif: *mut ffi_cif,
callback: Callback<U, R>,
userdata: *const U,
code: CodePtr,
) -> Result<()> {
let status = raw::ffi_prep_closure_loc(
closure,
cif,
Some(mem::transmute::<Callback<U, R>, RawCallback>(callback)),
userdata as *mut c_void,
code.as_mut_ptr(),
);
status_to_result(status, ())
}
/// Initializes a mutable closure with a callback function and (mutable)
/// userdata.
///
/// After allocating a closure with [`closure_alloc`], it needs to be
/// initialized with a function `callback` to call and a pointer
/// `userdata` to pass to it. Invoking the closure’s code pointer will
/// then pass the provided arguments and the user data pointer to the
/// callback.
///
/// For immutable userdata use [`prep_closure`].
///
/// # Safety
///
/// The closure retains a reference to CIF `cif`, so that must
/// still be live when the closure is used lest undefined behavior
/// result.
///
/// # Arguments
///
/// - `closure` — the closure to initialize
/// - `cif` — the calling convention and types for calling the closure
/// - `callback` — the function that the closure will invoke
/// - `userdata` — the closed-over value, stored in the closure and
/// passed to the callback upon invocation
/// - `code` — the closure’s code pointer, *i.e.*, the second component
/// returned by [`closure_alloc`].
///
/// # Result
///
/// `Ok(())` for success or `Err(e)` for failure.
///
/// # Examples
///
/// ```
/// use libffi::low::*;
///
/// use std::mem;
/// use std::os::raw::c_void;
///
/// unsafe extern "C" fn callback(_cif: &ffi_cif,
/// result: &mut u64,
/// args: *const *const c_void,
/// userdata: &mut u64)
/// {
/// let args: *const &u64 = mem::transmute(args);
/// *result = *userdata;
/// *userdata += **args;
/// }
///
/// fn twice(f: extern "C" fn(u64) -> u64, x: u64) -> u64 {
/// f(f(x))
/// }
///
/// unsafe {
/// let mut cif: ffi_cif = Default::default();
/// let mut args = [&mut types::uint64 as *mut _];
/// let mut userdata: u64 = 5;
///
/// prep_cif(&mut cif, ffi_abi_FFI_DEFAULT_ABI, 1, &mut types::uint64,
/// args.as_mut_ptr()).unwrap();
///
/// let (closure, code) = closure_alloc();
/// let add5: extern "C" fn(u64) -> u64 = mem::transmute(code);
///
/// prep_closure_mut(closure,
/// &mut cif,
/// callback,
/// &mut userdata,
/// CodePtr(add5 as *mut _)).unwrap();
///
/// assert_eq!(5, add5(6));
/// assert_eq!(11, add5(7));
///
/// assert_eq!(19, twice(add5, 1));
/// }
/// ```
pub unsafe fn prep_closure_mut<U, R>(
closure: *mut ffi_closure,
cif: *mut ffi_cif,
callback: CallbackMut<U, R>,
userdata: *mut U,
code: CodePtr,
) -> Result<()> {
let status = raw::ffi_prep_closure_loc(
closure,
cif,
Some(mem::transmute::<CallbackMut<U, R>, RawCallback>(callback)),
userdata as *mut c_void,
code.as_mut_ptr(),
);
status_to_result(status, ())
}