metered_wasmi/
lib.rs

1//! # metered_wasmi
2//!
3//! This library allows WebAssembly modules to be loaded in binary format and their functions invoked.
4//!
5//! # Introduction
6//!
7//! WebAssembly (wasm) is a safe, portable and compact format that is designed for efficient execution.
8//!
9//! Wasm code is distributed in the form of modules that contains definitions of:
10//!
11//! - functions,
12//! - global variables,
13//! - linear memory instances and
14//! - tables.
15//!
16//! Each of these definitions can be imported and exported.
17//!
18//! In addition to these definitions, modules can define initialization data for their memory or tables. This initialization data can take the
19//! form of segments, copied to given offsets. They can also define a `start` function that is automatically executed when the module is loaded.
20//!
21//! ## Loading and Validation
22//!
23//! Before execution, a module must be validated. This process checks that the module is well-formed
24//! and makes only allowed operations.
25//!
26//! A valid module can't access memory outside its sandbox, can't cause stack underflows
27//! and can only call functions with correct signatures.
28//!
29//! ## Instantiation
30//!
31//! In order to execute code from a wasm module, it must be instantiated.
32//! Instantiation includes the following steps:
33//!
34//! 1. Creating an empty module instance.
35//! 2. Resolving the definition instances for each declared import in the module.
36//! 3. Instantiating definitions declared in the module (e.g. allocate global variables, allocate linear memory, etc.).
37//! 4. Initializing memory and table contents by copying segments into them.
38//! 5. Executing the `start` function, if any.
39//!
40//! After these steps, the module instance is ready to execute functions.
41//!
42//! ## Execution
43//!
44//! It only is allowed to call functions which are exported by the module.
45//! Functions can either return a result or trap (e.g. there can't be linking error in the middle of the function execution).
46//! This property is ensured by the validation process.
47//!
48//! # Examples
49//!
50//! ```rust
51//! extern crate metered_wasmi;
52//! extern crate wabt;
53//!
54//! use metered_wasmi::{ModuleInstance, ImportsBuilder, NopExternals, RuntimeValue};
55//!
56//! fn main() {
57//!     // Parse WAT (WebAssembly Text format) into wasm bytecode.
58//!     let wasm_binary: Vec<u8> =
59//!         wabt::wat2wasm(
60//!             r#"
61//!             (module
62//!                 (func (export "test") (result i32)
63//!                     i32.const 1337
64//!                 )
65//!             )
66//!             "#,
67//!         )
68//!         .expect("failed to parse wat");
69//!
70//!     // Load wasm binary and prepare it for instantiation.
71//!     let module = metered_wasmi::Module::from_buffer(&wasm_binary)
72//!         .expect("failed to load wasm");
73//!
74//!     // Instantiate a module with empty imports and
75//!     // assert that there is no `start` function.
76//!     let instance =
77//!         ModuleInstance::new(
78//!             &module,
79//!             &ImportsBuilder::default(),
80//!         )
81//!         .expect("failed to instantiate wasm module")
82//!         .assert_no_start();
83//!
84//!     // Finally, invoke the exported function "test" with no parameters
85//!     // and empty external function executor.
86//!     assert_eq!(
87//!         instance.invoke_export(
88//!             "test",
89//!             &[],
90//!             &mut NopExternals,
91//!         ).expect("failed to execute export"),
92//!         Some(RuntimeValue::I32(1337)),
93//!     );
94//! }
95//! ```
96
97#![warn(missing_docs)]
98#![cfg_attr(not(feature = "std"), no_std)]
99
100#[cfg(not(feature = "std"))]
101#[macro_use]
102extern crate alloc;
103#[cfg(feature = "std")]
104extern crate std as alloc;
105
106#[cfg(feature = "std")]
107#[macro_use]
108extern crate core;
109
110#[cfg(test)]
111extern crate assert_matches;
112#[cfg(test)]
113extern crate wabt;
114
115extern crate memory_units as memory_units_crate;
116extern crate parity_wasm;
117
118extern crate wasmi_validation as validation;
119
120use alloc::{
121    boxed::Box,
122    string::{String, ToString},
123    vec::Vec,
124};
125use core::fmt;
126#[cfg(feature = "std")]
127use std::error;
128
129#[cfg(not(feature = "std"))]
130extern crate libm;
131
132extern crate num_rational;
133extern crate num_traits;
134
135/// Error type which can be thrown by wasm code or by host environment.
136///
137/// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution.
138/// Traps can't be handled by WebAssembly code, but are reported to the embedder.
139#[derive(Debug)]
140pub struct Trap {
141    kind: TrapKind,
142}
143
144impl Trap {
145    /// Create new trap.
146    pub fn new(kind: TrapKind) -> Trap {
147        Trap { kind }
148    }
149
150    /// Returns kind of this trap.
151    pub fn kind(&self) -> &TrapKind {
152        &self.kind
153    }
154}
155
156impl fmt::Display for Trap {
157    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158        write!(f, "Trap: {:?}", self.kind)
159    }
160}
161
162#[cfg(feature = "std")]
163impl error::Error for Trap {
164    fn description(&self) -> &str {
165        "runtime trap"
166    }
167}
168
169/// Error type which can be thrown by wasm code or by host environment.
170///
171/// See [`Trap`] for details.
172///
173/// [`Trap`]: struct.Trap.html
174#[derive(Debug)]
175pub enum TrapKind {
176    /// Wasm code executed `unreachable` opcode.
177    ///
178    /// `unreachable` is a special opcode which always traps upon execution.
179    /// This opcode have a similar purpose as `ud2` in x86.
180    Unreachable,
181
182    /// Attempt to load or store at the address which
183    /// lies outside of bounds of the memory.
184    ///
185    /// Since addresses are interpreted as unsigned integers, out of bounds access
186    /// can't happen with negative addresses (i.e. they will always wrap).
187    MemoryAccessOutOfBounds,
188
189    /// Attempt to access table element at index which
190    /// lies outside of bounds.
191    ///
192    /// This typically can happen when `call_indirect` is executed
193    /// with index that lies out of bounds.
194    ///
195    /// Since indexes are interpreted as unsinged integers, out of bounds access
196    /// can't happen with negative indexes (i.e. they will always wrap).
197    TableAccessOutOfBounds,
198
199    /// Attempt to access table element which is uninitialized (i.e. `None`).
200    ///
201    /// This typically can happen when `call_indirect` is executed.
202    ElemUninitialized,
203
204    /// Attempt to divide by zero.
205    ///
206    /// This trap typically can happen if `div` or `rem` is executed with
207    /// zero as divider.
208    DivisionByZero,
209
210    /// Attempt to make a conversion to an int failed.
211    ///
212    /// This can happen when:
213    ///
214    /// - trying to do signed division (or get the remainder) -2<sup>N-1</sup> over -1. This is
215    ///   because the result +2<sup>N-1</sup> isn't representable as a N-bit signed integer.
216    /// - trying to truncate NaNs, infinity, or value for which the result is out of range into an integer.
217    InvalidConversionToInt,
218
219    /// Stack overflow.
220    ///
221    /// This is likely caused by some infinite or very deep recursion.
222    /// Extensive inlining might also be the cause of stack overflow.
223    StackOverflow,
224
225    /// Out Of Gas
226    ///
227    /// Function exceeded it's gas limit
228    OutOfGas,
229
230    /// Attempt to invoke a function with mismatching signature.
231    ///
232    /// This can happen if [`FuncInstance`] was invoked
233    /// with mismatching [signature][`Signature`].
234    ///
235    /// This can always happen with indirect calls. `call_indirect` instruction always
236    /// specifies the expected signature of function. If `call_indirect` is executed
237    /// with index that points on function with signature different that is
238    /// expected by this `call_indirect`, this trap is raised.
239    ///
240    /// [`Signature`]: struct.Signature.html
241    UnexpectedSignature,
242
243    /// Error specified by the host.
244    ///
245    /// Typically returned from an implementation of [`Externals`].
246    ///
247    /// [`Externals`]: trait.Externals.html
248    Host(Box<dyn host::HostError>),
249}
250
251impl TrapKind {
252    /// Whether this trap is specified by the host.
253    pub fn is_host(&self) -> bool {
254        match self {
255            &TrapKind::Host(_) => true,
256            _ => false,
257        }
258    }
259}
260
261/// Internal interpreter error.
262#[derive(Debug)]
263pub enum Error {
264    /// Module validation error. Might occur only at load time.
265    Validation(String),
266    /// Error while instantiating a module. Might occur when provided
267    /// with incorrect exports (i.e. linkage failure).
268    Instantiation(String),
269    /// Function-level error.
270    Function(String),
271    /// Table-level error.
272    Table(String),
273    /// Memory-level error.
274    Memory(String),
275    /// Global-level error.
276    Global(String),
277    /// Value-level error.
278    Value(String),
279    /// Trap.
280    Trap(Trap),
281    /// Custom embedder error.
282    Host(Box<dyn host::HostError>),
283}
284
285impl Error {
286    /// Returns [`HostError`] if this `Error` represents some host error.
287    ///
288    /// I.e. if this error have variant [`Host`] or [`Trap`][`Trap`] with [host][`TrapKind::Host`] error.
289    ///
290    /// [`HostError`]: trait.HostError.html
291    /// [`Host`]: enum.Error.html#variant.Host
292    /// [`Trap`]: enum.Error.html#variant.Trap
293    /// [`TrapKind::Host`]: enum.TrapKind.html#variant.Host
294    pub fn as_host_error(&self) -> Option<&dyn host::HostError> {
295        match *self {
296            Error::Host(ref host_err) => Some(&**host_err),
297            Error::Trap(ref trap) => match *trap.kind() {
298                TrapKind::Host(ref host_err) => Some(&**host_err),
299                _ => None,
300            },
301            _ => None,
302        }
303    }
304}
305
306impl Into<String> for Error {
307    fn into(self) -> String {
308        match self {
309            Error::Validation(s) => s,
310            Error::Instantiation(s) => s,
311            Error::Function(s) => s,
312            Error::Table(s) => s,
313            Error::Memory(s) => s,
314            Error::Global(s) => s,
315            Error::Value(s) => s,
316            Error::Trap(s) => format!("trap: {:?}", s),
317            Error::Host(e) => format!("user: {}", e),
318        }
319    }
320}
321
322impl fmt::Display for Error {
323    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
324        match *self {
325            Error::Validation(ref s) => write!(f, "Validation: {}", s),
326            Error::Instantiation(ref s) => write!(f, "Instantiation: {}", s),
327            Error::Function(ref s) => write!(f, "Function: {}", s),
328            Error::Table(ref s) => write!(f, "Table: {}", s),
329            Error::Memory(ref s) => write!(f, "Memory: {}", s),
330            Error::Global(ref s) => write!(f, "Global: {}", s),
331            Error::Value(ref s) => write!(f, "Value: {}", s),
332            Error::Trap(ref s) => write!(f, "Trap: {:?}", s),
333            Error::Host(ref e) => write!(f, "User: {}", e),
334        }
335    }
336}
337
338#[cfg(feature = "std")]
339impl error::Error for Error {
340    fn description(&self) -> &str {
341        match *self {
342            Error::Validation(ref s) => s,
343            Error::Instantiation(ref s) => s,
344            Error::Function(ref s) => s,
345            Error::Table(ref s) => s,
346            Error::Memory(ref s) => s,
347            Error::Global(ref s) => s,
348            Error::Value(ref s) => s,
349            Error::Trap(_) => "Trap",
350            Error::Host(_) => "Host error",
351        }
352    }
353}
354
355impl<U> From<U> for Error
356where
357    U: host::HostError + Sized,
358{
359    fn from(e: U) -> Self {
360        Error::Host(Box::new(e))
361    }
362}
363
364impl<U> From<U> for Trap
365where
366    U: host::HostError + Sized,
367{
368    fn from(e: U) -> Self {
369        Trap::new(TrapKind::Host(Box::new(e)))
370    }
371}
372
373impl From<Trap> for Error {
374    fn from(e: Trap) -> Error {
375        Error::Trap(e)
376    }
377}
378
379impl From<TrapKind> for Trap {
380    fn from(e: TrapKind) -> Trap {
381        Trap::new(e)
382    }
383}
384
385impl From<validation::Error> for Error {
386    fn from(e: validation::Error) -> Error {
387        Error::Validation(e.to_string())
388    }
389}
390
391mod func;
392mod global;
393mod host;
394mod imports;
395pub mod isa;
396mod memory;
397mod module;
398pub mod nan_preserving_float;
399mod prepare;
400mod runner;
401mod table;
402mod types;
403mod value;
404
405#[cfg(test)]
406mod tests;
407
408pub use self::func::{FuncInstance, FuncInvocation, FuncRef, ResumableError};
409pub use self::global::{GlobalInstance, GlobalRef};
410pub use self::host::{Externals, HostError, NopExternals, RuntimeArgs};
411pub use self::imports::{ImportResolver, ImportsBuilder, ModuleImportResolver};
412pub use self::memory::{MemoryInstance, MemoryRef, LINEAR_MEMORY_PAGE_SIZE};
413pub use self::module::{ExternVal, ModuleInstance, ModuleRef, NotStartedModuleRef};
414pub use self::runner::{
415    FunctionContext, StackRecycler, DEFAULT_CALL_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT,
416};
417pub use self::table::{TableInstance, TableRef};
418pub use self::types::{GlobalDescriptor, MemoryDescriptor, Signature, TableDescriptor, ValueType};
419pub use self::value::{Error as ValueError, FromRuntimeValue, LittleEndianConvert, RuntimeValue};
420
421/// WebAssembly-specific sizes and units.
422pub mod memory_units {
423    pub use memory_units_crate::wasm32::*;
424    pub use memory_units_crate::{size_of, ByteSize, Bytes, RoundUpTo};
425}
426
427/// Deserialized module prepared for instantiation.
428pub struct Module {
429    code_map: Vec<isa::Instructions>,
430    module: parity_wasm::elements::Module,
431}
432
433impl Module {
434    /// Create `Module` from `parity_wasm::elements::Module`.
435    ///
436    /// This function will load, validate and prepare a `parity_wasm`'s `Module`.
437    ///
438    /// # Errors
439    ///
440    /// Returns `Err` if provided `Module` is not valid.
441    ///
442    /// # Examples
443    ///
444    /// ```rust
445    /// extern crate parity_wasm;
446    /// extern crate metered_wasmi;
447    ///
448    /// use parity_wasm::builder;
449    /// use parity_wasm::elements;
450    ///
451    /// fn main() {
452    ///     let parity_module =
453    ///         builder::module()
454    ///             .function()
455    ///                 .signature().with_param(elements::ValueType::I32).build()
456    ///                 .body().build()
457    ///             .build()
458    ///         .build();
459    ///
460    ///     let module = metered_wasmi::Module::from_parity_wasm_module(parity_module)
461    ///         .expect("parity-wasm builder generated invalid module!");
462    ///
463    ///     // Instantiate `module`, etc...
464    /// }
465    /// ```
466    pub fn from_parity_wasm_module(module: parity_wasm::elements::Module) -> Result<Module, Error> {
467        let prepare::CompiledModule { code_map, module } = prepare::compile_module(module)?;
468
469        Ok(Module { code_map, module })
470    }
471
472    /// Fail if the module contains any floating-point operations
473    ///
474    /// # Errors
475    ///
476    /// Returns `Err` if provided `Module` is not valid.
477    ///
478    /// # Examples
479    ///
480    /// ```rust
481    /// # extern crate metered_wasmi;
482    /// # extern crate wabt;
483    ///
484    /// let wasm_binary: Vec<u8> =
485    ///     wabt::wat2wasm(
486    ///         r#"
487    ///         (module
488    ///          (func $add (param $lhs i32) (param $rhs i32) (result i32)
489    ///                get_local $lhs
490    ///                get_local $rhs
491    ///                i32.add))
492    ///         "#,
493    ///     )
494    ///     .expect("failed to parse wat");
495    ///
496    /// // Load wasm binary and prepare it for instantiation.
497    /// let module = metered_wasmi::Module::from_buffer(&wasm_binary).expect("Parsing failed");
498    /// assert!(module.deny_floating_point().is_ok());
499    ///
500    /// let wasm_binary: Vec<u8> =
501    ///     wabt::wat2wasm(
502    ///         r#"
503    ///         (module
504    ///          (func $add (param $lhs f32) (param $rhs f32) (result f32)
505    ///                get_local $lhs
506    ///                get_local $rhs
507    ///                f32.add))
508    ///         "#,
509    ///     )
510    ///     .expect("failed to parse wat");
511    ///
512    /// let module = metered_wasmi::Module::from_buffer(&wasm_binary).expect("Parsing failed");
513    /// assert!(module.deny_floating_point().is_err());
514    ///
515    /// let wasm_binary: Vec<u8> =
516    ///     wabt::wat2wasm(
517    ///         r#"
518    ///         (module
519    ///          (func $add (param $lhs f32) (param $rhs f32) (result f32)
520    ///                get_local $lhs))
521    ///         "#,
522    ///     )
523    ///     .expect("failed to parse wat");
524    ///
525    /// let module = metered_wasmi::Module::from_buffer(&wasm_binary).expect("Parsing failed");
526    /// assert!(module.deny_floating_point().is_err());
527    /// ```
528    pub fn deny_floating_point(&self) -> Result<(), Error> {
529        prepare::deny_floating_point(&self.module).map_err(Into::into)
530    }
531
532    /// Create `Module` from a given buffer.
533    ///
534    /// This function will deserialize wasm module from a given module,
535    /// validate and prepare it for instantiation.
536    ///
537    /// # Errors
538    ///
539    /// Returns `Err` if wasm binary in provided `buffer` is not valid wasm binary.
540    ///
541    /// # Examples
542    ///
543    /// ```rust
544    /// extern crate metered_wasmi;
545    ///
546    /// fn main() {
547    ///     let module =
548    ///         metered_wasmi::Module::from_buffer(
549    ///             // Minimal module:
550    ///             //   \0asm - magic
551    ///             //    0x01 - version (in little-endian)
552    ///             &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]
553    ///         ).expect("Failed to load minimal module");
554    ///
555    ///     // Instantiate `module`, etc...
556    /// }
557    /// ```
558    pub fn from_buffer<B: AsRef<[u8]>>(buffer: B) -> Result<Module, Error> {
559        let module = parity_wasm::elements::deserialize_buffer(buffer.as_ref())
560            .map_err(|e: parity_wasm::elements::Error| Error::Validation(e.to_string()))?;
561        Module::from_parity_wasm_module(module)
562    }
563
564    pub(crate) fn module(&self) -> &parity_wasm::elements::Module {
565        &self.module
566    }
567
568    pub(crate) fn code(&self) -> &Vec<isa::Instructions> {
569        &self.code_map
570    }
571}