Skip to main content

OomTest

Struct OomTest 

Source
pub struct OomTest { /* private fields */ }
Expand description

A test helper that checks that some code handles OOM correctly.

OomTest will only work correctly when OomTestAllocator is configured as the global allocator.

OomTest does not support reentrancy, so you cannot run an OomTest within an OomTest.

§Example

use std::time::Duration;
use wasmtime::Result;
use wasmtime_fuzzing::oom::{OomTest, OomTestAllocator};

#[global_allocator]
static GLOBAL_ALLOCATOR: OomTestAllocator = OomTestAllocator::new();

#[test]
fn my_oom_test() -> Result<()> {
    OomTest::new()
        .max_iters(1_000_000)
        .max_duration(Duration::from_secs(5))
        .allow_alloc_after_oom(true)
        .test(|| {
            todo!("insert code here that should handle OOM here...")
        })
}

Use test_with_reuse when you also want to check that some context is still usable after the OOM, e.g. that nothing was left half-registered in state that is shared with an Engine:

use wasmtime::Result;
use wasmtime_fuzzing::oom::OomTest;

#[test]
fn my_oom_reuse_test() -> Result<()> {
    OomTest::new().test_with_reuse(
        || todo!("create the context that is reused after the OOM..."),
        |context| todo!("insert code here that should handle OOM here..."),
        |context| todo!("check that `context` is still usable..."),
    )
}

Implementations§

Source§

impl OomTest

Source

pub fn new() -> Self

Create a new OOM test.

By default there is no iteration or time limit, tests will be executed until the pass (or fail).

Source

pub fn max_iters(&mut self, max_iters: u32) -> &mut Self

Configure the maximum number of times to run an OOM test.

Source

pub fn max_duration(&mut self, max_duration: Duration) -> &mut Self

Configure the maximum duration of time to run an OOM text.

Source

pub fn allow_alloc_after_oom(&mut self, allow: bool) -> &mut Self

Configure whether to allow allocation attempts after an OOM has already been injected.

The default is false.

Source

pub fn alloc_succeeds_after_oom(&mut self, succeeds: bool) -> &mut Self

Configure whether allocations after an OOM (assuming allow_alloc_after_oom(true)) will succeed or will always return null.

The default is false.

Source

pub fn allow_missed_oom_errors(&mut self, allow: bool) -> &mut Self

Configure whether to allow a test to pass if it does not return Err(OutOfMemory) when a synthetic OOM was injected (perhaps because it is exercising logic that is robust to OOM).

The default is false.

Source

pub fn seed(&mut self, seed: u64) -> &mut Self

Configure the seed for the RNG used in fuzz mode.

The default is 0.

Source

pub fn test(&self, test_func: impl Fn() -> Result<()>) -> Result<()>

Repeatedly run the given test function, injecting OOMs at different times and checking that it correctly handles them.

The test function should not use threads, or else allocations may not be tracked correctly and OOM injection may be incorrect.

The test function should return an Err(_) if and only if it encounters an OOM.

Returns early once the test function returns Ok(()) before an OOM has been injected.

Source

pub async fn test_async( &self, test_func: impl AsyncFn() -> Result<()>, ) -> Result<()>

The same as test but async.

Source

pub fn test_with_reuse<T>( &self, make_context: impl Fn() -> Result<T>, test_func: impl Fn(&mut T) -> Result<()>, post_oom_func: impl Fn(T) -> Result<()>, ) -> Result<()>

The same as test, but additionally exercising context that is reused after the OOM is triggered.

Each iteration runs three phases in sequence:

  1. make_context creates the context that is shared between the two phases that follow. It is called afresh every iteration, so that each iteration begins from identical state.

  2. test_func is the main OOM test, and is the only phase into which OOMs are injected. It is otherwise the same as the function given to test.

  3. post_oom_func checks that we recovered from the OOM correctly and that we can still interact with the context afterwards, e.g. that nothing was left half-registered in shared state, rather than properly cleaned up, when the OOM happened.

OOMs are never injected into make_context or post_oom_func and neither’s allocations are counted. An Err(_) returned from either is a test failure.

Source

pub async fn test_with_reuse_async<T>( &self, make_context: impl AsyncFn() -> Result<T>, test_func: impl AsyncFn(&mut T) -> Result<()>, post_oom_func: impl AsyncFn(T) -> Result<()>, ) -> Result<()>

The same as test_with_reuse but async.

Source

pub fn fuzz(&self, test_func: impl Fn() -> Result<()>) -> Result<()>

Similar to test but instead of exhaustively injecting OOMs on every allocation, randomly chooses which allocation to OOM each iteration.

Requires max_iters to be set.

Source

pub async fn fuzz_async( &self, test_func: impl AsyncFn() -> Result<()>, ) -> Result<()>

The same as fuzz but async.

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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more