Skip to content

Commit

Permalink
refactor(core-backend): Refactor MemoryError (#2892)
Browse files Browse the repository at this point in the history
  • Loading branch information
ark0f authored Jul 10, 2023
1 parent 8b897c2 commit 5aa7ac5
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 140 deletions.
19 changes: 9 additions & 10 deletions core-backend/common/src/funcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@

use crate::{
memory::{MemoryAccessError, WasmMemoryRead},
runtime::Runtime,
syscall_trace, ActorTerminationReason, BackendAllocExternalitiesError, BackendExternalities,
BackendExternalitiesError, MessageWaitedType, TerminationReason, TrapExplanation,
runtime::{RunFallibleError, Runtime},
syscall_trace, ActorTerminationReason, BackendAllocSyscallError, BackendExternalities,
BackendSyscallError, MessageWaitedType, TerminationReason, TrapExplanation,
UnrecoverableExecutionError, UnrecoverableMemoryError, PTR_SPECIAL,
};
use alloc::string::{String, ToString};
Expand Down Expand Up @@ -50,9 +50,9 @@ pub struct FuncsHandler<Ext: Externalities + 'static, Runtime> {
impl<Ext, R> FuncsHandler<Ext, R>
where
Ext: BackendExternalities + 'static,
Ext::UnrecoverableError: BackendExternalitiesError,
Ext::FallibleError: BackendExternalitiesError,
Ext::AllocError: BackendAllocExternalitiesError<ExtError = Ext::UnrecoverableError>,
Ext::UnrecoverableError: BackendSyscallError,
RunFallibleError: From<Ext::FallibleError>,
Ext::AllocError: BackendAllocSyscallError<ExtError = Ext::UnrecoverableError>,
R: Runtime<Ext>,
{
/// !!! Usage warning: make sure to do it before any other read/write,
Expand All @@ -69,12 +69,11 @@ where
fn read_message_payload(
ctx: &mut R,
read_payload: WasmMemoryRead,
) -> Result<Payload, TerminationReason> {
) -> Result<Payload, RunFallibleError> {
ctx.read(read_payload)?
.try_into()
.map_err(|PayloadSizeError| {
TrapExplanation::FallibleExt(MessageError::MaxMessageSizeExceed.into()).into()
})
.map_err(|PayloadSizeError| MessageError::MaxMessageSizeExceed.into())
.map_err(RunFallibleError::FallibleExt)
}

#[host(fallible, wgas, cost = RuntimeCosts::Send(len))]
Expand Down
68 changes: 25 additions & 43 deletions core-backend/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ pub mod funcs;
pub mod memory;
pub mod runtime;

use crate::memory::MemoryAccessError;
use alloc::{
collections::{BTreeMap, BTreeSet},
string::String,
Expand All @@ -44,7 +43,6 @@ use core::{
fmt::{Debug, Display},
};
use gear_core::{
buffer::RuntimeBufferSizeError,
env::Externalities,
gas::{ChargeError, CountersOwner, GasAmount, GasLeft},
ids::{CodeId, MessageId, ProgramId, ReservationId},
Expand All @@ -55,12 +53,13 @@ use gear_core::{
pages::{GearPage, WasmPage},
reservation::GasReserver,
};
use gear_core_errors::{ExtError as FallibleExtError, MemoryError};
use lazy_pages::GlobalsAccessConfig;
use memory::ProcessAccessError;
use scale_info::scale::{self, Decode, Encode};

use crate::runtime::RunFallibleError;
pub use crate::utils::{LimitedStr, TrimmedString};
use gear_core::memory::MemoryError;
pub use log;

pub const PTR_SPECIAL: u32 = u32::MAX;
Expand All @@ -71,21 +70,6 @@ pub enum TerminationReason {
System(SystemTerminationReason),
}

impl From<MemoryAccessError> for TerminationReason {
fn from(err: MemoryAccessError) -> Self {
match err {
MemoryAccessError::Memory(err) => TrapExplanation::FallibleExt(err.into()).into(),
MemoryAccessError::RuntimeBuffer(RuntimeBufferSizeError) => {
TrapExplanation::FallibleExt(MemoryError::RuntimeAllocOutOfBounds.into()).into()
}
MemoryAccessError::Decode => unreachable!("{:?}", err),
MemoryAccessError::GasLimitExceeded => TrapExplanation::GasLimitExceeded.into(),
MemoryAccessError::GasAllowanceExceeded => ActorTerminationReason::GasAllowanceExceeded,
}
.into()
}
}

impl From<ChargeError> for TerminationReason {
fn from(err: ChargeError) -> Self {
match err {
Expand All @@ -99,18 +83,18 @@ impl From<ChargeError> for TerminationReason {
}
}

impl<E: BackendExternalitiesError> From<E> for TerminationReason {
fn from(err: E) -> Self {
err.into_termination_reason()
}
}

impl From<TrapExplanation> for TerminationReason {
fn from(trap: TrapExplanation) -> Self {
ActorTerminationReason::Trap(trap).into()
}
}

impl<E: BackendSyscallError> From<E> for TerminationReason {
fn from(err: E) -> Self {
err.into_termination_reason()
}
}

#[derive(Decode, Encode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, derive_more::From)]
#[codec(crate = scale)]
pub enum ActorTerminationReason {
Expand Down Expand Up @@ -169,6 +153,9 @@ pub enum UnrecoverableExecutionError {
derive_more::From,
)]
pub enum UnrecoverableMemoryError {
/// The error occurs in attempt to access memory outside wasm program memory.
#[display(fmt = "Trying to access memory outside wasm program memory")]
AccessOutOfBounds,
/// The error occurs, when program tries to allocate in block-chain runtime more memory than allowed.
#[display(fmt = "Trying to allocate more memory in block-chain runtime than allowed")]
RuntimeAllocOutOfBounds,
Expand Down Expand Up @@ -243,8 +230,6 @@ pub enum TrapExplanation {
ProgramAllocOutOfBounds,
#[display(fmt = "Sys-call unrecoverable error: {_0}")]
UnrecoverableExt(UnrecoverableExtError),
#[display(fmt = "Sys-call fallible error: {_0}")]
FallibleExt(FallibleExtError),
#[display(fmt = "{_0}")]
Panic(TrimmedString),
#[display(fmt = "Reason is unknown. Possibly `unreachable` instruction is occurred")]
Expand Down Expand Up @@ -304,17 +289,20 @@ pub trait BackendExternalities: Externalities + CountersOwner {
) -> Result<(), ProcessAccessError>;
}

/// A trait for conversion of the externalities API error to `TerminationReason`.
pub trait BackendExternalitiesError: Clone + Sized {
/// A trait for conversion of the externalities API error
/// to `TerminationReason` and `RunFallibleError`.
pub trait BackendSyscallError: Sized {
fn into_termination_reason(self) -> TerminationReason;

fn into_run_fallible_error(self) -> RunFallibleError;
}

// TODO: consider to remove this trait and use Result<Result<Page, AllocError>, GasError> instead #2571
/// A trait for conversion of the externalities memory management error to api error.
///
/// If the conversion fails, then `Self` is returned in the `Err` variant.
pub trait BackendAllocExternalitiesError: Sized {
type ExtError: BackendExternalitiesError;
pub trait BackendAllocSyscallError: Sized {
type ExtError: BackendSyscallError;

fn into_backend_error(self) -> Result<Self::ExtError, Self>;
}
Expand Down Expand Up @@ -406,27 +394,21 @@ pub trait BackendState {
/// Process fallible syscall function result
fn process_fallible_func_result<T: Sized>(
&mut self,
res: Result<T, TerminationReason>,
res: Result<T, RunFallibleError>,
) -> Result<Result<T, u32>, TerminationReason> {
match res {
Err(err) => {
if let TerminationReason::Actor(ActorTerminationReason::Trap(
TrapExplanation::FallibleExt(ext_err),
)) = err
{
let code = ext_err.to_u32();
log::trace!(target: "syscalls", "fallible syscall error: {ext_err}");
Ok(Err(code))
} else {
Err(err)
}
Err(RunFallibleError::FallibleExt(ext_err)) => {
let code = ext_err.to_u32();
log::trace!(target: "syscalls", "fallible syscall error: {ext_err}");
Ok(Err(code))
}
Err(RunFallibleError::TerminationReason(reason)) => Err(reason),
Ok(res) => Ok(Ok(res)),
}
}

/// Process alloc function result
fn process_alloc_func_result<T: Sized, ExtAllocError: BackendAllocExternalitiesError>(
fn process_alloc_func_result<T: Sized, ExtAllocError: BackendAllocSyscallError>(
&mut self,
res: Result<T, ExtAllocError>,
) -> Result<Result<T, ExtAllocError>, TerminationReason> {
Expand Down
57 changes: 44 additions & 13 deletions core-backend/common/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

//! Work with WASM program memory in backends.

use crate::BackendExternalities;
use crate::{
runtime::RunFallibleError, ActorTerminationReason, BackendExternalities, BackendSyscallError,
TerminationReason, TrapExplanation, UnrecoverableMemoryError,
};
use alloc::vec::Vec;
use core::{
fmt::Debug,
Expand All @@ -31,9 +34,9 @@ use core::{
use gear_core::{
buffer::{RuntimeBuffer, RuntimeBufferSizeError},
gas::GasLeft,
memory::{Memory, MemoryInterval},
memory::{Memory, MemoryError, MemoryInterval},
};
use gear_core_errors::MemoryError;
use gear_core_errors::MemoryError as FallibleMemoryError;
use scale_info::scale::{self, Decode, DecodeAll, Encode, MaxEncodedLen};

/// Memory access error during sys-call that lazy-pages have caught.
Expand All @@ -47,22 +50,50 @@ pub enum ProcessAccessError {

#[derive(Debug, Clone, derive_more::From)]
pub enum MemoryAccessError {
#[from]
Memory(MemoryError),
#[from]
ProcessAccess(ProcessAccessError),
RuntimeBuffer(RuntimeBufferSizeError),
// TODO: remove #2164
Decode,
GasLimitExceeded,
GasAllowanceExceeded,
}

impl From<ProcessAccessError> for MemoryAccessError {
fn from(err: ProcessAccessError) -> Self {
match err {
ProcessAccessError::OutOfBounds => MemoryError::AccessOutOfBounds.into(),
ProcessAccessError::GasLimitExceeded => Self::GasLimitExceeded,
ProcessAccessError::GasAllowanceExceeded => Self::GasAllowanceExceeded,
impl BackendSyscallError for MemoryAccessError {
fn into_termination_reason(self) -> TerminationReason {
match self {
MemoryAccessError::ProcessAccess(ProcessAccessError::OutOfBounds)
| MemoryAccessError::Memory(MemoryError::AccessOutOfBounds) => {
TrapExplanation::UnrecoverableExt(
UnrecoverableMemoryError::AccessOutOfBounds.into(),
)
.into()
}
MemoryAccessError::RuntimeBuffer(RuntimeBufferSizeError) => {
TrapExplanation::UnrecoverableExt(
UnrecoverableMemoryError::RuntimeAllocOutOfBounds.into(),
)
.into()
}
MemoryAccessError::ProcessAccess(ProcessAccessError::GasLimitExceeded) => {
TrapExplanation::GasLimitExceeded.into()
}
MemoryAccessError::ProcessAccess(ProcessAccessError::GasAllowanceExceeded) => {
ActorTerminationReason::GasAllowanceExceeded
}
MemoryAccessError::Decode => unreachable!(),
}
.into()
}

fn into_run_fallible_error(self) -> RunFallibleError {
match self {
MemoryAccessError::Memory(MemoryError::AccessOutOfBounds)
| MemoryAccessError::ProcessAccess(ProcessAccessError::OutOfBounds) => {
RunFallibleError::FallibleExt(FallibleMemoryError::AccessOutOfBounds.into())
}
MemoryAccessError::RuntimeBuffer(RuntimeBufferSizeError) => {
RunFallibleError::FallibleExt(FallibleMemoryError::RuntimeAllocOutOfBounds.into())
}
e => RunFallibleError::TerminationReason(e.into_termination_reason()),
}
}
}
Expand Down
23 changes: 14 additions & 9 deletions core-backend/common/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::{
memory::ProcessAccessError, BackendAllocExternalitiesError, BackendExternalities,
BackendExternalitiesError, ExtInfo, SystemReservationContext, TerminationReason,
memory::ProcessAccessError, runtime::RunFallibleError, BackendAllocSyscallError,
BackendExternalities, BackendSyscallError, ExtInfo, SystemReservationContext,
TerminationReason,
};
use alloc::{collections::BTreeSet, vec, vec::Vec};
use core::{cell::Cell, fmt, fmt::Debug};
Expand All @@ -27,12 +28,12 @@ use gear_core::{
env::{Externalities, PayloadSliceLock, UnlockPayloadBound},
gas::{ChargeError, CountersOwner, GasAmount, GasCounter, GasLeft},
ids::{MessageId, ProgramId, ReservationId},
memory::{Memory, MemoryInterval},
memory::{Memory, MemoryError, MemoryInterval},
message::{HandlePacket, IncomingDispatch, InitPacket, ReplyPacket},
pages::{PageNumber, PageU32Size, WasmPage, WASM_PAGE_SIZE},
reservation::GasReserver,
};
use gear_core_errors::{MemoryError, ReplyCode, SignalCode};
use gear_core_errors::{ReplyCode, SignalCode};
use gear_wasm_instrument::syscalls::SysCallName;
use scale_info::scale::{self, Decode, Encode};

Expand All @@ -47,13 +48,17 @@ impl fmt::Display for Error {
}
}

impl BackendExternalitiesError for Error {
impl BackendSyscallError for Error {
fn into_termination_reason(self) -> TerminationReason {
unimplemented!()
}

fn into_run_fallible_error(self) -> RunFallibleError {
unimplemented!()
}
}

impl BackendAllocExternalitiesError for Error {
impl BackendAllocSyscallError for Error {
type ExtError = Self;

fn into_backend_error(self) -> Result<Self::ExtError, Self> {
Expand Down Expand Up @@ -353,18 +358,18 @@ impl Memory for MockMemory {
self.write_attempt_count.set(self.write_attempt_count() + 1);
let page_index = self
.page_index(offset)
.ok_or(MemoryError::RuntimeAllocOutOfBounds)?;
.ok_or(MemoryError::AccessOutOfBounds)?;
let page_offset = offset as usize % WASM_PAGE_SIZE;

if page_offset + buffer.len() > WASM_PAGE_SIZE {
return Err(MemoryError::RuntimeAllocOutOfBounds);
return Err(MemoryError::AccessOutOfBounds);
}

let page_start = page_index * WASM_PAGE_SIZE;
let start = page_start + page_offset;

if start + buffer.len() > self.pages.len() {
return Err(MemoryError::RuntimeAllocOutOfBounds);
return Err(MemoryError::AccessOutOfBounds);
}

let dest = &mut self.pages[start..(start + buffer.len())];
Expand Down
21 changes: 19 additions & 2 deletions core-backend/common/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,26 @@

use crate::{
memory::{MemoryAccessRecorder, MemoryOwner},
BackendExternalities, BackendState, TerminationReason,
BackendExternalities, BackendState, BackendSyscallError, TerminationReason,
};
use gear_core::{costs::RuntimeCosts, pages::WasmPage};
use gear_core_errors::ExtError as FallibleExtError;

/// Error returned from closure argument in [`Runtime::run_fallible`].
#[derive(Debug, Clone)]
pub enum RunFallibleError {
TerminationReason(TerminationReason),
FallibleExt(FallibleExtError),
}

impl<E> From<E> for RunFallibleError
where
E: BackendSyscallError,
{
fn from(err: E) -> Self {
err.into_run_fallible_error()
}
}

pub trait Runtime<Ext: BackendExternalities>:
MemoryOwner + MemoryAccessRecorder + BackendState
Expand All @@ -44,7 +61,7 @@ pub trait Runtime<Ext: BackendExternalities>:
f: F,
) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, TerminationReason>,
F: FnOnce(&mut Self) -> Result<T, RunFallibleError>,
R: From<Result<T, u32>> + Sized;

fn alloc(&mut self, pages: u32) -> Result<WasmPage, Ext::AllocError>;
Expand Down
Loading

0 comments on commit 5aa7ac5

Please sign in to comment.