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