miri/shims/native_lib/
ffi.rs

1//! Support code for dealing with libffi.
2
3use libffi::low::CodePtr;
4use libffi::middle::{Arg as ArgPtr, Cif, Type as FfiType};
5
6/// Perform the actual FFI call.
7///
8/// # Safety
9///
10/// The safety invariants of the foreign function being called must be upheld (if any).
11pub unsafe fn call<R: libffi::high::CType>(fun: CodePtr, args: &mut [OwnedArg]) -> R {
12    let arg_ptrs: Vec<_> = args.iter().map(|arg| arg.ptr()).collect();
13    let cif = Cif::new(args.iter_mut().map(|arg| arg.ty.take().unwrap()), R::reify().into_middle());
14    // SAFETY: Caller upholds that the function is safe to call, and since we
15    // were passed a slice reference we know the `OwnedArg`s won't have been
16    // dropped by this point.
17    unsafe { cif.call(fun, &arg_ptrs) }
18}
19
20/// An argument for an FFI call.
21#[derive(Debug, Clone)]
22pub struct OwnedArg {
23    /// The type descriptor for this argument.
24    ty: Option<FfiType>,
25    /// Corresponding bytes for the value.
26    bytes: Box<[u8]>,
27}
28
29impl OwnedArg {
30    /// Instantiates an argument from a type descriptor and bytes.
31    pub fn new(ty: FfiType, bytes: Box<[u8]>) -> Self {
32        Self { ty: Some(ty), bytes }
33    }
34
35    /// Creates a libffi argument pointer pointing to this argument's bytes.
36    /// NB: Since `libffi::middle::Arg` ignores the lifetime of the reference
37    /// it's derived from, it is up to the caller to ensure the `OwnedArg` is
38    /// not dropped before unsafely calling `libffi::middle::Cif::call()`!
39    fn ptr(&self) -> ArgPtr {
40        // FIXME: Using `&self.bytes[0]` to reference the whole array is
41        // definitely unsound under SB, but we're waiting on
42        // https://github.com/libffi-rs/libffi-rs/commit/112a37b3b6ffb35bd75241fbcc580de40ba74a73
43        // to land in a release so that we don't need to do this.
44        ArgPtr::new(&self.bytes[0])
45    }
46}