wasmer_runtime_core_fl/
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!(f, "Import not found, namespace: {}, name: {}", namespace, name),
152            LinkError::IncorrectGlobalDescriptor {namespace, name,expected,found} => {
153                write!(f, "Incorrect global descriptor, namespace: {}, name: {}, expected global descriptor: {:?}, found global descriptor: {:?}", namespace, name, expected, found)
154            },
155            LinkError::IncorrectImportSignature{namespace, name,expected,found} => {
156                write!(f, "Incorrect import signature, namespace: {}, name: {}, expected signature: {}, found signature: {}", namespace, name, expected, found)
157            }
158            LinkError::IncorrectImportType{namespace, name,expected,found} => {
159                write!(f, "Incorrect import type, namespace: {}, name: {}, expected type: {}, found type: {}", namespace, name, expected, found)
160            }
161            LinkError::IncorrectMemoryDescriptor{namespace, name,expected,found} => {
162                write!(f, "Incorrect memory descriptor, namespace: {}, name: {}, expected memory descriptor: {:?}, found memory descriptor: {:?}", namespace, name, expected, found)
163            },
164            LinkError::IncorrectTableDescriptor{namespace, name,expected,found} => {
165                write!(f, "Incorrect table descriptor, namespace: {}, name: {}, expected table descriptor: {:?}, found table descriptor: {:?}", namespace, name, expected, found)
166            },
167            LinkError::Generic { message } => {
168                write!(f, "{}", message)
169            },
170        }
171    }
172}
173
174impl std::error::Error for LinkError {}
175
176/// An error that happened while invoking a Wasm function.
177#[derive(Debug)]
178pub enum InvokeError {
179    /// Indicates an exceptional circumstance such as a bug in Wasmer (please file an issue!)
180    /// or a hardware failure.
181    FailedWithNoError,
182    /// Indicates that a trap occurred that is not known to Wasmer.
183    UnknownTrap {
184        /// The address that the trap occurred at.
185        address: usize,
186        /// The name of the signal.
187        signal: &'static str,
188    },
189    /// A trap that Wasmer knows about occurred.
190    TrapCode {
191        /// The type of exception.
192        code: ExceptionCode,
193        /// Where in the Wasm file this trap orginated from.
194        srcloc: u32,
195    },
196    /// A trap occurred that Wasmer knows about but it had a trap code that
197    /// we weren't expecting or that we do not handle.  This error may be backend-specific.
198    UnknownTrapCode {
199        /// The trap code we saw but did not recognize.
200        trap_code: String,
201        /// Where in the Wasm file this trap orginated from.
202        srcloc: u32,
203    },
204    /// An "early trap" occurred.  TODO: document this properly
205    EarlyTrap(Box<RuntimeError>),
206    /// Indicates that a breakpoint was hit. The inner value is dependent upon
207    /// the middleware or backend being used.
208    Breakpoint(Box<RuntimeError>),
209}
210
211impl From<InvokeError> for RuntimeError {
212    fn from(other: InvokeError) -> RuntimeError {
213        match other {
214            InvokeError::EarlyTrap(re) | InvokeError::Breakpoint(re) => *re,
215            _ => RuntimeError::InvokeError(other),
216        }
217    }
218}
219
220impl std::error::Error for InvokeError {}
221
222impl std::fmt::Display for InvokeError {
223    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
224        match self {
225            InvokeError::FailedWithNoError => write!(f, "Invoke failed with no error"),
226            InvokeError::UnknownTrap { address, signal } => write!(
227                f,
228                "An unknown trap (`{}`) occured at 0x{:X}",
229                signal, address
230            ),
231            InvokeError::TrapCode { code, srcloc } => {
232                write!(f, "A `{}` trap was thrown at code offset {}", code, srcloc)
233            }
234            InvokeError::UnknownTrapCode { trap_code, srcloc } => write!(
235                f,
236                "A trap with an unknown trap code (`{}`) was thrown at code offset {}",
237                trap_code, srcloc
238            ),
239            InvokeError::EarlyTrap(rte) => write!(f, "Early trap: {}", rte),
240            InvokeError::Breakpoint(rte) => write!(f, "Breakpoint hit: {}", rte),
241        }
242    }
243}
244
245/// A `RuntimeError` is an error that describes why the attempt to fully execute
246/// some Wasm has failed.
247///
248/// These reasons vary from the Wasm trapping or otherwise failing directly to user
249/// controlled conditions such as metering running out of gas or a user host function
250/// returning a custom error type directly.
251#[derive(Debug)]
252pub enum RuntimeError {
253    /// An error relating to the invocation of a Wasm function.
254    InvokeError(InvokeError),
255    /// A metering triggered error value.
256    ///
257    /// An error of this type indicates that it was returned by the metering system.
258    Metering(Box<dyn Any + Send>),
259    /// A frozen state of Wasm used to pause and resume execution.  Not strictly an
260    /// "error", but this happens while executing and therefore is a `RuntimeError`
261    /// from the persective of the caller that expected the code to fully execute.
262    InstanceImage(Box<dyn Any + Send>),
263    /// A user triggered error value.
264    ///
265    /// An error returned from a host function.
266    User(Box<dyn Any + Send>),
267}
268
269impl PartialEq for RuntimeError {
270    fn eq(&self, _other: &RuntimeError) -> bool {
271        false
272    }
273}
274
275impl std::error::Error for RuntimeError {}
276
277impl std::fmt::Display for RuntimeError {
278    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
279        match self {
280            RuntimeError::InvokeError(ie) => write!(f, "Error when calling invoke: {}", ie),
281            RuntimeError::Metering(_) => write!(f, "unknown metering error type"),
282            RuntimeError::InstanceImage(_) => write!(
283                f,
284                "Execution interrupted by a suspend signal: instance image returned"
285            ),
286            RuntimeError::User(user_error) => {
287                write!(f, "User supplied error: ")?;
288                if let Some(s) = user_error.downcast_ref::<String>() {
289                    write!(f, "\"{}\"", s)
290                } else if let Some(s) = user_error.downcast_ref::<&str>() {
291                    write!(f, "\"{}\"", s)
292                } else if let Some(n) = user_error.downcast_ref::<i32>() {
293                    write!(f, "{}", n)
294                } else {
295                    write!(f, "unknown user error type")
296                }
297            }
298        }
299    }
300}
301
302/// This error type is produced by resolving a wasm function
303/// given its name.
304///
305/// Comparing two `ResolveError`s always evaluates to false.
306#[derive(Debug, Clone)]
307pub enum ResolveError {
308    /// Found signature did not match expected signature.
309    Signature {
310        /// Expected `FuncSig`.
311        expected: FuncSig,
312        /// Found type.
313        found: Vec<Type>,
314    },
315    /// Export not found.
316    ExportNotFound {
317        /// Name.
318        name: String,
319    },
320    /// Export found with the wrong type.
321    ExportWrongType {
322        /// Name.
323        name: String,
324    },
325}
326
327impl PartialEq for ResolveError {
328    fn eq(&self, _other: &ResolveError) -> bool {
329        false
330    }
331}
332
333impl std::fmt::Display for ResolveError {
334    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
335        match self {
336            ResolveError::ExportNotFound { name } => write!(f, "Export not found: {}", name),
337            ResolveError::ExportWrongType { name } => write!(f, "Export wrong type: {}", name),
338            ResolveError::Signature { expected, found } => {
339                let found = found
340                    .as_slice()
341                    .iter()
342                    .map(|p| p.to_string())
343                    .collect::<Vec<_>>()
344                    .join(", ");
345                let expected: &FuncSig = expected.borrow();
346                write!(
347                    f,
348                    "Parameters of type [{}] did not match signature {}",
349                    found, expected
350                )
351            }
352        }
353    }
354}
355
356impl std::error::Error for ResolveError {}
357
358/// This error type is produced by calling a wasm function
359/// exported from a module.
360///
361/// If the module traps in some way while running, this will
362/// be the `CallError::Runtime(RuntimeError)` variant.
363///
364/// Comparing two `CallError`s always evaluates to false.
365pub enum CallError {
366    /// An error occured resolving the functions name or types.
367    Resolve(ResolveError),
368    /// A runtime error occurred during the function call.
369    Runtime(RuntimeError),
370}
371
372impl PartialEq for CallError {
373    fn eq(&self, _other: &CallError) -> bool {
374        false
375    }
376}
377
378impl std::fmt::Display for CallError {
379    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
380        match self {
381            CallError::Resolve(resolve_error) => write!(f, "Call error: {}", resolve_error),
382            CallError::Runtime(runtime_error) => write!(f, "Call error: {}", runtime_error),
383        }
384    }
385}
386
387impl std::fmt::Debug for CallError {
388    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
389        match self {
390            CallError::Resolve(resolve_err) => write!(f, "ResolveError: {:?}", resolve_err),
391            CallError::Runtime(runtime_err) => write!(f, "RuntimeError: {:?}", runtime_err),
392        }
393    }
394}
395
396impl std::error::Error for CallError {}
397
398/// This error type is produced when creating something,
399/// like a `Memory` or a `Table`.
400#[derive(Debug, Clone)]
401pub enum CreationError {
402    /// Unable to create memory error.
403    UnableToCreateMemory,
404    /// Unable to create table error.
405    UnableToCreateTable,
406    /// Invalid descriptor error with message.
407    InvalidDescriptor(String),
408}
409
410impl PartialEq for CreationError {
411    fn eq(&self, _other: &CreationError) -> bool {
412        false
413    }
414}
415
416impl std::fmt::Display for CreationError {
417    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
418        match self {
419            CreationError::UnableToCreateMemory => write!(f, "Unable to Create Memory"),
420            CreationError::UnableToCreateTable => write!(f, "Unable to Create Table"),
421            CreationError::InvalidDescriptor(msg) => write!(
422                f,
423                "Unable to create because the supplied descriptor is invalid: \"{}\"",
424                msg
425            ),
426        }
427    }
428}
429
430impl std::error::Error for CreationError {}
431
432/// The amalgamation of all errors that can occur
433/// during the compilation, instantiation, or execution
434/// of a WebAssembly module.
435///
436/// Comparing two `Error`s always evaluates to false.
437#[derive(Debug)]
438pub enum Error {
439    /// Compile error.
440    CompileError(CompileError),
441    /// Link errors.
442    LinkError(Vec<LinkError>),
443    /// Runtime error.
444    RuntimeError(RuntimeError),
445    /// Resolve error.
446    ResolveError(ResolveError),
447    /// Call error.
448    CallError(CallError),
449    /// Creation error.
450    CreationError(CreationError),
451}
452
453impl PartialEq for Error {
454    fn eq(&self, _other: &Error) -> bool {
455        false
456    }
457}
458
459impl From<CompileError> for Error {
460    fn from(compile_err: CompileError) -> Self {
461        Error::CompileError(compile_err)
462    }
463}
464
465impl From<RuntimeError> for Error {
466    fn from(runtime_err: RuntimeError) -> Self {
467        Error::RuntimeError(runtime_err)
468    }
469}
470
471impl From<ResolveError> for Error {
472    fn from(resolve_err: ResolveError) -> Self {
473        Error::ResolveError(resolve_err)
474    }
475}
476
477impl From<CallError> for Error {
478    fn from(call_err: CallError) -> Self {
479        Error::CallError(call_err)
480    }
481}
482
483impl From<CreationError> for Error {
484    fn from(creation_err: CreationError) -> Self {
485        Error::CreationError(creation_err)
486    }
487}
488
489impl From<Vec<LinkError>> for Error {
490    fn from(link_errs: Vec<LinkError>) -> Self {
491        Error::LinkError(link_errs)
492    }
493}
494
495impl From<RuntimeError> for CallError {
496    fn from(runtime_err: RuntimeError) -> Self {
497        CallError::Runtime(runtime_err)
498    }
499}
500
501impl From<ResolveError> for CallError {
502    fn from(resolve_err: ResolveError) -> Self {
503        CallError::Resolve(resolve_err)
504    }
505}
506
507impl std::fmt::Display for Error {
508    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
509        match self {
510            Error::CompileError(err) => write!(f, "compile error: {}", err),
511            Error::LinkError(errs) => {
512                if errs.len() == 1 {
513                    write!(f, "link error: {}", errs[0])
514                } else {
515                    write!(f, "{} link errors:", errs.len())?;
516                    for (i, err) in errs.iter().enumerate() {
517                        write!(f, " ({} of {}) {}", i + 1, errs.len(), err)?;
518                    }
519                    Ok(())
520                }
521            }
522            Error::RuntimeError(err) => write!(f, "runtime error: {}", err),
523            Error::ResolveError(err) => write!(f, "resolve error: {}", err),
524            Error::CallError(err) => write!(f, "call error: {}", err),
525            Error::CreationError(err) => write!(f, "creation error: {}", err),
526        }
527    }
528}
529
530impl std::error::Error for Error {}
531
532/// An error occurred while growing a memory or table.
533#[derive(Debug)]
534pub enum GrowError {
535    /// Error growing memory.
536    MemoryGrowError,
537    /// Error growing table.
538    TableGrowError,
539    /// Max pages were exceeded.
540    ExceededMaxPages(PageError),
541    /// Max pages for memory were exceeded.
542    ExceededMaxPagesForMemory(usize, usize),
543    /// Error protecting memory.
544    CouldNotProtectMemory(MemoryProtectionError),
545    /// Error creating memory.
546    CouldNotCreateMemory(MemoryCreationError),
547}
548
549impl std::fmt::Display for GrowError {
550    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
551        match self {
552            GrowError::MemoryGrowError => write!(f, "Unable to grow memory"),
553            GrowError::TableGrowError => write!(f, "Unable to grow table"),
554            GrowError::ExceededMaxPages(e) => write!(f, "Grow Error: {}", e),
555            GrowError::ExceededMaxPagesForMemory(left, added) => write!(f, "Failed to add pages because would exceed maximum number of pages for the memory. Left: {}, Added: {}", left, added),
556            GrowError::CouldNotCreateMemory(e) => write!(f, "Grow Error: {}", e),
557            GrowError::CouldNotProtectMemory(e) => write!(f, "Grow Error: {}", e),
558        }
559    }
560}
561
562impl std::error::Error for GrowError {}
563
564/// A kind of page error.
565#[derive(Debug)]
566pub enum PageError {
567    // left, right, added
568    /// Max pages were exceeded error.
569    ExceededMaxPages(usize, usize, usize),
570}
571
572impl std::fmt::Display for PageError {
573    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
574        match self {
575            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),
576        }
577    }
578}
579impl std::error::Error for PageError {}
580
581impl Into<GrowError> for PageError {
582    fn into(self) -> GrowError {
583        GrowError::ExceededMaxPages(self)
584    }
585}
586
587/// Error occured while creating memory.
588#[derive(Debug)]
589pub enum MemoryCreationError {
590    /// Allocation of virtual memory failed error.
591    VirtualMemoryAllocationFailed(usize, String),
592    /// Error creating memory from file.
593    CouldNotCreateMemoryFromFile(std::io::Error),
594}
595
596impl std::fmt::Display for MemoryCreationError {
597    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
598        match self {
599            MemoryCreationError::VirtualMemoryAllocationFailed(size, msg) => write!(
600                f,
601                "Allocation virtual memory with size {} failed. \nErrno message: {}",
602                size, msg
603            ),
604            MemoryCreationError::CouldNotCreateMemoryFromFile(e) => write!(f, "IO Error: {}", e),
605        }
606    }
607}
608impl std::error::Error for MemoryCreationError {}
609
610impl Into<GrowError> for MemoryCreationError {
611    fn into(self) -> GrowError {
612        GrowError::CouldNotCreateMemory(self)
613    }
614}
615
616impl From<std::io::Error> for MemoryCreationError {
617    fn from(io_error: std::io::Error) -> Self {
618        MemoryCreationError::CouldNotCreateMemoryFromFile(io_error)
619    }
620}
621
622/// Error protecting memory.
623#[derive(Debug)]
624pub enum MemoryProtectionError {
625    /// Protection failed error.
626    ProtectionFailed(usize, usize, String),
627}
628
629impl std::fmt::Display for MemoryProtectionError {
630    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
631        match self {
632            MemoryProtectionError::ProtectionFailed(start, size, msg) => write!(
633                f,
634                "Allocation virtual memory starting at {} with size {} failed. \nErrno message: {}",
635                start, size, msg
636            ),
637        }
638    }
639}
640impl std::error::Error for MemoryProtectionError {}
641
642impl Into<GrowError> for MemoryProtectionError {
643    fn into(self) -> GrowError {
644        GrowError::CouldNotProtectMemory(self)
645    }
646}
647
648/// Parse Error.
649#[derive(Debug)]
650pub enum ParseError {
651    /// Error reading binary.
652    BinaryReadError,
653}
654
655impl From<wasmparser::BinaryReaderError> for ParseError {
656    fn from(_: wasmparser::BinaryReaderError) -> Self {
657        ParseError::BinaryReadError
658    }
659}