Skip to main content

wasmer_runtime_core_near/
error.rs

1//! The error module contains the data structures and helper functions used to implement errors that
2//! are produced and returned from the wasmer runtime core.
3use crate::backend::ExceptionCode;
4use crate::types::{FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type};
5use core::borrow::Borrow;
6use std::any::Any;
7
8/// Aliases the standard `Result` type as `Result` within this module.
9pub type Result<T> = std::result::Result<T, Error>;
10/// Result of an attempt to compile the provided WebAssembly module into a `Module`.
11/// Aliases the standard `Result` with `CompileError` as the default error type.
12pub type CompileResult<T> = std::result::Result<T, CompileError>;
13/// Result of an attempt to link the provided WebAssembly instance.
14/// Aliases the standard `Result` with `Vec<LinkError>` as the default error type.
15pub type LinkResult<T> = std::result::Result<T, Vec<LinkError>>;
16/// Result of an attempt to run the provided WebAssembly instance.
17/// Aliases the standard `Result` with `RuntimeError` as the default error type.
18pub type RuntimeResult<T> = std::result::Result<T, RuntimeError>;
19/// Result of an attempt to call the provided WebAssembly instance.
20/// Aliases the standard `Result` with `CallError` as the default error type.
21pub type CallResult<T> = std::result::Result<T, CallError>;
22/// Result of an attempt to resolve a WebAssembly function by name.
23/// Aliases the standard `Result` with `ResolveError` as the default error type.
24pub type ResolveResult<T> = std::result::Result<T, ResolveError>;
25/// Result of an attempt to parse bytes into a WebAssembly module.
26/// Aliases the standard `Result` with `ParseError` as the default error type.
27pub type ParseResult<T> = std::result::Result<T, ParseError>;
28
29/// This is returned when the chosen compiler is unable to
30/// successfully compile the provided WebAssembly module into
31/// a `Module`.
32///
33/// Comparing two `CompileError`s always evaluates to false.
34#[derive(Debug, Clone)]
35pub enum CompileError {
36    /// A validation error containing an error message.
37    ValidationError {
38        /// An error message.
39        msg: String,
40    },
41    /// A internal error containing an error message.
42    InternalError {
43        /// An error message.
44        msg: String,
45    },
46}
47
48impl PartialEq for CompileError {
49    fn eq(&self, _other: &CompileError) -> bool {
50        false
51    }
52}
53
54impl std::fmt::Display for CompileError {
55    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
56        match self {
57            CompileError::InternalError { msg } => {
58                write!(f, "Internal compiler error: \"{}\"", msg)
59            }
60            CompileError::ValidationError { msg } => write!(f, "Validation error \"{}\"", msg),
61        }
62    }
63}
64
65impl std::error::Error for CompileError {}
66
67/// This is returned when the runtime is unable to
68/// correctly link the module with the provided imports.
69///
70/// Comparing two `LinkError`s always evaluates to false.
71#[derive(Debug, Clone)]
72pub enum LinkError {
73    /// The type of the provided import does not match the expected type.
74    IncorrectImportType {
75        /// Namespace.
76        namespace: String,
77        /// Name.
78        name: String,
79        /// Expected.
80        expected: String,
81        /// Found.
82        found: String,
83    },
84    /// The signature of the provided import does not match the expected signature.
85    IncorrectImportSignature {
86        /// Namespace.
87        namespace: String,
88        /// Name.
89        name: String,
90        /// Expected.
91        expected: FuncSig,
92        /// Found.
93        found: FuncSig,
94    },
95    /// An expected import was not provided.
96    ImportNotFound {
97        /// Namespace.
98        namespace: String,
99        /// Name.
100        name: String,
101    },
102    /// The memory descriptor provided does not match the expected descriptor.
103    IncorrectMemoryDescriptor {
104        /// Namespace.
105        namespace: String,
106        /// Name.
107        name: String,
108        /// Expected.
109        expected: MemoryDescriptor,
110        /// Found.
111        found: MemoryDescriptor,
112    },
113    /// The table descriptor provided does not match the expected descriptor.
114    IncorrectTableDescriptor {
115        /// Namespace.
116        namespace: String,
117        /// Name.
118        name: String,
119        /// Expected.
120        expected: TableDescriptor,
121        /// Found.
122        found: TableDescriptor,
123    },
124    /// The global descriptor provided does not match the expected descriptor.
125    IncorrectGlobalDescriptor {
126        /// Namespace.
127        namespace: String,
128        /// Name.
129        name: String,
130        /// Expected.
131        expected: GlobalDescriptor,
132        /// Found.
133        found: GlobalDescriptor,
134    },
135    /// A generic error with a message.
136    Generic {
137        /// Error message.
138        message: String,
139    },
140}
141
142impl PartialEq for LinkError {
143    fn eq(&self, _other: &LinkError) -> bool {
144        false
145    }
146}
147
148impl std::fmt::Display for LinkError {
149    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
150        match self {
151            LinkError::ImportNotFound { namespace, name } => write!(
152                f,
153                "Import not found, namespace: {}, name: {}",
154                namespace, name
155            ),
156            LinkError::IncorrectGlobalDescriptor {
157                namespace,
158                name,
159                expected,
160                found,
161            } => {
162                write!(f, "Incorrect global descriptor, namespace: {}, name: {}, expected global descriptor: {:?}, found global descriptor: {:?}", namespace, name, expected, found)
163            }
164            LinkError::IncorrectImportSignature {
165                namespace,
166                name,
167                expected,
168                found,
169            } => {
170                write!(f, "Incorrect import signature, namespace: {}, name: {}, expected signature: {}, found signature: {}", namespace, name, expected, found)
171            }
172            LinkError::IncorrectImportType {
173                namespace,
174                name,
175                expected,
176                found,
177            } => {
178                write!(f, "Incorrect import type, namespace: {}, name: {}, expected type: {}, found type: {}", namespace, name, expected, found)
179            }
180            LinkError::IncorrectMemoryDescriptor {
181                namespace,
182                name,
183                expected,
184                found,
185            } => {
186                write!(f, "Incorrect memory descriptor, namespace: {}, name: {}, expected memory descriptor: {:?}, found memory descriptor: {:?}", namespace, name, expected, found)
187            }
188            LinkError::IncorrectTableDescriptor {
189                namespace,
190                name,
191                expected,
192                found,
193            } => {
194                write!(f, "Incorrect table descriptor, namespace: {}, name: {}, expected table descriptor: {:?}, found table descriptor: {:?}", namespace, name, expected, found)
195            }
196            LinkError::Generic { message } => {
197                write!(f, "{}", message)
198            }
199        }
200    }
201}
202
203impl std::error::Error for LinkError {}
204
205/// An error that happened while invoking a Wasm function.
206#[derive(Debug)]
207pub enum InvokeError {
208    /// Indicates an exceptional circumstance such as a bug in Wasmer (please file an issue!)
209    /// or a hardware failure.
210    FailedWithNoError,
211    /// Indicates that a trap occurred that is not known to Wasmer.
212    UnknownTrap {
213        /// The address that the trap occurred at.
214        address: usize,
215        /// The name of the signal.
216        signal: &'static str,
217    },
218    /// A trap that Wasmer knows about occurred.
219    TrapCode {
220        /// The type of exception.
221        code: ExceptionCode,
222        /// Where in the Wasm file this trap orginated from.
223        srcloc: u32,
224    },
225    /// A trap occurred that Wasmer knows about but it had a trap code that
226    /// we weren't expecting or that we do not handle.  This error may be backend-specific.
227    UnknownTrapCode {
228        /// The trap code we saw but did not recognize.
229        trap_code: String,
230        /// Where in the Wasm file this trap orginated from.
231        srcloc: u32,
232    },
233    /// An "early trap" occurred.  TODO: document this properly
234    EarlyTrap(Box<RuntimeError>),
235    /// Indicates that a breakpoint was hit. The inner value is dependent upon
236    /// the middleware or backend being used.
237    Breakpoint(Box<RuntimeError>),
238}
239
240impl From<InvokeError> for RuntimeError {
241    fn from(other: InvokeError) -> RuntimeError {
242        match other {
243            InvokeError::EarlyTrap(re) | InvokeError::Breakpoint(re) => *re,
244            _ => RuntimeError::InvokeError(other),
245        }
246    }
247}
248
249impl std::error::Error for InvokeError {}
250
251impl std::fmt::Display for InvokeError {
252    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
253        match self {
254            InvokeError::FailedWithNoError => write!(f, "Invoke failed with no error"),
255            InvokeError::UnknownTrap { address, signal } => write!(
256                f,
257                "An unknown trap (`{}`) occured at 0x{:X}",
258                signal, address
259            ),
260            InvokeError::TrapCode { code, srcloc } => {
261                write!(f, "A `{}` trap was thrown at code offset {}", code, srcloc)
262            }
263            InvokeError::UnknownTrapCode { trap_code, srcloc } => write!(
264                f,
265                "A trap with an unknown trap code (`{}`) was thrown at code offset {}",
266                trap_code, srcloc
267            ),
268            InvokeError::EarlyTrap(rte) => write!(f, "Early trap: {}", rte),
269            InvokeError::Breakpoint(rte) => write!(f, "Breakpoint hit: {}", rte),
270        }
271    }
272}
273
274/// A `RuntimeError` is an error that describes why the attempt to fully execute
275/// some Wasm has failed.
276///
277/// These reasons vary from the Wasm trapping or otherwise failing directly to user
278/// controlled conditions such as metering running out of gas or a user host function
279/// returning a custom error type directly.
280#[derive(Debug)]
281pub enum RuntimeError {
282    /// An error relating to the invocation of a Wasm function.
283    InvokeError(InvokeError),
284    /// A metering triggered error value.
285    ///
286    /// An error of this type indicates that it was returned by the metering system.
287    Metering(Box<dyn Any + Send>),
288    /// A frozen state of Wasm used to pause and resume execution.  Not strictly an
289    /// "error", but this happens while executing and therefore is a `RuntimeError`
290    /// from the persective of the caller that expected the code to fully execute.
291    InstanceImage(Box<dyn Any + Send>),
292    /// A user triggered error value.
293    ///
294    /// An error returned from a host function.
295    User(Box<dyn Any + Send>),
296}
297
298impl PartialEq for RuntimeError {
299    fn eq(&self, _other: &RuntimeError) -> bool {
300        false
301    }
302}
303
304impl std::error::Error for RuntimeError {}
305
306impl std::fmt::Display for RuntimeError {
307    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
308        match self {
309            RuntimeError::InvokeError(ie) => write!(f, "Error when calling invoke: {}", ie),
310            RuntimeError::Metering(_) => write!(f, "unknown metering error type"),
311            RuntimeError::InstanceImage(_) => write!(
312                f,
313                "Execution interrupted by a suspend signal: instance image returned"
314            ),
315            RuntimeError::User(user_error) => {
316                write!(f, "User supplied error: ")?;
317                if let Some(s) = user_error.downcast_ref::<String>() {
318                    write!(f, "\"{}\"", s)
319                } else if let Some(s) = user_error.downcast_ref::<&str>() {
320                    write!(f, "\"{}\"", s)
321                } else if let Some(n) = user_error.downcast_ref::<i32>() {
322                    write!(f, "{}", n)
323                } else {
324                    write!(f, "unknown user error type")
325                }
326            }
327        }
328    }
329}
330
331/// This error type is produced by resolving a wasm function
332/// given its name.
333///
334/// Comparing two `ResolveError`s always evaluates to false.
335#[derive(Debug, Clone)]
336pub enum ResolveError {
337    /// Found signature did not match expected signature.
338    Signature {
339        /// Expected `FuncSig`.
340        expected: FuncSig,
341        /// Found type.
342        found: Vec<Type>,
343    },
344    /// Export not found.
345    ExportNotFound {
346        /// Name.
347        name: String,
348    },
349    /// Export found with the wrong type.
350    ExportWrongType {
351        /// Name.
352        name: String,
353    },
354}
355
356impl PartialEq for ResolveError {
357    fn eq(&self, _other: &ResolveError) -> bool {
358        false
359    }
360}
361
362impl std::fmt::Display for ResolveError {
363    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
364        match self {
365            ResolveError::ExportNotFound { name } => write!(f, "Export not found: {}", name),
366            ResolveError::ExportWrongType { name } => write!(f, "Export wrong type: {}", name),
367            ResolveError::Signature { expected, found } => {
368                let found = found
369                    .as_slice()
370                    .iter()
371                    .map(|p| p.to_string())
372                    .collect::<Vec<_>>()
373                    .join(", ");
374                let expected: &FuncSig = expected.borrow();
375                write!(
376                    f,
377                    "Parameters of type [{}] did not match signature {}",
378                    found, expected
379                )
380            }
381        }
382    }
383}
384
385impl std::error::Error for ResolveError {}
386
387/// This error type is produced by calling a wasm function
388/// exported from a module.
389///
390/// If the module traps in some way while running, this will
391/// be the `CallError::Runtime(RuntimeError)` variant.
392///
393/// Comparing two `CallError`s always evaluates to false.
394pub enum CallError {
395    /// An error occured resolving the functions name or types.
396    Resolve(ResolveError),
397    /// A runtime error occurred during the function call.
398    Runtime(RuntimeError),
399}
400
401impl PartialEq for CallError {
402    fn eq(&self, _other: &CallError) -> bool {
403        false
404    }
405}
406
407impl std::fmt::Display for CallError {
408    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
409        match self {
410            CallError::Resolve(resolve_error) => write!(f, "Call error: {}", resolve_error),
411            CallError::Runtime(runtime_error) => write!(f, "Call error: {}", runtime_error),
412        }
413    }
414}
415
416impl std::fmt::Debug for CallError {
417    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
418        match self {
419            CallError::Resolve(resolve_err) => write!(f, "ResolveError: {:?}", resolve_err),
420            CallError::Runtime(runtime_err) => write!(f, "RuntimeError: {:?}", runtime_err),
421        }
422    }
423}
424
425impl std::error::Error for CallError {}
426
427/// This error type is produced when creating something,
428/// like a `Memory` or a `Table`.
429#[derive(Debug, Clone)]
430pub enum CreationError {
431    /// Unable to create memory error.
432    UnableToCreateMemory,
433    /// Unable to create table error.
434    UnableToCreateTable,
435    /// Invalid descriptor error with message.
436    InvalidDescriptor(String),
437}
438
439impl PartialEq for CreationError {
440    fn eq(&self, _other: &CreationError) -> bool {
441        false
442    }
443}
444
445impl std::fmt::Display for CreationError {
446    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
447        match self {
448            CreationError::UnableToCreateMemory => write!(f, "Unable to Create Memory"),
449            CreationError::UnableToCreateTable => write!(f, "Unable to Create Table"),
450            CreationError::InvalidDescriptor(msg) => write!(
451                f,
452                "Unable to create because the supplied descriptor is invalid: \"{}\"",
453                msg
454            ),
455        }
456    }
457}
458
459impl std::error::Error for CreationError {}
460
461/// The amalgamation of all errors that can occur
462/// during the compilation, instantiation, or execution
463/// of a WebAssembly module.
464///
465/// Comparing two `Error`s always evaluates to false.
466#[derive(Debug)]
467pub enum Error {
468    /// Compile error.
469    CompileError(CompileError),
470    /// Link errors.
471    LinkError(Vec<LinkError>),
472    /// Runtime error.
473    RuntimeError(RuntimeError),
474    /// Resolve error.
475    ResolveError(ResolveError),
476    /// Call error.
477    CallError(CallError),
478    /// Creation error.
479    CreationError(CreationError),
480}
481
482impl PartialEq for Error {
483    fn eq(&self, _other: &Error) -> bool {
484        false
485    }
486}
487
488impl From<CompileError> for Error {
489    fn from(compile_err: CompileError) -> Self {
490        Error::CompileError(compile_err)
491    }
492}
493
494impl From<RuntimeError> for Error {
495    fn from(runtime_err: RuntimeError) -> Self {
496        Error::RuntimeError(runtime_err)
497    }
498}
499
500impl From<ResolveError> for Error {
501    fn from(resolve_err: ResolveError) -> Self {
502        Error::ResolveError(resolve_err)
503    }
504}
505
506impl From<CallError> for Error {
507    fn from(call_err: CallError) -> Self {
508        Error::CallError(call_err)
509    }
510}
511
512impl From<CreationError> for Error {
513    fn from(creation_err: CreationError) -> Self {
514        Error::CreationError(creation_err)
515    }
516}
517
518impl From<Vec<LinkError>> for Error {
519    fn from(link_errs: Vec<LinkError>) -> Self {
520        Error::LinkError(link_errs)
521    }
522}
523
524impl From<RuntimeError> for CallError {
525    fn from(runtime_err: RuntimeError) -> Self {
526        CallError::Runtime(runtime_err)
527    }
528}
529
530impl From<ResolveError> for CallError {
531    fn from(resolve_err: ResolveError) -> Self {
532        CallError::Resolve(resolve_err)
533    }
534}
535
536impl std::fmt::Display for Error {
537    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
538        match self {
539            Error::CompileError(err) => write!(f, "compile error: {}", err),
540            Error::LinkError(errs) => {
541                if errs.len() == 1 {
542                    write!(f, "link error: {}", errs[0])
543                } else {
544                    write!(f, "{} link errors:", errs.len())?;
545                    for (i, err) in errs.iter().enumerate() {
546                        write!(f, " ({} of {}) {}", i + 1, errs.len(), err)?;
547                    }
548                    Ok(())
549                }
550            }
551            Error::RuntimeError(err) => write!(f, "runtime error: {}", err),
552            Error::ResolveError(err) => write!(f, "resolve error: {}", err),
553            Error::CallError(err) => write!(f, "call error: {}", err),
554            Error::CreationError(err) => write!(f, "creation error: {}", err),
555        }
556    }
557}
558
559impl std::error::Error for Error {}
560
561/// An error occurred while growing a memory or table.
562#[derive(Debug)]
563pub enum GrowError {
564    /// Error growing memory.
565    MemoryGrowError,
566    /// Error growing table.
567    TableGrowError,
568    /// Max pages were exceeded.
569    ExceededMaxPages(PageError),
570    /// Max pages for memory were exceeded.
571    ExceededMaxPagesForMemory(usize, usize),
572    /// Error protecting memory.
573    CouldNotProtectMemory(MemoryProtectionError),
574    /// Error creating memory.
575    CouldNotCreateMemory(MemoryCreationError),
576}
577
578impl std::fmt::Display for GrowError {
579    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
580        match self {
581            GrowError::MemoryGrowError => write!(f, "Unable to grow memory"),
582            GrowError::TableGrowError => write!(f, "Unable to grow table"),
583            GrowError::ExceededMaxPages(e) => write!(f, "Grow Error: {}", e),
584            GrowError::ExceededMaxPagesForMemory(left, added) => write!(f, "Failed to add pages because would exceed maximum number of pages for the memory. Left: {}, Added: {}", left, added),
585            GrowError::CouldNotCreateMemory(e) => write!(f, "Grow Error: {}", e),
586            GrowError::CouldNotProtectMemory(e) => write!(f, "Grow Error: {}", e),
587        }
588    }
589}
590
591impl std::error::Error for GrowError {}
592
593/// A kind of page error.
594#[derive(Debug)]
595pub enum PageError {
596    // left, right, added
597    /// Max pages were exceeded error.
598    ExceededMaxPages(usize, usize, usize),
599}
600
601impl std::fmt::Display for PageError {
602    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
603        match self {
604            PageError::ExceededMaxPages(left, right, added) => write!(f, "Failed to add pages because would exceed maximum number of pages. Left: {}, Right: {}, Pages added: {}", left, right, added),
605        }
606    }
607}
608impl std::error::Error for PageError {}
609
610impl Into<GrowError> for PageError {
611    fn into(self) -> GrowError {
612        GrowError::ExceededMaxPages(self)
613    }
614}
615
616/// Error occured while creating memory.
617#[derive(Debug)]
618pub enum MemoryCreationError {
619    /// Allocation of virtual memory failed error.
620    VirtualMemoryAllocationFailed(usize, String),
621    /// Error creating memory from file.
622    CouldNotCreateMemoryFromFile(std::io::Error),
623}
624
625impl std::fmt::Display for MemoryCreationError {
626    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
627        match self {
628            MemoryCreationError::VirtualMemoryAllocationFailed(size, msg) => write!(
629                f,
630                "Allocation virtual memory with size {} failed. \nErrno message: {}",
631                size, msg
632            ),
633            MemoryCreationError::CouldNotCreateMemoryFromFile(e) => write!(f, "IO Error: {}", e),
634        }
635    }
636}
637impl std::error::Error for MemoryCreationError {}
638
639impl Into<GrowError> for MemoryCreationError {
640    fn into(self) -> GrowError {
641        GrowError::CouldNotCreateMemory(self)
642    }
643}
644
645impl From<std::io::Error> for MemoryCreationError {
646    fn from(io_error: std::io::Error) -> Self {
647        MemoryCreationError::CouldNotCreateMemoryFromFile(io_error)
648    }
649}
650
651/// Error protecting memory.
652#[derive(Debug)]
653pub enum MemoryProtectionError {
654    /// Protection failed error.
655    ProtectionFailed(usize, usize, String),
656}
657
658impl std::fmt::Display for MemoryProtectionError {
659    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
660        match self {
661            MemoryProtectionError::ProtectionFailed(start, size, msg) => write!(
662                f,
663                "Allocation virtual memory starting at {} with size {} failed. \nErrno message: {}",
664                start, size, msg
665            ),
666        }
667    }
668}
669impl std::error::Error for MemoryProtectionError {}
670
671impl Into<GrowError> for MemoryProtectionError {
672    fn into(self) -> GrowError {
673        GrowError::CouldNotProtectMemory(self)
674    }
675}
676
677/// Parse Error.
678#[derive(Debug)]
679pub enum ParseError {
680    /// Error reading binary.
681    BinaryReadError,
682}
683
684impl From<wasmparser::BinaryReaderError> for ParseError {
685    fn from(_: wasmparser::BinaryReaderError) -> Self {
686        ParseError::BinaryReadError
687    }
688}