mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-10 08:47:58 +00:00
Remove UserError and switch to error::Error (#2899)
* Remove `UserError` and switch to `error::Error` * More cleanup * Update core/executor/src/error.rs Co-Authored-By: Sergei Pepyakin <s.pepyakin@gmail.com> * Fix typo * Update core/executor/src/allocator.rs Co-Authored-By: Stanislav Tkach <stanislav.tkach@gmail.com>
This commit is contained in:
@@ -17,9 +17,8 @@
|
||||
//! This module implements a freeing-bump allocator.
|
||||
//! See more details at https://github.com/paritytech/substrate/issues/1615.
|
||||
|
||||
use crate::wasm_utils::UserError;
|
||||
use crate::error::{Error, Result};
|
||||
use log::trace;
|
||||
use wasmi::Error;
|
||||
use wasmi::MemoryRef;
|
||||
use wasmi::memory_units::Bytes;
|
||||
|
||||
@@ -34,9 +33,6 @@ const ALIGNMENT: u32 = 8;
|
||||
const N: usize = 22;
|
||||
const MAX_POSSIBLE_ALLOCATION: u32 = 16777216; // 2^24 bytes
|
||||
|
||||
pub const OUT_OF_SPACE: &str = "Requested allocation size does not fit into remaining heap space";
|
||||
pub const REQUESTED_SIZE_TOO_LARGE: &str = "Requested size to allocate is too large";
|
||||
|
||||
pub struct FreeingBumpHeapAllocator {
|
||||
bumper: u32,
|
||||
heads: [u32; N],
|
||||
@@ -46,8 +42,12 @@ pub struct FreeingBumpHeapAllocator {
|
||||
total_size: u32,
|
||||
}
|
||||
|
||||
impl FreeingBumpHeapAllocator {
|
||||
/// Create an allocator error.
|
||||
fn error(msg: &'static str) -> Error {
|
||||
Error::Allocator(msg)
|
||||
}
|
||||
|
||||
impl FreeingBumpHeapAllocator {
|
||||
/// Creates a new allocation heap which follows a freeing-bump strategy.
|
||||
/// The maximum size which can be allocated at once is 16 MiB.
|
||||
///
|
||||
@@ -87,23 +87,22 @@ impl FreeingBumpHeapAllocator {
|
||||
|
||||
/// Gets requested number of bytes to allocate and returns a pointer.
|
||||
/// The maximum size which can be allocated at once is 16 MiB.
|
||||
pub fn allocate(&mut self, size: u32) -> Result<u32, UserError> {
|
||||
pub fn allocate(&mut self, size: u32) -> Result<u32> {
|
||||
if size > MAX_POSSIBLE_ALLOCATION {
|
||||
return Err(UserError(REQUESTED_SIZE_TOO_LARGE));
|
||||
return Err(Error::RequestedAllocationTooLarge);
|
||||
}
|
||||
|
||||
let size = size.max(8);
|
||||
let item_size = size.next_power_of_two();
|
||||
if item_size + 8 + self.total_size > self.max_heap_size {
|
||||
return Err(UserError(OUT_OF_SPACE));
|
||||
return Err(Error::AllocatorOutOfSpace);
|
||||
}
|
||||
|
||||
let list_index = (item_size.trailing_zeros() - 3) as usize;
|
||||
let ptr: u32 = if self.heads[list_index] != 0 {
|
||||
// Something from the free list
|
||||
let item = self.heads[list_index];
|
||||
let four_bytes = self.get_heap_4bytes(item)
|
||||
.map_err(|_| UserError("Unable to get bytes at pointer taken from list of free items"))?;
|
||||
let four_bytes = self.get_heap_4bytes(item)?;
|
||||
self.heads[list_index] = FreeingBumpHeapAllocator::le_bytes_to_u32(four_bytes);
|
||||
item + 8
|
||||
} else {
|
||||
@@ -111,13 +110,9 @@ impl FreeingBumpHeapAllocator {
|
||||
self.bump(item_size + 8) + 8
|
||||
};
|
||||
|
||||
for i in 1..8 {
|
||||
self.set_heap(ptr - i, 255)
|
||||
.map_err(|_| UserError("Unable to successively write bytes into heap at pointer prefix"))?;
|
||||
}
|
||||
(1..8).try_for_each(|i| self.set_heap(ptr - i, 255))?;
|
||||
|
||||
self.set_heap(ptr - 8, list_index as u8)
|
||||
.map_err(|_| UserError("Unable to write byte into heap at pointer prefix"))?;
|
||||
self.set_heap(ptr - 8, list_index as u8)?;
|
||||
|
||||
self.total_size = self.total_size + item_size + 8;
|
||||
trace!(target: "wasm-heap", "Heap size is {} bytes after allocation", self.total_size);
|
||||
@@ -126,31 +121,24 @@ impl FreeingBumpHeapAllocator {
|
||||
}
|
||||
|
||||
/// Deallocates the space which was allocated for a pointer.
|
||||
pub fn deallocate(&mut self, ptr: u32) -> Result<(), UserError> {
|
||||
pub fn deallocate(&mut self, ptr: u32) -> Result<()> {
|
||||
let ptr = ptr - self.ptr_offset;
|
||||
if ptr < 8 {
|
||||
return Err(UserError("Invalid pointer for deallocation"));
|
||||
return Err(error("Invalid pointer for deallocation"));
|
||||
}
|
||||
|
||||
let list_index = self.get_heap_byte(ptr - 8)
|
||||
.map_err(|_| UserError("Unable to access pointer prefix"))? as usize;
|
||||
for i in 1..8 {
|
||||
let heap_byte = self.get_heap_byte(ptr - i)
|
||||
.map_err(|_| UserError("Unable to write single bytes into heap at pointer"))?;
|
||||
debug_assert!(heap_byte == 255)
|
||||
}
|
||||
let list_index = usize::from(self.get_heap_byte(ptr - 8)?);
|
||||
(1..8).try_for_each(|i| self.get_heap_byte(ptr - i).map(|byte| assert!(byte == 255)))?;
|
||||
let tail = self.heads[list_index];
|
||||
self.heads[list_index] = ptr - 8;
|
||||
|
||||
let mut slice = self.get_heap_4bytes(ptr - 8)
|
||||
.map_err(|_| UserError("Unable to get 4 bytes from heap at pointer prefix"))?;
|
||||
let mut slice = self.get_heap_4bytes(ptr - 8)?;
|
||||
FreeingBumpHeapAllocator::write_u32_into_le_bytes(tail, &mut slice);
|
||||
self.set_heap_4bytes(ptr - 8, slice)
|
||||
.map_err(|_| UserError("Unable to write 4 bytes into heap at pointer prefix"))?;
|
||||
self.set_heap_4bytes(ptr - 8, slice)?;
|
||||
|
||||
let item_size = FreeingBumpHeapAllocator::get_item_size_from_index(list_index);
|
||||
self.total_size = self.total_size.checked_sub(item_size as u32 + 8)
|
||||
.ok_or_else(|| UserError("Unable to subtract from total heap size without overflow"))?;
|
||||
.ok_or_else(|| error("Unable to subtract from total heap size without overflow"))?;
|
||||
trace!(target: "wasm-heap", "Heap size is {} bytes after deallocation", self.total_size);
|
||||
|
||||
Ok(())
|
||||
@@ -176,24 +164,24 @@ impl FreeingBumpHeapAllocator {
|
||||
1 << 3 << index
|
||||
}
|
||||
|
||||
fn get_heap_4bytes(&mut self, ptr: u32) -> Result<[u8; 4], Error> {
|
||||
fn get_heap_4bytes(&mut self, ptr: u32) -> Result<[u8; 4]> {
|
||||
let mut arr = [0u8; 4];
|
||||
self.heap.get_into(self.ptr_offset + ptr, &mut arr)?;
|
||||
Ok(arr)
|
||||
}
|
||||
|
||||
fn get_heap_byte(&mut self, ptr: u32) -> Result<u8, Error> {
|
||||
fn get_heap_byte(&mut self, ptr: u32) -> Result<u8> {
|
||||
let mut arr = [0u8; 1];
|
||||
self.heap.get_into(self.ptr_offset + ptr, &mut arr)?;
|
||||
Ok(arr[0])
|
||||
}
|
||||
|
||||
fn set_heap(&mut self, ptr: u32, value: u8) -> Result<(), Error> {
|
||||
self.heap.set(self.ptr_offset + ptr, &[value])
|
||||
fn set_heap(&mut self, ptr: u32, value: u8) -> Result<()> {
|
||||
self.heap.set(self.ptr_offset + ptr, &[value]).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn set_heap_4bytes(&mut self, ptr: u32, value: [u8; 4]) -> Result<(), Error> {
|
||||
self.heap.set(self.ptr_offset + ptr, &value)
|
||||
fn set_heap_4bytes(&mut self, ptr: u32, value: [u8; 4]) -> Result<()> {
|
||||
self.heap.set(self.ptr_offset + ptr, &value).map_err(Into::into)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -353,7 +341,10 @@ mod tests {
|
||||
// then
|
||||
assert_eq!(ptr.is_err(), true);
|
||||
if let Err(err) = ptr {
|
||||
assert_eq!(err, UserError(OUT_OF_SPACE));
|
||||
match err {
|
||||
Error::AllocatorOutOfSpace => {},
|
||||
_ => panic!("Expected out of space error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +363,10 @@ mod tests {
|
||||
// there is no room for another half page incl. its 8 byte prefix
|
||||
assert_eq!(ptr2.is_err(), true);
|
||||
if let Err(err) = ptr2 {
|
||||
assert_eq!(err, UserError(OUT_OF_SPACE));
|
||||
match err {
|
||||
Error::AllocatorOutOfSpace => {},
|
||||
_ => panic!("Expected out of space error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +396,10 @@ mod tests {
|
||||
// then
|
||||
assert_eq!(ptr.is_err(), true);
|
||||
if let Err(err) = ptr {
|
||||
assert_eq!(err, UserError(REQUESTED_SIZE_TOO_LARGE));
|
||||
match err {
|
||||
Error::RequestedAllocationTooLarge => {},
|
||||
e => panic!("Expected out of space error, got: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,20 @@ pub enum Error {
|
||||
/// Runtime failed.
|
||||
#[display(fmt="Runtime error")]
|
||||
Runtime,
|
||||
/// Runtime failed.
|
||||
/// Invalid memory reference.
|
||||
#[display(fmt="Invalid memory reference")]
|
||||
InvalidMemoryReference,
|
||||
/// Some other error occurred
|
||||
Other(&'static str),
|
||||
/// Some error occurred in the allocator
|
||||
#[display(fmt="Error in allocator: {}", _0)]
|
||||
Allocator(&'static str),
|
||||
/// The allocator run out of space.
|
||||
#[display(fmt="Allocator run out of space")]
|
||||
AllocatorOutOfSpace,
|
||||
/// Someone tried to allocate more memory than the allowed maximum per allocation.
|
||||
#[display(fmt="Requested allocation size is too large")]
|
||||
RequestedAllocationTooLarge,
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
@@ -72,3 +83,11 @@ impl std::error::Error for Error {
|
||||
}
|
||||
|
||||
impl state_machine::Error for Error {}
|
||||
|
||||
impl wasmi::HostError for Error {}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
fn from(err: &'static str) -> Error {
|
||||
Error::Other(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,13 @@
|
||||
|
||||
//! This module implements sandboxing support in the runtime.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use crate::error::{Result, Error};
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
use parity_codec::{Decode, Encode};
|
||||
use primitives::sandbox as sandbox_primitives;
|
||||
use crate::wasm_utils::UserError;
|
||||
use wasmi;
|
||||
use wasmi::memory_units::Pages;
|
||||
use wasmi::{
|
||||
Externals, FuncRef, ImportResolver, MemoryInstance, MemoryRef, Module, ModuleInstance,
|
||||
ModuleRef, RuntimeArgs, RuntimeValue, Trap, TrapKind
|
||||
ModuleRef, RuntimeArgs, RuntimeValue, Trap, TrapKind, memory_units::Pages,
|
||||
};
|
||||
|
||||
/// Index of a function inside the supervisor.
|
||||
@@ -75,18 +72,18 @@ impl ImportResolver for Imports {
|
||||
module_name: &str,
|
||||
field_name: &str,
|
||||
signature: &::wasmi::Signature,
|
||||
) -> Result<FuncRef, ::wasmi::Error> {
|
||||
) -> std::result::Result<FuncRef, wasmi::Error> {
|
||||
let key = (
|
||||
module_name.as_bytes().to_owned(),
|
||||
field_name.as_bytes().to_owned(),
|
||||
);
|
||||
let idx = *self.func_map.get(&key).ok_or_else(|| {
|
||||
::wasmi::Error::Instantiation(format!(
|
||||
wasmi::Error::Instantiation(format!(
|
||||
"Export {}:{} not found",
|
||||
module_name, field_name
|
||||
))
|
||||
})?;
|
||||
Ok(::wasmi::FuncInstance::alloc_host(signature.clone(), idx.0))
|
||||
Ok(wasmi::FuncInstance::alloc_host(signature.clone(), idx.0))
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
@@ -94,7 +91,7 @@ impl ImportResolver for Imports {
|
||||
module_name: &str,
|
||||
field_name: &str,
|
||||
_memory_type: &::wasmi::MemoryDescriptor,
|
||||
) -> Result<MemoryRef, ::wasmi::Error> {
|
||||
) -> std::result::Result<MemoryRef, wasmi::Error> {
|
||||
let key = (
|
||||
module_name.as_bytes().to_vec(),
|
||||
field_name.as_bytes().to_vec(),
|
||||
@@ -102,7 +99,7 @@ impl ImportResolver for Imports {
|
||||
let mem = self.memories_map
|
||||
.get(&key)
|
||||
.ok_or_else(|| {
|
||||
::wasmi::Error::Instantiation(format!(
|
||||
wasmi::Error::Instantiation(format!(
|
||||
"Export {}:{} not found",
|
||||
module_name, field_name
|
||||
))
|
||||
@@ -116,8 +113,8 @@ impl ImportResolver for Imports {
|
||||
module_name: &str,
|
||||
field_name: &str,
|
||||
_global_type: &::wasmi::GlobalDescriptor,
|
||||
) -> Result<::wasmi::GlobalRef, ::wasmi::Error> {
|
||||
Err(::wasmi::Error::Instantiation(format!(
|
||||
) -> std::result::Result<wasmi::GlobalRef, wasmi::Error> {
|
||||
Err(wasmi::Error::Instantiation(format!(
|
||||
"Export {}:{} not found",
|
||||
module_name, field_name
|
||||
)))
|
||||
@@ -128,8 +125,8 @@ impl ImportResolver for Imports {
|
||||
module_name: &str,
|
||||
field_name: &str,
|
||||
_table_type: &::wasmi::TableDescriptor,
|
||||
) -> Result<::wasmi::TableRef, ::wasmi::Error> {
|
||||
Err(::wasmi::Error::Instantiation(format!(
|
||||
) -> std::result::Result<wasmi::TableRef, wasmi::Error> {
|
||||
Err(wasmi::Error::Instantiation(format!(
|
||||
"Export {}:{} not found",
|
||||
module_name, field_name
|
||||
)))
|
||||
@@ -153,7 +150,7 @@ pub trait SandboxCapabilities {
|
||||
/// Returns `Err` if allocation not possible or errors during heap management.
|
||||
///
|
||||
/// Returns pointer to the allocated block.
|
||||
fn allocate(&mut self, len: u32) -> Result<u32, UserError>;
|
||||
fn allocate(&mut self, len: u32) -> Result<u32>;
|
||||
|
||||
/// Deallocate space specified by the pointer that was previously returned by [`allocate`].
|
||||
///
|
||||
@@ -162,21 +159,21 @@ pub trait SandboxCapabilities {
|
||||
/// Returns `Err` if deallocation not possible or because of errors in heap management.
|
||||
///
|
||||
/// [`allocate`]: #tymethod.allocate
|
||||
fn deallocate(&mut self, ptr: u32) -> Result<(), UserError>;
|
||||
fn deallocate(&mut self, ptr: u32) -> Result<()>;
|
||||
|
||||
/// Write `data` into the supervisor memory at offset specified by `ptr`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `Err` if `ptr + data.len()` is out of bounds.
|
||||
fn write_memory(&mut self, ptr: u32, data: &[u8]) -> Result<(), UserError>;
|
||||
fn write_memory(&mut self, ptr: u32, data: &[u8]) -> Result<()>;
|
||||
|
||||
/// Read `len` bytes from the supervisor memory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `Err` if `ptr + len` is out of bounds.
|
||||
fn read_memory(&self, ptr: u32, len: u32) -> Result<Vec<u8>, UserError>;
|
||||
fn read_memory(&self, ptr: u32, len: u32) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
/// Implementation of [`Externals`] that allows execution of guest module with
|
||||
@@ -190,12 +187,12 @@ pub struct GuestExternals<'a, FE: SandboxCapabilities + Externals + 'a> {
|
||||
}
|
||||
|
||||
fn trap(msg: &'static str) -> Trap {
|
||||
TrapKind::Host(Box::new(UserError(msg))).into()
|
||||
TrapKind::Host(Box::new(Error::Other(msg))).into()
|
||||
}
|
||||
|
||||
fn deserialize_result(serialized_result: &[u8]) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn deserialize_result(serialized_result: &[u8]) -> std::result::Result<Option<RuntimeValue>, Trap> {
|
||||
use self::sandbox_primitives::{HostError, ReturnValue};
|
||||
let result_val = Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..])
|
||||
let result_val = std::result::Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..])
|
||||
.ok_or_else(|| trap("Decoding Result<ReturnValue, HostError> failed!"))?;
|
||||
|
||||
match result_val {
|
||||
@@ -212,7 +209,7 @@ impl<'a, FE: SandboxCapabilities + Externals + 'a> Externals for GuestExternals<
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
) -> std::result::Result<Option<RuntimeValue>, Trap> {
|
||||
// Make `index` typesafe again.
|
||||
let index = GuestFuncIndex(index);
|
||||
|
||||
@@ -331,7 +328,7 @@ impl SandboxInstance {
|
||||
args: &[RuntimeValue],
|
||||
supervisor_externals: &mut FE,
|
||||
state: u32,
|
||||
) -> Result<Option<wasmi::RuntimeValue>, wasmi::Error> {
|
||||
) -> std::result::Result<Option<wasmi::RuntimeValue>, wasmi::Error> {
|
||||
with_guest_externals(
|
||||
supervisor_externals,
|
||||
self,
|
||||
@@ -362,7 +359,7 @@ pub enum InstantiationError {
|
||||
fn decode_environment_definition(
|
||||
raw_env_def: &[u8],
|
||||
memories: &[Option<MemoryRef>],
|
||||
) -> Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> {
|
||||
) -> std::result::Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> {
|
||||
let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut &raw_env_def[..])
|
||||
.ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?;
|
||||
|
||||
@@ -420,7 +417,7 @@ pub fn instantiate<FE: SandboxCapabilities + Externals>(
|
||||
wasm: &[u8],
|
||||
raw_env_def: &[u8],
|
||||
state: u32,
|
||||
) -> Result<u32, InstantiationError> {
|
||||
) -> std::result::Result<u32, InstantiationError> {
|
||||
let (imports, guest_to_supervisor_mapping) =
|
||||
decode_environment_definition(raw_env_def, &supervisor_externals.store().memories)?;
|
||||
|
||||
@@ -476,7 +473,7 @@ impl Store {
|
||||
///
|
||||
/// Returns `Err` if the memory couldn't be created.
|
||||
/// Typically happens if `initial` is more than `maximum`.
|
||||
pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result<u32, UserError> {
|
||||
pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result<u32> {
|
||||
let maximum = match maximum {
|
||||
sandbox_primitives::MEM_UNLIMITED => None,
|
||||
specified_limit => Some(Pages(specified_limit as usize)),
|
||||
@@ -486,8 +483,7 @@ impl Store {
|
||||
MemoryInstance::alloc(
|
||||
Pages(initial as usize),
|
||||
maximum,
|
||||
)
|
||||
.map_err(|_| UserError("Sandboxed memory allocation error"))?;
|
||||
)?;
|
||||
|
||||
let mem_idx = self.memories.len();
|
||||
self.memories.push(Some(mem));
|
||||
@@ -500,12 +496,12 @@ impl Store {
|
||||
///
|
||||
/// Returns `Err` If `instance_idx` isn't a valid index of an instance or
|
||||
/// instance is already torndown.
|
||||
pub fn instance(&self, instance_idx: u32) -> Result<Rc<SandboxInstance>, UserError> {
|
||||
pub fn instance(&self, instance_idx: u32) -> Result<Rc<SandboxInstance>> {
|
||||
self.instances
|
||||
.get(instance_idx as usize)
|
||||
.cloned()
|
||||
.ok_or_else(|| UserError("Trying to access a non-existent instance"))?
|
||||
.ok_or_else(|| UserError("Trying to access a torndown instance"))
|
||||
.ok_or_else(|| "Trying to access a non-existent instance")?
|
||||
.ok_or_else(|| "Trying to access a torndown instance".into())
|
||||
}
|
||||
|
||||
/// Returns reference to a memory instance by `memory_idx`.
|
||||
@@ -514,12 +510,12 @@ impl Store {
|
||||
///
|
||||
/// Returns `Err` If `memory_idx` isn't a valid index of an memory or
|
||||
/// if memory has been torn down.
|
||||
pub fn memory(&self, memory_idx: u32) -> Result<MemoryRef, UserError> {
|
||||
pub fn memory(&self, memory_idx: u32) -> Result<MemoryRef> {
|
||||
self.memories
|
||||
.get(memory_idx as usize)
|
||||
.cloned()
|
||||
.ok_or_else(|| UserError("Trying to access a non-existent sandboxed memory"))?
|
||||
.ok_or_else(|| UserError("Trying to access a torndown sandboxed memory"))
|
||||
.ok_or_else(|| "Trying to access a non-existent sandboxed memory")?
|
||||
.ok_or_else(|| "Trying to access a torndown sandboxed memory".into())
|
||||
}
|
||||
|
||||
/// Tear down the memory at the specified index.
|
||||
@@ -528,10 +524,10 @@ impl Store {
|
||||
///
|
||||
/// Returns `Err` if `memory_idx` isn't a valid index of an memory or
|
||||
/// if it has been torn down.
|
||||
pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<(), UserError> {
|
||||
pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<()> {
|
||||
match self.memories.get_mut(memory_idx as usize) {
|
||||
None => Err(UserError("Trying to teardown a non-existent sandboxed memory")),
|
||||
Some(None) => Err(UserError("Double teardown of a sandboxed memory")),
|
||||
None => Err("Trying to teardown a non-existent sandboxed memory".into()),
|
||||
Some(None) => Err("Double teardown of a sandboxed memory".into()),
|
||||
Some(memory) => {
|
||||
*memory = None;
|
||||
Ok(())
|
||||
@@ -545,10 +541,10 @@ impl Store {
|
||||
///
|
||||
/// Returns `Err` if `instance_idx` isn't a valid index of an instance or
|
||||
/// if it has been torn down.
|
||||
pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<(), UserError> {
|
||||
pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<()> {
|
||||
match self.instances.get_mut(instance_idx as usize) {
|
||||
None => Err(UserError("Trying to teardown a non-existent instance")),
|
||||
Some(None) => Err(UserError("Double teardown of an instance")),
|
||||
None => Err("Trying to teardown a non-existent instance".into()),
|
||||
Some(None) => Err("Double teardown of an instance".into()),
|
||||
Some(instance) => {
|
||||
*instance = None;
|
||||
Ok(())
|
||||
@@ -565,9 +561,8 @@ impl Store {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives::{Blake2Hasher};
|
||||
use crate::allocator;
|
||||
use crate::sandbox::trap;
|
||||
use crate::wasm_executor::WasmExecutor;
|
||||
use state_machine::TestExternalities as CoreTestExternalities;
|
||||
use wabt;
|
||||
@@ -647,7 +642,7 @@ mod tests {
|
||||
if let Err(err) = res {
|
||||
assert_eq!(
|
||||
format!("{}", err),
|
||||
format!("{}", wasmi::Error::Trap(trap(allocator::OUT_OF_SPACE)))
|
||||
format!("{}", wasmi::Error::Trap(Error::AllocatorOutOfSpace.into()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,31 +16,73 @@
|
||||
|
||||
//! Rust implementation of Substrate contracts.
|
||||
|
||||
use wasmi::{ValueType, RuntimeValue, HostError};
|
||||
use wasmi::{ValueType, RuntimeValue};
|
||||
use wasmi::nan_preserving_float::{F32, F64};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct UserError(pub &'static str);
|
||||
impl fmt::Display for UserError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "UserError: {}", self.0)
|
||||
}
|
||||
}
|
||||
impl HostError for UserError {
|
||||
pub trait ConvertibleToWasm {
|
||||
const VALUE_TYPE: ValueType;
|
||||
type NativeType; fn to_runtime_value(self) -> RuntimeValue;
|
||||
}
|
||||
|
||||
pub trait ConvertibleToWasm { const VALUE_TYPE: ValueType; type NativeType; fn to_runtime_value(self) -> RuntimeValue; }
|
||||
impl ConvertibleToWasm for i32 { type NativeType = i32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self) } }
|
||||
impl ConvertibleToWasm for u32 { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } }
|
||||
impl ConvertibleToWasm for i64 { type NativeType = i64; const VALUE_TYPE: ValueType = ValueType::I64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self) } }
|
||||
impl ConvertibleToWasm for u64 { type NativeType = u64; const VALUE_TYPE: ValueType = ValueType::I64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self as i64) } }
|
||||
impl ConvertibleToWasm for F32 { type NativeType = F32; const VALUE_TYPE: ValueType = ValueType::F32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F32(self) } }
|
||||
impl ConvertibleToWasm for F64 { type NativeType = F64; const VALUE_TYPE: ValueType = ValueType::F64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F64(self) } }
|
||||
impl ConvertibleToWasm for isize { type NativeType = i32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } }
|
||||
impl ConvertibleToWasm for usize { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as u32 as i32) } }
|
||||
impl<T> ConvertibleToWasm for *const T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } }
|
||||
impl<T> ConvertibleToWasm for *mut T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } }
|
||||
impl ConvertibleToWasm for i32 {
|
||||
type NativeType = i32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self) }
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for u32 {
|
||||
type NativeType = u32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) }
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for i64 {
|
||||
type NativeType = i64;
|
||||
const VALUE_TYPE: ValueType = ValueType::I64;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self) }
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for u64 {
|
||||
type NativeType = u64;
|
||||
const VALUE_TYPE: ValueType = ValueType::I64;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self as i64) }
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for F32 {
|
||||
type NativeType = F32;
|
||||
const VALUE_TYPE: ValueType = ValueType::F32;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F32(self) }
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for F64 {
|
||||
type NativeType = F64;
|
||||
const VALUE_TYPE: ValueType = ValueType::F64;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F64(self) }
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for isize {
|
||||
type NativeType = i32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) }
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for usize {
|
||||
type NativeType = u32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as u32 as i32) }
|
||||
}
|
||||
|
||||
impl<T> ConvertibleToWasm for *const T {
|
||||
type NativeType = u32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) }
|
||||
}
|
||||
|
||||
impl<T> ConvertibleToWasm for *mut T {
|
||||
type NativeType = u32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) }
|
||||
}
|
||||
|
||||
/// Converts arguments into respective WASM types.
|
||||
#[macro_export]
|
||||
@@ -118,7 +160,7 @@ macro_rules! unmarshall_args {
|
||||
#[inline(always)]
|
||||
pub fn constrain_closure<R, F>(f: F) -> F
|
||||
where
|
||||
F: FnOnce() -> Result<R, ::wasmi::Trap>
|
||||
F: FnOnce() -> Result<R, crate::error::Error>
|
||||
{
|
||||
f
|
||||
}
|
||||
@@ -132,14 +174,14 @@ macro_rules! marshall {
|
||||
>(|| {
|
||||
unmarshall_args!($body, $objectname, $args_iter, $( $names : $params ),*)
|
||||
});
|
||||
let r = body()?;
|
||||
let r = body().map_err(wasmi::Trap::from)?;
|
||||
return Ok(Some({ use $crate::wasm_utils::ConvertibleToWasm; r.to_runtime_value() }))
|
||||
});
|
||||
( $args_iter:ident, $objectname:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({
|
||||
let body = $crate::wasm_utils::constrain_closure::<(), _>(|| {
|
||||
unmarshall_args!($body, $objectname, $args_iter, $( $names : $params ),*)
|
||||
});
|
||||
body()?;
|
||||
body().map_err(wasmi::Trap::from)?;
|
||||
return Ok(None)
|
||||
})
|
||||
}
|
||||
@@ -154,7 +196,13 @@ macro_rules! dispatch_fn {
|
||||
panic!("fn with index {} is undefined", $index);
|
||||
};
|
||||
|
||||
( @iter $index:expr, $index_ident:ident, $objectname:ident, $args_iter:ident, $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt $($tail:tt)*) => (
|
||||
(@iter
|
||||
$index:expr,
|
||||
$index_ident:ident,
|
||||
$objectname:ident,
|
||||
$args_iter:ident,
|
||||
$name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt $($tail:tt)*
|
||||
) => (
|
||||
if $index_ident == $index {
|
||||
{ marshall!($args_iter, $objectname, ( $( $names : $params ),* ) $( -> $returns )* => $body) }
|
||||
}
|
||||
@@ -177,7 +225,11 @@ macro_rules! impl_function_executor {
|
||||
fn resolver() -> &'static dyn $crate::wasmi::ModuleImportResolver {
|
||||
struct Resolver;
|
||||
impl $crate::wasmi::ModuleImportResolver for Resolver {
|
||||
fn resolve_func(&self, name: &str, signature: &$crate::wasmi::Signature) -> ::std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> {
|
||||
fn resolve_func(
|
||||
&self,
|
||||
name: &str,
|
||||
signature: &$crate::wasmi::Signature
|
||||
) -> std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> {
|
||||
resolve_fn!(signature, name, $( $name( $( $params ),* ) $( -> $returns )* => )*);
|
||||
|
||||
Err($crate::wasmi::Error::Instantiation(
|
||||
@@ -194,7 +246,7 @@ macro_rules! impl_function_executor {
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: $crate::wasmi::RuntimeArgs,
|
||||
) -> ::std::result::Result<Option<$crate::wasmi::RuntimeValue>, $crate::wasmi::Trap> {
|
||||
) -> std::result::Result<Option<$crate::wasmi::RuntimeValue>, $crate::wasmi::Trap> {
|
||||
let $objectname = self;
|
||||
let mut args = args.as_ref().iter();
|
||||
dispatch_fn!(index, $objectname, args, $( $name( $( $names : $params ),* ) $( -> $returns )* => $body ),*);
|
||||
|
||||
Reference in New Issue
Block a user