From ef0530ad8febd814429be68dd8791e7caa459f1d Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Wed, 3 Aug 2022 17:54:12 +0300 Subject: [PATCH 1/3] Restrict FFI types on wasm Signed-off-by: Shanin Roman --- ffi/Cargo.toml | 3 ++ ffi/derive/src/convert.rs | 63 ++++++++++++++++++++++++---- ffi/src/handle.rs | 4 +- ffi/src/lib.rs | 36 ++++++++++++++++ ffi/src/owned.rs | 84 +++++++++++++++++++++++++------------ ffi/src/primitives.rs | 70 +++++++++++++++++++++++++++---- ffi/tests/ffi_export.rs | 4 +- ffi/tests/gen_shared_fns.rs | 4 +- 8 files changed, 217 insertions(+), 51 deletions(-) diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index f55c7ed380c..09a0627f05c 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -4,6 +4,9 @@ version = "2.0.0-pre-rc.7" authors = ["Iroha 2 team "] edition = "2021" +[features] +wasm = [] + [dependencies] iroha_ffi_derive = { version = "=2.0.0-pre-rc.7", path = "derive" } diff --git a/ffi/derive/src/convert.rs b/ffi/derive/src/convert.rs index bd2cea01722..0ca6abc1c9e 100644 --- a/ffi/derive/src/convert.rs +++ b/ffi/derive/src/convert.rs @@ -86,7 +86,8 @@ fn variant_discriminants(enum_: &syn::DataEnum) -> Vec { } fn derive_try_from_repr_c_for_opaque_item_wrapper(name: &Ident) -> TokenStream2 { - let opaque_item_slice_into_ffi_derive = derive_try_from_repr_c_for_opaque_item_slice(name); + let opaque_item_slice_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_slice(name); + let opaque_item_vec_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_vec(name); quote! { impl<'itm> iroha_ffi::TryFromReprC<'itm> for #name { @@ -139,12 +140,14 @@ fn derive_try_from_repr_c_for_opaque_item_wrapper(name: &Ident) -> TokenStream2 } } - #opaque_item_slice_into_ffi_derive + #opaque_item_slice_try_from_repr_c_derive + #opaque_item_vec_try_from_repr_c_derive } } fn derive_try_from_repr_c_for_opaque_item(name: &Ident) -> TokenStream2 { - let opaque_item_slice_into_ffi_derive = derive_try_from_repr_c_for_opaque_item_slice(name); + let opaque_item_slice_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_slice(name); + let opaque_item_vec_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_vec(name); quote! { impl<'itm> iroha_ffi::TryFromReprC<'itm> for #name { @@ -187,7 +190,8 @@ fn derive_try_from_repr_c_for_opaque_item(name: &Ident) -> TokenStream2 { } } - #opaque_item_slice_into_ffi_derive + #opaque_item_slice_try_from_repr_c_derive + #opaque_item_vec_try_from_repr_c_derive } } @@ -213,6 +217,29 @@ fn derive_try_from_repr_c_for_opaque_item_slice(name: &Ident) -> TokenStream2 { } } +fn derive_try_from_repr_c_for_opaque_item_vec(name: &Ident) -> TokenStream2 { + quote! { + impl<'itm> iroha_ffi::owned::TryFromReprCVec<'itm> for #name { + type Source = iroha_ffi::slice::SliceRef<'itm, >::Source>; + type Store = (); + + unsafe fn try_from_repr_c( + source: Self::Source, + _: &'itm mut >::Store, + ) -> iroha_ffi::Result> { + let slice = source.into_rust().ok_or(iroha_ffi::FfiReturn::ArgIsNull)?; + let mut res = Vec::with_capacity(slice.len()); + + for elem in slice { + res.push(iroha_ffi::TryFromReprC::try_from_repr_c(*elem, &mut ())?); + } + + Ok(res) + } + } + } +} + fn derive_try_from_repr_c_for_item(_: &Ident) -> TokenStream2 { quote! { // TODO: @@ -248,15 +275,17 @@ fn derive_try_from_repr_c_for_fieldless_enum( quote! { impl<'itm> iroha_ffi::TryFromReprC<'itm> for #enum_name { - type Source = #ffi_type; + type Source = <#ffi_type as iroha_ffi::TryFromReprC<'itm>>::Source; type Store = (); unsafe fn try_from_repr_c( source: >::Source, - _: &mut >::Store + store: &mut >::Store ) -> iroha_ffi::Result { #( #discriminants )* + let source: #ffi_type = iroha_ffi::TryFromReprC::try_from_repr_c(source, store)?; + match source { #( #discriminant_names => Ok(#enum_name::#variant_names), )* _ => Err(iroha_ffi::FfiReturn::TrapRepresentation), @@ -323,6 +352,7 @@ fn derive_try_from_repr_c_for_fieldless_enum( fn derive_into_ffi_for_opaque_item_wrapper(name: &Ident) -> TokenStream2 { let opaque_item_slice_into_ffi_derive = derive_into_ffi_for_opaque_item_slice(name); + let opaque_item_vec_into_ffi_derive = derive_into_ffi_for_opaque_item_vec(name); quote! { impl iroha_ffi::IntoFfi for #name { @@ -350,11 +380,13 @@ fn derive_into_ffi_for_opaque_item_wrapper(name: &Ident) -> TokenStream2 { } #opaque_item_slice_into_ffi_derive + #opaque_item_vec_into_ffi_derive } } fn derive_into_ffi_for_opaque_item(name: &Ident) -> TokenStream2 { let opaque_item_slice_into_ffi_derive = derive_into_ffi_for_opaque_item_slice(name); + let opaque_item_vec_into_ffi_derive = derive_into_ffi_for_opaque_item_vec(name); quote! { impl iroha_ffi::IntoFfi for #name { @@ -388,6 +420,7 @@ fn derive_into_ffi_for_opaque_item(name: &Ident) -> TokenStream2 { } #opaque_item_slice_into_ffi_derive + #opaque_item_vec_into_ffi_derive } } @@ -403,6 +436,18 @@ fn derive_into_ffi_for_opaque_item_slice(name: &Ident) -> TokenStream2 { } } +fn derive_into_ffi_for_opaque_item_vec(name: &Ident) -> TokenStream2 { + quote! { + impl iroha_ffi::owned::IntoFfiVec for #name { + type Target = iroha_ffi::owned::LocalSlice<<#name as iroha_ffi::IntoFfi>::Target>; + + fn into_ffi(source: Vec) -> Self::Target { + source.into_iter().map(IntoFfi::into_ffi).collect() + } + } + } +} + fn derive_into_ffi_for_item(_: &Ident) -> TokenStream2 { quote! { // TODO: @@ -414,10 +459,10 @@ fn derive_into_ffi_for_fieldless_enum(enum_name: &Ident, repr: &[syn::NestedMeta quote! { impl iroha_ffi::IntoFfi for #enum_name { - type Target = #ffi_type; - + type Target = <#ffi_type as iroha_ffi::IntoFfi>::Target; + fn into_ffi(self) -> Self::Target { - self as #ffi_type + (self as #ffi_type).into_ffi() } } diff --git a/ffi/src/handle.rs b/ffi/src/handle.rs index 28ad428d1bd..ce0779561f5 100644 --- a/ffi/src/handle.rs +++ b/ffi/src/handle.rs @@ -113,7 +113,7 @@ macro_rules! def_ffi_fn { handle_id: $crate::handle::Id, left_handle_ptr: *const core::ffi::c_void, right_handle_ptr: *const core::ffi::c_void, - output_ptr: *mut u8, + output_ptr: *mut ::Target, ) -> $crate::FfiReturn { $crate::def_ffi_fn!(@catch_unwind { use core::borrow::Borrow; @@ -152,7 +152,7 @@ macro_rules! def_ffi_fn { handle_id: $crate::handle::Id, left_handle_ptr: *const core::ffi::c_void, right_handle_ptr: *const core::ffi::c_void, - output_ptr: *mut i8, + output_ptr: *mut ::Target, ) -> $crate::FfiReturn { $crate::def_ffi_fn!(@catch_unwind { use core::borrow::Borrow; diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index 091371f6efb..ba5c47dc5dc 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -7,6 +7,8 @@ extern crate alloc; +use alloc::vec::Vec; + pub use iroha_ffi_derive::*; use owned::Local; @@ -315,6 +317,40 @@ macro_rules! impl_tuple { Local::new($ffi_ty($( <$ty as IntoFfi>::into_ffi($ty),)+)) } } + + impl<$($ty: IntoFfi),+> $crate::owned::IntoFfiVec for ($( $ty, )+) { + type Target = $crate::owned::LocalSlice<::Target>; + + fn into_ffi(source: Vec) -> Self::Target { + source.into_iter().map(IntoFfi::into_ffi).collect() + } + } + + impl<'itm, $($ty: TryFromReprC<'itm>),+> $crate::owned::TryFromReprCVec<'itm> for ($( $ty, )+) { + type Source = $crate::slice::SliceRef<'itm, >::Source>; + type Store = Vec<>::Store>; + + unsafe fn try_from_repr_c( + source: Self::Source, + store: &'itm mut Self::Store, + ) -> Result> { + let prev_store_len = store.len(); + let slice = source.into_rust().ok_or(FfiReturn::ArgIsNull)?; + store.extend(core::iter::repeat_with(Default::default).take(slice.len())); + + let mut substore = &mut store[prev_store_len..]; + let mut res = Vec::with_capacity(slice.len()); + + let mut i = 0; + while let Some((first, rest)) = substore.split_first_mut() { + res.push(TryFromReprC::try_from_repr_c(slice[i], first)?); + substore = rest; + i += 1; + } + + Ok(res) + } + } }; // NOTE: This is a trick to index tuples diff --git a/ffi/src/owned.rs b/ffi/src/owned.rs index be63a77c5ef..0caa2262ee0 100644 --- a/ffi/src/owned.rs +++ b/ffi/src/owned.rs @@ -5,9 +5,45 @@ use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec}; use crate::{ slice::{OutBoxedSlice, SliceRef}, - AsReprCRef, FfiReturn, IntoFfi, Output, ReprC, TryFromReprC, + AsReprCRef, FfiReturn, IntoFfi, Output, ReprC, TryFromReprC, Result }; +/// Trait that facilitates the implementation of [`IntoFfi`] for vectors of foreign types +pub trait IntoFfiVec: Sized { + /// Immutable vec equivalent of [`IntoFfi::Target`] + type Target: ReprC; + + /// Convert from `&[Self]` into [`Self::Target`] + fn into_ffi(source: Vec) -> Self::Target; +} + +/// Trait that facilitates the implementation of [`TryFromReprC`] for vector of foreign types +pub trait TryFromReprCVec<'slice>: Sized { + /// Vec equivalent of [`TryFromReprC::Source`] + type Source: ReprC + Copy; + + /// Type into which state can be stored during conversion. Useful for returning + /// non-owning types but performing some conversion which requires allocation. + /// Serves similar purpose as does context in a closure + type Store: Default; + + /// Convert from [`Self::Source`] into `&[Self]` + /// + /// # Errors + /// + /// * [`FfiResult::ArgIsNull`] - given pointer is null + /// * [`FfiResult::UnknownHandle`] - given id doesn't identify any known handle + /// * [`FfiResult::TrapRepresentation`] - given value contains trap representation + /// + /// # Safety + /// + /// All conversions from a pointer must ensure pointer validity beforehand + unsafe fn try_from_repr_c( + source: Self::Source, + store: &'slice mut Self::Store, + ) -> Result>; +} + /// Wrapper around `T` that is local to the conversion site. This structure carries /// ownership and care must be taken not to let it transfer ownership into an FFI function // NOTE: It's not possible to mutably reference local context @@ -121,40 +157,34 @@ impl LocalSlice { } } -impl IntoFfi for Vec +impl<'itm, T> IntoFfiVec for &'itm T where - T::Target: ReprC, + &'itm T: IntoFfi, { - type Target = LocalSlice; + type Target = LocalSlice<::Target>; + + fn into_ffi(source: Vec) -> Self::Target { + source.into_iter().map(IntoFfi::into_ffi).collect() + } +} + +impl IntoFfi for Vec { + type Target = T::Target; fn into_ffi(self) -> Self::Target { - self.into_iter().map(IntoFfi::into_ffi).collect() + ::into_ffi(self) } } -impl<'itm, T: TryFromReprC<'itm>> TryFromReprC<'itm> for Vec { - type Source = SliceRef<'itm, T::Source>; - type Store = Vec; +impl<'slice, T: TryFromReprCVec<'slice> + 'slice> TryFromReprC<'slice> for Vec { + type Source = T::Source; + type Store = T::Store; unsafe fn try_from_repr_c( source: Self::Source, - store: &'itm mut Self::Store, - ) -> Result { - let prev_store_len = store.len(); - let slice = source.into_rust().ok_or(FfiReturn::ArgIsNull)?; - store.extend(core::iter::repeat_with(Default::default).take(slice.len())); - - let mut substore = &mut store[prev_store_len..]; - let mut res = Vec::with_capacity(slice.len()); - - let mut i = 0; - while let Some((first, rest)) = substore.split_first_mut() { - res.push(>::try_from_repr_c(slice[i], first)?); - substore = rest; - i += 1; - } - - Ok(res) + store: &'slice mut Self::Store, + ) -> Result { + ::try_from_repr_c(source, store) } } @@ -165,7 +195,7 @@ impl<'itm> TryFromReprC<'itm> for String { unsafe fn try_from_repr_c( source: Self::Source, _: &mut Self::Store, - ) -> Result { + ) -> Result { String::from_utf8(source.into_rust().ok_or(FfiReturn::ArgIsNull)?.to_owned()) .map_err(|_e| FfiReturn::Utf8Error) } @@ -177,7 +207,7 @@ impl<'itm> TryFromReprC<'itm> for &'itm str { unsafe fn try_from_repr_c( source: Self::Source, _: &mut Self::Store, - ) -> Result { + ) -> Result { core::str::from_utf8(source.into_rust().ok_or(FfiReturn::ArgIsNull)?) .map_err(|_e| FfiReturn::Utf8Error) } diff --git a/ffi/src/primitives.rs b/ffi/src/primitives.rs index bd8f1614e1c..a328287cb3d 100644 --- a/ffi/src/primitives.rs +++ b/ffi/src/primitives.rs @@ -1,6 +1,10 @@ +//! Logic related to the conversion of primitive types. #![allow(trivial_casts)] +use alloc::vec::Vec; + use crate::{ + owned::{IntoFfiVec, LocalSlice, TryFromReprCVec}, slice::{ IntoFfiSliceMut, IntoFfiSliceRef, SliceMut, SliceRef, TryFromReprCSliceMut, TryFromReprCSliceRef, @@ -64,7 +68,7 @@ impl<'slice> TryFromReprCSliceRef<'slice> for bool { } impl IntoFfi for bool { - type Target = u8; + type Target = ::Target; fn into_ffi(self) -> Self::Target { u8::from(self).into_ffi() @@ -139,10 +143,10 @@ impl<'slice> TryFromReprCSliceRef<'slice> for core::cmp::Ordering { } impl IntoFfi for core::cmp::Ordering { - type Target = i8; + type Target = ::Target; fn into_ffi(self) -> Self::Target { - self as i8 + (self as i8).into_ffi() } } impl IntoFfi for &core::cmp::Ordering { @@ -169,16 +173,43 @@ impl<'itm> IntoFfiSliceRef<'itm> for core::cmp::Ordering { } } +/// Trait for replacing unsupported types with supported ones when crossing FFI-boundary (for example in case of wasm) +pub trait PrimitiveRepr { + /// Type used to represent [`Self`] when crossing FFI-boundry + type Repr; +} + +macro_rules! primitive_repr_impls { + ($($source:ty => $target:ty),+ $(,)?) => {$( + impl PrimitiveRepr for $source { + type Repr = $target; + } + )+}; +} +macro_rules! primitive_repr_self_impls { + ($($source:ty),+ $(,)?) => { + primitive_repr_impls! { + $($source => $source),* + } + }; +} + +#[cfg(feature = "wasm")] +primitive_repr_impls! {u8 => u32, u16 => u32, i8 => i32, i16 => i32} +#[cfg(not(feature = "wasm"))] +primitive_repr_self_impls! {u8, u16, i8, i16} +primitive_repr_self_impls! {u32, u64, u128, i32, i64, i128} + macro_rules! primitive_impls { ( $( $ty:ty ),+ $(,)? ) => { $( unsafe impl ReprC for $ty {} impl TryFromReprC<'_> for $ty { - type Source = Self; + type Source = <$ty as PrimitiveRepr>::Repr; type Store = (); unsafe fn try_from_repr_c(source: Self::Source, _: &mut Self::Store) -> Result { - Ok(source) + source.try_into().map_err(|_| FfiReturn::TrapRepresentation) } } @@ -201,10 +232,10 @@ macro_rules! primitive_impls { } impl IntoFfi for $ty { - type Target = Self; + type Target = <$ty as PrimitiveRepr>::Repr; fn into_ffi(self) -> Self::Target { - self + self.into() } } @@ -221,8 +252,29 @@ macro_rules! primitive_impls { fn into_ffi(source: &mut [Self]) -> Self::Target { SliceMut::from_slice(source) } - } )+ - }; + } + + impl IntoFfiVec for $ty + { + type Target = LocalSlice<$ty>; + + fn into_ffi(source: Vec<$ty>) -> Self::Target { + source.into_iter().collect() + } + } + + impl<'itm> TryFromReprCVec<'itm> for $ty { + type Source = SliceRef<'itm, $ty>; + type Store = (); + + unsafe fn try_from_repr_c( + source: Self::Source, + _: &'itm mut Self::Store, + ) -> Result> { + source.into_rust().ok_or(FfiReturn::ArgIsNull).map(alloc::borrow::ToOwned::to_owned) + } + } + )+}; } primitive_impls! {u8, u16, u32, u64, u128, i8, i16, i32, i64} diff --git a/ffi/tests/ffi_export.rs b/ffi/tests/ffi_export.rs index 6cef3f43ddb..52403c3764d 100644 --- a/ffi/tests/ffi_export.rs +++ b/ffi/tests/ffi_export.rs @@ -286,12 +286,12 @@ fn return_result() { unsafe { assert_eq!( FfiReturn::ExecutionFail, - FfiStruct__fallible_int_output(u8::from(false), output.as_mut_ptr()) + FfiStruct__fallible_int_output(From::from(false), output.as_mut_ptr()) ); assert_eq!(0, output.assume_init()); assert_eq!( FfiReturn::Ok, - FfiStruct__fallible_int_output(u8::from(true), output.as_mut_ptr()) + FfiStruct__fallible_int_output(From::from(true), output.as_mut_ptr()) ); assert_eq!(42, output.assume_init()); } diff --git a/ffi/tests/gen_shared_fns.rs b/ffi/tests/gen_shared_fns.rs index ea0e4dba5cd..17b3d41c3c5 100644 --- a/ffi/tests/gen_shared_fns.rs +++ b/ffi/tests/gen_shared_fns.rs @@ -59,7 +59,7 @@ fn gen_shared_fns() { cloned }; - let mut is_equal = MaybeUninit::::new(1); + let mut is_equal = MaybeUninit::new(1); let cloned_ptr = IntoFfi::into_ffi(&cloned); __eq( @@ -73,7 +73,7 @@ fn gen_shared_fns() { assert!(is_equal); // TODO: Fix - let mut ordering = MaybeUninit::::new(1); + let mut ordering = MaybeUninit::new(1); __ord( FfiStruct1::ID, ffi_struct1.cast(), From 51f8b9ba94cac7af259f1611ddc51e7ece88bead Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Fri, 5 Aug 2022 12:44:59 +0300 Subject: [PATCH 2/3] Relace trait `PrimitiveRepr` with `WasmRepr` Signed-off-by: Shanin Roman --- ffi/src/primitives.rs | 51 ++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/ffi/src/primitives.rs b/ffi/src/primitives.rs index a328287cb3d..7cdd34b03e7 100644 --- a/ffi/src/primitives.rs +++ b/ffi/src/primitives.rs @@ -173,39 +173,47 @@ impl<'itm> IntoFfiSliceRef<'itm> for core::cmp::Ordering { } } -/// Trait for replacing unsupported types with supported ones when crossing FFI-boundary (for example in case of wasm) -pub trait PrimitiveRepr { +/// Trait for replacing unsupported types with supported when crossing WASM FFI-boundary +#[cfg(feature = "wasm")] +pub trait WasmRepr { /// Type used to represent [`Self`] when crossing FFI-boundry - type Repr; + type Repr: ReprC; } -macro_rules! primitive_repr_impls { - ($($source:ty => $target:ty),+ $(,)?) => {$( - impl PrimitiveRepr for $source { - type Repr = $target; +#[cfg(feature = "wasm")] +macro_rules! wasm_repr_impls { + ($src:ty = $dst:ty, $($tail:tt)+) => { + wasm_repr_impls! { $src = $dst } + wasm_repr_impls! { $($tail)+ } + }; + ($src:ty, $($tail:tt)+) => { + wasm_repr_impls! { $src } + wasm_repr_impls! { $($tail)+ } + }; + ($src:ty = $dst:ty) => { + impl WasmRepr for $src { + type Repr = $dst; } - )+}; -} -macro_rules! primitive_repr_self_impls { - ($($source:ty),+ $(,)?) => { - primitive_repr_impls! { - $($source => $source),* + }; + ($src:ty) => { + impl WasmRepr for $src { + type Repr = Self; } }; } #[cfg(feature = "wasm")] -primitive_repr_impls! {u8 => u32, u16 => u32, i8 => i32, i16 => i32} -#[cfg(not(feature = "wasm"))] -primitive_repr_self_impls! {u8, u16, i8, i16} -primitive_repr_self_impls! {u32, u64, u128, i32, i64, i128} +wasm_repr_impls! {u8 = u32, u16 = u32, i8 = i32, i16 = i32, u32, u64, i32, i64} macro_rules! primitive_impls { ( $( $ty:ty ),+ $(,)? ) => { $( unsafe impl ReprC for $ty {} impl TryFromReprC<'_> for $ty { - type Source = <$ty as PrimitiveRepr>::Repr; + #[cfg(feature = "wasm")] + type Source = <$ty as WasmRepr>::Repr; + #[cfg(not(feature = "wasm"))] + type Source = Self; type Store = (); unsafe fn try_from_repr_c(source: Self::Source, _: &mut Self::Store) -> Result { @@ -232,7 +240,10 @@ macro_rules! primitive_impls { } impl IntoFfi for $ty { - type Target = <$ty as PrimitiveRepr>::Repr; + #[cfg(feature = "wasm")] + type Target = <$ty as WasmRepr>::Repr; + #[cfg(not(feature = "wasm"))] + type Target = Self; fn into_ffi(self) -> Self::Target { self.into() @@ -277,4 +288,4 @@ macro_rules! primitive_impls { )+}; } -primitive_impls! {u8, u16, u32, u64, u128, i8, i16, i32, i64} +primitive_impls! {u8, u16, u32, u64, i8, i16, i32, i64} From 762bbb94a7182d2cac3e61fa8643a345e4319966 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Fri, 5 Aug 2022 14:02:15 +0300 Subject: [PATCH 3/3] Add `ConversionFailed` to `FfiReturn` Signed-off-by: Shanin Roman --- ffi/derive/src/convert.rs | 8 +++++--- ffi/src/handle.rs | 2 ++ ffi/src/lib.rs | 2 ++ ffi/src/owned.rs | 18 ++++++------------ ffi/src/primitives.rs | 2 +- ffi/tests/ffi_export.rs | 20 ++++++++++++++++++++ ffi/tests/gen_shared_fns.rs | 1 - 7 files changed, 36 insertions(+), 17 deletions(-) diff --git a/ffi/derive/src/convert.rs b/ffi/derive/src/convert.rs index 0ca6abc1c9e..d442f7b8038 100644 --- a/ffi/derive/src/convert.rs +++ b/ffi/derive/src/convert.rs @@ -86,7 +86,8 @@ fn variant_discriminants(enum_: &syn::DataEnum) -> Vec { } fn derive_try_from_repr_c_for_opaque_item_wrapper(name: &Ident) -> TokenStream2 { - let opaque_item_slice_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_slice(name); + let opaque_item_slice_try_from_repr_c_derive = + derive_try_from_repr_c_for_opaque_item_slice(name); let opaque_item_vec_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_vec(name); quote! { @@ -146,7 +147,8 @@ fn derive_try_from_repr_c_for_opaque_item_wrapper(name: &Ident) -> TokenStream2 } fn derive_try_from_repr_c_for_opaque_item(name: &Ident) -> TokenStream2 { - let opaque_item_slice_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_slice(name); + let opaque_item_slice_try_from_repr_c_derive = + derive_try_from_repr_c_for_opaque_item_slice(name); let opaque_item_vec_try_from_repr_c_derive = derive_try_from_repr_c_for_opaque_item_vec(name); quote! { @@ -460,7 +462,7 @@ fn derive_into_ffi_for_fieldless_enum(enum_name: &Ident, repr: &[syn::NestedMeta quote! { impl iroha_ffi::IntoFfi for #enum_name { type Target = <#ffi_type as iroha_ffi::IntoFfi>::Target; - + fn into_ffi(self) -> Self::Target { (self as #ffi_type).into_ffi() } diff --git a/ffi/src/handle.rs b/ffi/src/handle.rs index ce0779561f5..4a262eec450 100644 --- a/ffi/src/handle.rs +++ b/ffi/src/handle.rs @@ -113,6 +113,7 @@ macro_rules! def_ffi_fn { handle_id: $crate::handle::Id, left_handle_ptr: *const core::ffi::c_void, right_handle_ptr: *const core::ffi::c_void, + // Pointer to FFI-safe representation of `bool` (u8 or u32 if `wasm` feature is active) output_ptr: *mut ::Target, ) -> $crate::FfiReturn { $crate::def_ffi_fn!(@catch_unwind { @@ -152,6 +153,7 @@ macro_rules! def_ffi_fn { handle_id: $crate::handle::Id, left_handle_ptr: *const core::ffi::c_void, right_handle_ptr: *const core::ffi::c_void, + // Pointer to FFI-safe representation of `Ordering` (i8 or i32 if `wasm` feature is active) output_ptr: *mut ::Target, ) -> $crate::FfiReturn { $crate::def_ffi_fn!(@catch_unwind { diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index ba5c47dc5dc..d13a7f7a2f6 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -109,6 +109,8 @@ pub trait Output: Sized { #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(i8)] pub enum FfiReturn { + /// The input argument provided to FFI function can't be converted into inner rust representation. + ConversionFailed = -7, /// The input argument provided to FFI function has a trap representation. TrapRepresentation = -6, /// FFI function execution panicked. diff --git a/ffi/src/owned.rs b/ffi/src/owned.rs index 0caa2262ee0..2d939bd6b1c 100644 --- a/ffi/src/owned.rs +++ b/ffi/src/owned.rs @@ -5,7 +5,7 @@ use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec}; use crate::{ slice::{OutBoxedSlice, SliceRef}, - AsReprCRef, FfiReturn, IntoFfi, Output, ReprC, TryFromReprC, Result + AsReprCRef, FfiReturn, IntoFfi, Output, ReprC, Result, TryFromReprC, }; /// Trait that facilitates the implementation of [`IntoFfi`] for vectors of foreign types @@ -31,9 +31,9 @@ pub trait TryFromReprCVec<'slice>: Sized { /// /// # Errors /// - /// * [`FfiResult::ArgIsNull`] - given pointer is null - /// * [`FfiResult::UnknownHandle`] - given id doesn't identify any known handle - /// * [`FfiResult::TrapRepresentation`] - given value contains trap representation + /// * [`FfiReturn::ArgIsNull`] - given pointer is null + /// * [`FfiReturn::UnknownHandle`] - given id doesn't identify any known handle + /// * [`FfiReturn::TrapRepresentation`] - given value contains trap representation /// /// # Safety /// @@ -192,10 +192,7 @@ impl<'itm> TryFromReprC<'itm> for String { type Source = as TryFromReprC<'itm>>::Source; type Store = (); - unsafe fn try_from_repr_c( - source: Self::Source, - _: &mut Self::Store, - ) -> Result { + unsafe fn try_from_repr_c(source: Self::Source, _: &mut Self::Store) -> Result { String::from_utf8(source.into_rust().ok_or(FfiReturn::ArgIsNull)?.to_owned()) .map_err(|_e| FfiReturn::Utf8Error) } @@ -204,10 +201,7 @@ impl<'itm> TryFromReprC<'itm> for &'itm str { type Source = <&'itm [u8] as TryFromReprC<'itm>>::Source; type Store = (); - unsafe fn try_from_repr_c( - source: Self::Source, - _: &mut Self::Store, - ) -> Result { + unsafe fn try_from_repr_c(source: Self::Source, _: &mut Self::Store) -> Result { core::str::from_utf8(source.into_rust().ok_or(FfiReturn::ArgIsNull)?) .map_err(|_e| FfiReturn::Utf8Error) } diff --git a/ffi/src/primitives.rs b/ffi/src/primitives.rs index 7cdd34b03e7..a1954315df1 100644 --- a/ffi/src/primitives.rs +++ b/ffi/src/primitives.rs @@ -217,7 +217,7 @@ macro_rules! primitive_impls { type Store = (); unsafe fn try_from_repr_c(source: Self::Source, _: &mut Self::Store) -> Result { - source.try_into().map_err(|_| FfiReturn::TrapRepresentation) + source.try_into().map_err(|_| FfiReturn::ConversionFailed) } } diff --git a/ffi/tests/ffi_export.rs b/ffi/tests/ffi_export.rs index 52403c3764d..4e4a70908a3 100644 --- a/ffi/tests/ffi_export.rs +++ b/ffi/tests/ffi_export.rs @@ -89,6 +89,12 @@ impl FfiStruct { } } +#[ffi_export] +/// Return byte +pub fn simple(byte: u8) -> u8 { + byte +} + fn get_new_struct() -> FfiStruct { let name = Name(String::from("X")); @@ -296,3 +302,17 @@ fn return_result() { assert_eq!(42, output.assume_init()); } } + +#[cfg(feature = "wasm")] +#[test] +fn conversion_failed() { + let byte: u32 = u32::MAX; + let mut output = MaybeUninit::new(0); + + unsafe { + assert_eq!( + FfiReturn::ConversionFailed, + __simple(byte, output.as_mut_ptr()) + ) + } +} diff --git a/ffi/tests/gen_shared_fns.rs b/ffi/tests/gen_shared_fns.rs index 17b3d41c3c5..bbdfe4c0592 100644 --- a/ffi/tests/gen_shared_fns.rs +++ b/ffi/tests/gen_shared_fns.rs @@ -72,7 +72,6 @@ fn gen_shared_fns() { TryFromReprC::try_from_repr_c(is_equal.assume_init(), &mut ()).unwrap(); assert!(is_equal); - // TODO: Fix let mut ordering = MaybeUninit::new(1); __ord( FfiStruct1::ID,