diff --git a/runtime/near-vm-errors/src/lib.rs b/runtime/near-vm-errors/src/lib.rs index a0db37c9b4d..d334ab51301 100644 --- a/runtime/near-vm-errors/src/lib.rs +++ b/runtime/near-vm-errors/src/lib.rs @@ -29,7 +29,7 @@ pub enum FunctionCallError { MethodResolveError(MethodResolveError), /// A trap happened during execution of a binary WasmTrap(WasmTrap), - WasmUnknownError, + WasmUnknownError(String), HostError(HostError), EvmError(EvmError), /// Non-deterministic error. @@ -65,6 +65,8 @@ pub enum WasmTrap { StackOverflow, /// Generic trap. GenericTrap, + /// Indirect call to null. + IndirectCallToNull, } #[derive( @@ -355,8 +357,8 @@ impl fmt::Display for FunctionCallError { FunctionCallError::HostError(e) => e.fmt(f), FunctionCallError::LinkError { msg } => write!(f, "{}", msg), FunctionCallError::WasmTrap(trap) => write!(f, "WebAssembly trap: {}", trap), - FunctionCallError::WasmUnknownError => { - write!(f, "Unknown error during Wasm contract execution") + FunctionCallError::WasmUnknownError(msg) => { + write!(f, "Unknown error during Wasm contract execution: {}", msg) } FunctionCallError::EvmError(e) => write!(f, "EVM: {:?}", e), FunctionCallError::Nondeterministic(msg) => { @@ -381,6 +383,7 @@ impl fmt::Display for WasmTrap { WasmTrap::MisalignedAtomicAccess => write!(f, "Misaligned atomic access trap."), WasmTrap::GenericTrap => write!(f, "Generic trap."), WasmTrap::StackOverflow => write!(f, "Stack overflow."), + WasmTrap::IndirectCallToNull => write!(f, "Indirect call to null."), } } } diff --git a/runtime/near-vm-runner/src/wasmer1_runner.rs b/runtime/near-vm-runner/src/wasmer1_runner.rs index 2e2ead5db47..7848ddf86f3 100644 --- a/runtime/near-vm-runner/src/wasmer1_runner.rs +++ b/runtime/near-vm-runner/src/wasmer1_runner.rs @@ -118,7 +118,7 @@ impl IntoVMError for wasmer::RuntimeError { } Some(TrapCode::OutOfBounds) => FunctionCallError::WasmTrap(WasmTrap::MemoryOutOfBounds), Some(TrapCode::IndirectCallToNull) => { - FunctionCallError::WasmTrap(WasmTrap::IncorrectCallIndirectSignature) + FunctionCallError::WasmTrap(WasmTrap::IndirectCallToNull) } Some(TrapCode::BadSignature) => { FunctionCallError::WasmTrap(WasmTrap::IncorrectCallIndirectSignature) @@ -135,16 +135,16 @@ impl IntoVMError for wasmer::RuntimeError { Some(TrapCode::UnreachableCodeReached) => { FunctionCallError::WasmTrap(WasmTrap::Unreachable) } - Some(TrapCode::Interrupt) => { - FunctionCallError::Nondeterministic("Wasmer interrupt".to_string()) - } Some(TrapCode::UnalignedAtomic) => { FunctionCallError::WasmTrap(WasmTrap::MisalignedAtomicAccess) } + Some(TrapCode::Interrupt) => { + FunctionCallError::Nondeterministic("Wasmer interrupt".to_string()) + } Some(TrapCode::VMOutOfMemory) => { FunctionCallError::Nondeterministic("Wasmer out of memory".to_string()) } - None => FunctionCallError::Nondeterministic(error_msg), + None => panic!("Unknown error: {}", error_msg), }; VMError::FunctionCallError(error) } diff --git a/runtime/near-vm-runner/src/wasmer_runner.rs b/runtime/near-vm-runner/src/wasmer_runner.rs index 20bbf8e5ce7..991e2b9c1ef 100644 --- a/runtime/near-vm-runner/src/wasmer_runner.rs +++ b/runtime/near-vm-runner/src/wasmer_runner.rs @@ -6,7 +6,6 @@ use near_primitives::runtime::fees::RuntimeFeesConfig; use near_primitives::{ config::VMConfig, profile::ProfileData, types::CompiledContractCache, version::ProtocolVersion, }; -use near_vm_errors::FunctionCallError::WasmUnknownError; use near_vm_errors::{CompilationError, FunctionCallError, MethodResolveError, VMError, WasmTrap}; use near_vm_logic::types::PromiseResult; use near_vm_logic::{External, VMContext, VMLogic, VMLogicError, VMOutcome}; @@ -101,10 +100,9 @@ impl IntoVMError for wasmer_runtime::error::RuntimeError { // invoke returns false and doesn't fill error info what Singlepass BE doesn't. // Failed unwinder may happen in the case of deep recursion/stack overflow. // Also can be thrown on unreachable instruction, which is quite unfortunate. - InvokeError::FailedWithNoError => { - println!("FailedWithNoError"); - VMError::FunctionCallError(WasmUnknownError) - } + InvokeError::FailedWithNoError => VMError::FunctionCallError( + FunctionCallError::Nondeterministic("FailedWithNoError".to_string()), + ), // Indicates that a trap occurred that is not known to Wasmer. // As of 0.17.0, thrown only from Cranelift BE. InvokeError::UnknownTrap { address, signal } => { @@ -115,12 +113,15 @@ impl IntoVMError for wasmer_runtime::error::RuntimeError { ); } // A trap that Wasmer knows about occurred. - // As of 0.17.1, can be thrown on C signals caught, for example OOM. InvokeError::TrapCode { code, srcloc } => { VMError::FunctionCallError(match *code as u32 { 0 /* Unreachable */ => FunctionCallError::WasmTrap(WasmTrap::Unreachable), + 1 /* IncorrectCallIndirectSignature */ => FunctionCallError::WasmTrap(WasmTrap::IncorrectCallIndirectSignature), + 2 /* MemoryOutOfBounds */ => FunctionCallError::WasmTrap(WasmTrap::MemoryOutOfBounds), + 3 /* CallIndirectOOB */ => FunctionCallError::WasmTrap(WasmTrap::CallIndirectOOB), 4 /* IllegalArithmetic */ => FunctionCallError::WasmTrap(WasmTrap::IllegalArithmetic), - _ => FunctionCallError::Nondeterministic(format!("Wasmer trap {} at {}", code, srcloc)), + 5 /* MisalignedAtomicAccess */ => FunctionCallError::WasmTrap(WasmTrap::MisalignedAtomicAccess), + _ => FunctionCallError::WasmUnknownError(format!("Wasmer trap {} at {}", code, srcloc)), }) } // A trap occurred that Wasmer knows about but it had a trap code that diff --git a/runtime/near-vm-runner/src/wasmtime_runner.rs b/runtime/near-vm-runner/src/wasmtime_runner.rs index 36b16223dac..1a01a193888 100644 --- a/runtime/near-vm-runner/src/wasmtime_runner.rs +++ b/runtime/near-vm-runner/src/wasmtime_runner.rs @@ -89,19 +89,39 @@ pub mod wasmtime_runner { } } else { match trap.trap_code() { - Some(TrapCode::UnreachableCodeReached) => { - VMError::FunctionCallError(FunctionCallError::WasmTrap(WasmTrap::Unreachable)) - } Some(TrapCode::StackOverflow) => { VMError::FunctionCallError(FunctionCallError::WasmTrap(WasmTrap::StackOverflow)) } + Some(TrapCode::MemoryOutOfBounds) => VMError::FunctionCallError( + FunctionCallError::WasmTrap(WasmTrap::MemoryOutOfBounds), + ), + Some(TrapCode::TableOutOfBounds) => VMError::FunctionCallError( + FunctionCallError::WasmTrap(WasmTrap::MemoryOutOfBounds), + ), + Some(TrapCode::IndirectCallToNull) => VMError::FunctionCallError( + FunctionCallError::WasmTrap(WasmTrap::IndirectCallToNull), + ), + Some(TrapCode::BadSignature) => VMError::FunctionCallError( + FunctionCallError::WasmTrap(WasmTrap::IncorrectCallIndirectSignature), + ), + Some(TrapCode::IntegerOverflow) => VMError::FunctionCallError( + FunctionCallError::WasmTrap(WasmTrap::IllegalArithmetic), + ), Some(TrapCode::IntegerDivisionByZero) => VMError::FunctionCallError( FunctionCallError::WasmTrap(WasmTrap::IllegalArithmetic), ), + Some(TrapCode::BadConversionToInteger) => VMError::FunctionCallError( + FunctionCallError::WasmTrap(WasmTrap::IllegalArithmetic), + ), + Some(TrapCode::UnreachableCodeReached) => { + VMError::FunctionCallError(FunctionCallError::WasmTrap(WasmTrap::Unreachable)) + } Some(TrapCode::Interrupt) => VMError::FunctionCallError( FunctionCallError::Nondeterministic("interrupt".to_string()), ), - _ => VMError::FunctionCallError(FunctionCallError::WasmUnknownError), + _ => VMError::FunctionCallError(FunctionCallError::WasmUnknownError( + "unknown trap".to_string(), + )), } } } diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 6532268891a..d0dd905461f 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -200,7 +200,8 @@ pub(crate) fn action_function_call( | FunctionCallError::LinkError { msg: _ } | FunctionCallError::MethodResolveError(_) | FunctionCallError::WasmTrap(_) - | FunctionCallError::WasmUnknownError + // TODO: shall we abort on unknown errors also? + | FunctionCallError::WasmUnknownError(_) | FunctionCallError::HostError(_) | FunctionCallError::EvmError(_) => { result.result = Err(ActionErrorKind::FunctionCallError(err.to_string()).into());