|
| 1 | +//! Support code for dealing with libffi. |
| 2 | +
|
| 3 | +use libffi::low::CodePtr; |
| 4 | +use 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). |
| 11 | +pub 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)] |
| 22 | +pub 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 | + |
| 29 | +impl 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 | +} |
0 commit comments