Extract execution engines definitions into their own crates (#4489)

* Clean imports in wasmi_execution

* Replace `interpret_runtime_api_result` with `pointer_and_len_from_u64`.

* Extract sc-executor-common crate

* Extract `sc-executor-wasmi` into its own crate

* Extract `sc-executor-wasmtime` into its own crate.

* Add missing headers.

* Clean and docs

* Docs for sc-executor-wasmi

* Expand a comment about sandboxing

* Fix assert_matches

* Rename (un)pack_ptr_and_len and move them into util module

* Remove wasmtime errors in sc-executor-common
This commit is contained in:
Sergei Pepyakin
2019-12-24 13:17:41 +01:00
committed by GitHub
parent b214b3f3e9
commit 1782fbbbba
25 changed files with 326 additions and 161 deletions
@@ -16,7 +16,10 @@
//! Provides implementations for the runtime interface traits.
use crate::{RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner}};
use crate::{
RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner},
util::{unpack_ptr_and_len, pack_ptr_and_len},
};
#[cfg(feature = "std")]
use crate::host::*;
#[cfg(not(feature = "std"))]
@@ -44,27 +47,6 @@ assert_eq_size!(usize, u32);
#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))]
assert_eq_size!(*const u8, u32);
/// Converts a pointer and length into an `u64`.
pub fn pointer_and_len_to_u64(ptr: u32, len: u32) -> u64 {
// The static assertions from above are changed into a runtime check.
#[cfg(all(not(feature = "std"), feature = "disable_target_static_assertions"))]
assert_eq!(4, sp_std::mem::size_of::<usize>());
(u64::from(len) << 32) | u64::from(ptr)
}
/// Splits an `u64` into the pointer and length.
pub fn pointer_and_len_from_u64(val: u64) -> (u32, u32) {
// The static assertions from above are changed into a runtime check.
#[cfg(all(not(feature = "std"), feature = "disable_target_static_assertions"))]
assert_eq!(4, sp_std::mem::size_of::<usize>());
let ptr = (val & (!0u32 as u64)) as u32;
let len = (val >> 32) as u32;
(ptr, len)
}
/// Implement the traits for the given primitive traits.
macro_rules! impl_traits_for_primitives {
(
@@ -186,7 +168,7 @@ impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
let ptr = context.allocate_memory(vec.as_ref().len() as u32)?;
context.write_memory(ptr, &vec)?;
Ok(pointer_and_len_to_u64(ptr.into(), vec.len() as u32))
Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
}
}
@@ -211,7 +193,7 @@ impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
#[cfg(not(feature = "std"))]
impl<T: 'static + Decode> FromFFIValue for Vec<T> {
fn from_ffi_value(arg: u64) -> Vec<T> {
let (ptr, len) = pointer_and_len_from_u64(arg);
let (ptr, len) = unpack_ptr_and_len(arg);
let len = len as usize;
if TypeId::of::<T>() == TypeId::of::<u8>() {
@@ -238,7 +220,7 @@ impl<T: 'static + Decode> FromFFIValue for [T] {
type SelfInstance = Vec<T>;
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<Vec<T>> {
let (ptr, len) = pointer_and_len_from_u64(arg);
let (ptr, len) = unpack_ptr_and_len(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
@@ -259,7 +241,7 @@ impl IntoPreallocatedFFIValue for [u8] {
context: &mut dyn FunctionContext,
allocated: u64,
) -> Result<()> {
let (ptr, len) = pointer_and_len_from_u64(allocated);
let (ptr, len) = unpack_ptr_and_len(allocated);
if (len as usize) < self_instance.len() {
Err(
@@ -282,10 +264,10 @@ impl<T: 'static + Encode> IntoFFIValue for [T] {
fn into_ffi_value(&self) -> WrappedFFIValue<u64, Vec<u8>> {
if TypeId::of::<T>() == TypeId::of::<u8>() {
let slice = unsafe { mem::transmute::<&[T], &[u8]>(self) };
pointer_and_len_to_u64(slice.as_ptr() as u32, slice.len() as u32).into()
pack_ptr_and_len(slice.as_ptr() as u32, slice.len() as u32).into()
} else {
let data = self.encode();
let ffi_value = pointer_and_len_to_u64(data.as_ptr() as u32, data.len() as u32);
let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32);
(ffi_value, data).into()
}
}
@@ -428,7 +410,7 @@ impl FromFFIValue for str {
type SelfInstance = String;
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<String> {
let (ptr, len) = pointer_and_len_from_u64(arg);
let (ptr, len) = unpack_ptr_and_len(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
@@ -443,7 +425,7 @@ impl IntoFFIValue for str {
fn into_ffi_value(&self) -> WrappedFFIValue<u64, ()> {
let bytes = self.as_bytes();
pointer_and_len_to_u64(bytes.as_ptr() as u32, bytes.len() as u32).into()
pack_ptr_and_len(bytes.as_ptr() as u32, bytes.len() as u32).into()
}
}
@@ -241,6 +241,10 @@ pub mod host;
pub mod wasm;
pub mod pass_by;
mod util;
pub use util::unpack_ptr_and_len;
/// Something that can be used by the runtime interface as type to communicate between wasm and the
/// host.
///
@@ -260,4 +264,4 @@ pub type Pointer<T> = *mut T;
/// A pointer that can be used in a runtime interface function signature.
#[cfg(feature = "std")]
pub type Pointer<T> = sp_wasm_interface::Pointer<T>;
pub type Pointer<T> = sp_wasm_interface::Pointer<T>;
@@ -20,7 +20,7 @@
//! [`Codec`](pass_by::Codec), [`Inner`](pass_by::Inner) and [`Enum`](pass_by::Enum) are the
//! provided strategy implementations.
use crate::{RIType, impls::{pointer_and_len_from_u64, pointer_and_len_to_u64}};
use crate::{RIType, util::{unpack_ptr_and_len, pack_ptr_and_len}};
#[cfg(feature = "std")]
use crate::host::*;
@@ -228,14 +228,14 @@ impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
let ptr = context.allocate_memory(vec.len() as u32)?;
context.write_memory(ptr, &vec)?;
Ok(pointer_and_len_to_u64(ptr.into(), vec.len() as u32))
Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
}
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T> {
let (ptr, len) = pointer_and_len_from_u64(arg);
let (ptr, len) = unpack_ptr_and_len(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
T::decode(&mut &vec[..])
.map_err(|e| format!("Could not decode value from wasm: {}", e.what()))
@@ -248,12 +248,12 @@ impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
let data = instance.encode();
let ffi_value = pointer_and_len_to_u64(data.as_ptr() as u32, data.len() as u32);
let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32);
(ffi_value, data).into()
}
fn from_ffi_value(arg: Self::FFIType) -> T {
let (ptr, len) = pointer_and_len_from_u64(arg);
let (ptr, len) = unpack_ptr_and_len(arg);
let len = len as usize;
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, len) };
@@ -0,0 +1,59 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Various utilities that help interfacing with wasm runtime code.
/// Pack a pointer and length into an `u64`.
pub fn pack_ptr_and_len(ptr: u32, len: u32) -> u64 {
// The static assertions from above are changed into a runtime check.
#[cfg(all(not(feature = "std"), feature = "disable_target_static_assertions"))]
assert_eq!(4, sp_std::mem::size_of::<usize>());
(u64::from(len) << 32) | u64::from(ptr)
}
/// Unpacks an `u64` into the pointer and length.
///
/// Runtime API functions return a 64-bit value which encodes a pointer in the least-significant
/// 32-bits and a length in the most-significant 32 bits. This interprets the returned value as a pointer,
/// length tuple.
pub fn unpack_ptr_and_len(val: u64) -> (u32, u32) {
// The static assertions from above are changed into a runtime check.
#[cfg(all(not(feature = "std"), feature = "disable_target_static_assertions"))]
assert_eq!(4, sp_std::mem::size_of::<usize>());
let ptr = (val & (!0u32 as u64)) as u32;
let len = (val >> 32) as u32;
(ptr, len)
}
#[cfg(test)]
mod tests {
use super::{pack_ptr_and_len, unpack_ptr_and_len};
#[test]
fn ptr_len_packing_unpacking() {
const PTR: u32 = 0x1337;
const LEN: u32 = 0x7f000000;
let packed = pack_ptr_and_len(PTR, LEN);
let (ptr, len) = unpack_ptr_and_len(packed);
assert_eq!(PTR, ptr);
assert_eq!(LEN, len);
}
}