Skip to main content

OutOfMemory

Struct OutOfMemory 

pub struct OutOfMemory { /* private fields */ }
Expand description

An out-of-memory (OOM) error.

This error is the sentinel for allocation failure due to memory exhaustion.

Constructing an Error from an OutOfMemory does not allocate.

Allocation failure inside any Error method that must allocate (e.g. Error::context) will propagate an OutOfMemory error.

§Out-of-Memory Handling in Wasmtime

Wasmtime performs out-of-memory (OOM) error handling on a best-effort basis. OOM handling does not have tier 1 support at this time and, therefore, while failure to handle OOM at some allocation site may be considered a bug, and might be a potential denial-of-service vector, it would not be considered a security vulnerability.1

§Where Wasmtime Attempts to Handle OOM

It is important to note that not all portions of Wasmtime attempt to handle out-of-memory errors. Notably, Wasmtime only ever attempts to handle OOM in the core runtime and never in the compiler. No attempt is made to handle allocation failure in the middle of compiling new Modules or Components from Wasm to machine code (or Pulley bytecode). However, Wasmtime will attempt to handle OOM when running pre-compiled Wasm code (loaded via Module::deserialize or Component::deserialize).

Wasmtime’s interfaces allow you to handle OOM in your own embedding’s WASI implementations and host APIs, but Wasmtime’s provided WASI implementations (e.g. wasmtime_wasi_http) will generally not attempt to handle OOM (as they often depend on third-party crates that do not attempt to handle OOM).

The API documentation for individual functions and methods that handle OOM should generally document this fact by listing OutOfMemory as one of the potential errors returned.

WhereHandles OOM?
CompilerNo
wasmtime::Module::newNo
wasmtime::Component::newNo
wasmtime::CodeBuilderNo
 Other compilation APIs…No
RuntimeYes
wasmtime::StoreYes
wasmtime::LinkerYes
wasmtime::Module::deserializeYes
wasmtime::InstanceYes
wasmtime::Func::callYes
 Component Model concurrency/async APIsNot yet
 Other instantiation and execution APIs…Yes
WASI Implementations and Host APIsDepends
wasmtime_wasiNo
wasmtime_wasi_httpNo
wasmtime_wasi_*No
 Your embedding’s APIsIf you implement OOM handling

If you encounter an unhandled OOM inside Wasmtime, and it is within a portion of code where it should be handled, then please file an issue.

§Handling More OOMs with Rust Nightly APIs

Rust’s standard library provides fallible allocation APIs, or the necessary building blocks for making our own fallible allocation APIs, for some of its types and collections. For example, it provides Vec::try_reserve which can be used to build a fallible version of Vec::push and fallible Box allocation can be built upon raw allocations from the global allocator and Box::from_raw.

However, the standard library does not provide these things for all the types and collections that Wasmtime uses. Some of these APIs are completely missing (such as a fallible version of std::collections::hash_map::VacantEntry::insert) and some APIs exist but are feature-gated on unstable, nightly-only Rust features. The most relevant API from this latter category is Arc::try_new, as Wasmtime’s runtime uses a number of Arcs under the covers.

If handling OOMs is important for your Wasmtime embedding, then you should compile Wasmtime from source using a Nightly Rust toolchain and with the RUSTFLAGS="--cfg arc_try_new" environment variable set. This unlocks Wasmtime’s internal usage of Arc::try_new, making more OOM handling at more allocation sites possible.


  1. Note that unconstrained guest-controlled resource usage is still considered a vulnerability. Wasmtime has tier 1 support for limiting guest resources, but not for handling OOMs within those limits. 

Implementations§

§

impl OutOfMemory

pub const fn new(requested_allocation_size: usize) -> OutOfMemory

Construct a new OutOfMemory error.

The requested_allocation_size argument should be the size (in bytes) of the associated allocation that was attempted and failed.

This operation does not allocate.

§Example
use alloc::alloc::{Layout, alloc};
use core::ptr::NonNull;

/// Attempt to allocate a block of memory from the global allocator,
/// returning an `OutOfMemory` error on failure.
fn try_global_alloc(layout: Layout) -> Result<NonNull<u8>, OutOfMemory> {
    if layout.size() == 0 {
        return Ok(NonNull::dangling());
    }

    // Safety: the layout's size is non-zero.
    let ptr = unsafe { alloc(layout) };

    if let Some(ptr) = NonNull::new(ptr) {
        Ok(ptr)
    } else {
        // The allocation failed, so return an `OutOfMemory` error,
        // passing the attempted allocation's size into the `OutOfMemory`
        // constructor.
        Err(OutOfMemory::new(layout.size()))
    }
}

pub fn requested_allocation_size(&self) -> usize

Get the size (in bytes) of the associated allocation that was attempted and which failed.

Very large allocation sizes (near isize::MAX and larger) may be capped to a maximum value.

§Example
let oom = OutOfMemory::new(8192);
assert_eq!(oom.requested_allocation_size(), 8192);

Trait Implementations§

§

impl Clone for OutOfMemory

§

fn clone(&self) -> OutOfMemory

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl Debug for OutOfMemory

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl Display for OutOfMemory

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl Error for OutOfMemory

§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
§

impl<T> TryFromIterator<T, OutOfMemory> for Box<[T]>

§

fn try_from_iter<I>(iter: I) -> Result<Box<[T]>, OutOfMemory>
where I: Iterator<Item = T>,

Creates an instance of this collection from the iter provided. Read more
§

impl Copy for OutOfMemory

§

impl Send for OutOfMemory

§

impl Sync for OutOfMemory

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.