Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/fuzzing/src/lib.rs
3063 views
1
//! Fuzzing infrastructure for Wasmtime.
2
3
#![deny(missing_docs)]
4
5
use std::pin::Pin;
6
use std::task::{Context, Poll, Waker};
7
8
pub use wasm_mutate;
9
pub use wasm_smith;
10
pub mod generators;
11
pub mod mutators;
12
pub mod oom;
13
pub mod oracles;
14
pub mod single_module_fuzzer;
15
16
/// One time start up initialization for fuzzing:
17
///
18
/// * Enables `env_logger`.
19
///
20
/// * Restricts `rayon` to a single thread in its thread pool, for more
21
/// deterministic executions.
22
///
23
/// If a fuzz target is taking raw input bytes from the fuzzer, it is fine to
24
/// call this function in the fuzz target's oracle or in the fuzz target
25
/// itself. However, if the fuzz target takes an `Arbitrary` type, and the
26
/// `Arbitrary` implementation is not derived and does interesting things, then
27
/// the `Arbitrary` implementation should call this function, since it runs
28
/// before the fuzz target itself.
29
pub fn init_fuzzing() {
30
static INIT: std::sync::Once = std::sync::Once::new();
31
32
INIT.call_once(|| {
33
let _ = env_logger::try_init();
34
});
35
}
36
37
/// One time start up initialization for fuzzing:
38
///
39
/// * Enables `env_logger`.
40
///
41
/// * Restricts `rayon` to a single thread in its thread pool, for more
42
/// deterministic executions.
43
///
44
/// If a fuzz target is taking raw input bytes from the fuzzer, it is fine to
45
/// call this function in the fuzz target's oracle or in the fuzz target
46
/// itself. However, if the fuzz target takes an `Arbitrary` type, and the
47
/// `Arbitrary` implementation is not derived and does interesting things, then
48
/// the `Arbitrary` implementation should call this function, since it runs
49
/// before the fuzz target itself.
50
pub fn misc_init() {
51
init_fuzzing();
52
oracles::component_async::init();
53
}
54
55
fn block_on<F: Future>(future: F) -> F::Output {
56
const MAX_POLLS: u32 = 100_000;
57
58
let mut f = Box::pin(future);
59
let mut cx = Context::from_waker(Waker::noop());
60
for _ in 0..MAX_POLLS {
61
match f.as_mut().poll(&mut cx) {
62
Poll::Ready(val) => return val,
63
Poll::Pending => {}
64
}
65
}
66
67
panic!("future didn't become ready")
68
}
69
70
/// Helper future to yield N times before resolving.
71
struct YieldN(u32);
72
73
impl Future for YieldN {
74
type Output = ();
75
76
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
77
if self.0 == 0 {
78
Poll::Ready(())
79
} else {
80
self.0 -= 1;
81
cx.waker().wake_by_ref();
82
Poll::Pending
83
}
84
}
85
}
86
87
#[cfg(test)]
88
mod test {
89
use arbitrary::{Arbitrary, Unstructured};
90
use rand::prelude::*;
91
92
pub fn gen_until_pass<T: for<'a> Arbitrary<'a>>(
93
mut f: impl FnMut(T, &mut Unstructured<'_>) -> wasmtime::Result<bool>,
94
) -> bool {
95
let mut rng = SmallRng::seed_from_u64(0);
96
let mut buf = vec![0; 2048];
97
let n = 3000;
98
for _ in 0..n {
99
rng.fill_bytes(&mut buf);
100
let mut u = Unstructured::new(&buf);
101
102
if let Ok(config) = u.arbitrary() {
103
if f(config, &mut u).unwrap() {
104
return true;
105
}
106
}
107
}
108
false
109
}
110
111
/// Runs `f` with random data until it returns `Ok(())` `iters` times.
112
pub fn test_n_times<T: for<'a> Arbitrary<'a>>(
113
iters: u32,
114
mut f: impl FnMut(T, &mut Unstructured<'_>) -> arbitrary::Result<()>,
115
) {
116
let mut to_test = 0..iters;
117
let ok = gen_until_pass(|a, b| {
118
if f(a, b).is_ok() {
119
Ok(to_test.next().is_none())
120
} else {
121
Ok(false)
122
}
123
});
124
assert!(ok);
125
}
126
}
127
128