Add basic epoch-interruption config to fuzzing options. (#3844)
Without async fuzzing, we won't be able to test the most interesting aspects of epoch interruption, namely the interrupt/update-deadline/resume flow. However, the "trap on epoch change" behavior works even for synchronous stores, so we can fuzz with this the same way we fuzz with the interrupt flag.
This commit is contained in:
@@ -253,6 +253,7 @@ pub struct WasmtimeConfig {
|
|||||||
canonicalize_nans: bool,
|
canonicalize_nans: bool,
|
||||||
interruptable: bool,
|
interruptable: bool,
|
||||||
pub(crate) consume_fuel: bool,
|
pub(crate) consume_fuel: bool,
|
||||||
|
epoch_interruption: bool,
|
||||||
/// The Wasmtime memory configuration to use.
|
/// The Wasmtime memory configuration to use.
|
||||||
pub memory_config: MemoryConfig,
|
pub memory_config: MemoryConfig,
|
||||||
force_jump_veneers: bool,
|
force_jump_veneers: bool,
|
||||||
@@ -441,6 +442,7 @@ impl Config {
|
|||||||
.cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime())
|
.cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime())
|
||||||
.interruptable(self.wasmtime.interruptable)
|
.interruptable(self.wasmtime.interruptable)
|
||||||
.consume_fuel(self.wasmtime.consume_fuel)
|
.consume_fuel(self.wasmtime.consume_fuel)
|
||||||
|
.epoch_interruption(self.wasmtime.epoch_interruption)
|
||||||
.memory_init_cow(self.wasmtime.memory_init_cow)
|
.memory_init_cow(self.wasmtime.memory_init_cow)
|
||||||
.memory_guaranteed_dense_image_size(std::cmp::min(
|
.memory_guaranteed_dense_image_size(std::cmp::min(
|
||||||
// Clamp this at 16MiB so we don't get huge in-memory
|
// Clamp this at 16MiB so we don't get huge in-memory
|
||||||
@@ -509,18 +511,44 @@ impl Config {
|
|||||||
if self.wasmtime.consume_fuel {
|
if self.wasmtime.consume_fuel {
|
||||||
store.add_fuel(u64::max_value()).unwrap();
|
store.add_fuel(u64::max_value()).unwrap();
|
||||||
}
|
}
|
||||||
|
if self.wasmtime.epoch_interruption {
|
||||||
|
// Without fuzzing of async execution, we can't test the
|
||||||
|
// "update deadline and continue" behavior, but we can at
|
||||||
|
// least test the codegen paths and checks with the
|
||||||
|
// trapping behavior, which works synchronously too. We'll
|
||||||
|
// set the deadline one epoch tick in the future; then
|
||||||
|
// this works exactly like an interrupt flag. We expect no
|
||||||
|
// traps/interrupts unless we bump the epoch, which we do
|
||||||
|
// as one particular Timeout mode (`Timeout::Epoch`).
|
||||||
|
store.epoch_deadline_trap();
|
||||||
|
store.set_epoch_deadline(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates an arbitrary method of timing out an instance, ensuring that
|
/// Generates an arbitrary method of timing out an instance, ensuring that
|
||||||
/// this configuration supports the returned timeout.
|
/// this configuration supports the returned timeout.
|
||||||
pub fn generate_timeout(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<Timeout> {
|
pub fn generate_timeout(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<Timeout> {
|
||||||
if u.arbitrary()? {
|
let time_duration = Duration::from_secs(20);
|
||||||
self.wasmtime.interruptable = true;
|
let timeout = u
|
||||||
Ok(Timeout::Time(Duration::from_secs(20)))
|
.choose(&[
|
||||||
} else {
|
Timeout::Time(time_duration),
|
||||||
self.wasmtime.consume_fuel = true;
|
Timeout::Fuel(100_000),
|
||||||
Ok(Timeout::Fuel(100_000))
|
Timeout::Epoch(time_duration),
|
||||||
|
])?
|
||||||
|
.clone();
|
||||||
|
match &timeout {
|
||||||
|
&Timeout::Time(..) => {
|
||||||
|
self.wasmtime.interruptable = true;
|
||||||
|
}
|
||||||
|
&Timeout::Fuel(..) => {
|
||||||
|
self.wasmtime.consume_fuel = true;
|
||||||
|
}
|
||||||
|
&Timeout::Epoch(..) => {
|
||||||
|
self.wasmtime.epoch_interruption = true;
|
||||||
|
}
|
||||||
|
&Timeout::None => unreachable!("Not an option given to choose()"),
|
||||||
}
|
}
|
||||||
|
Ok(timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compiles the `wasm` within the `engine` provided.
|
/// Compiles the `wasm` within the `engine` provided.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ impl ResourceLimiter for StoreLimits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Methods of timing out execution of a WebAssembly module
|
/// Methods of timing out execution of a WebAssembly module
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Timeout {
|
pub enum Timeout {
|
||||||
/// No timeout is used, it should be guaranteed via some other means that
|
/// No timeout is used, it should be guaranteed via some other means that
|
||||||
/// the input does not infinite loop.
|
/// the input does not infinite loop.
|
||||||
@@ -114,6 +114,9 @@ pub enum Timeout {
|
|||||||
/// Fuel-based timeouts are used where the specified fuel is all that the
|
/// Fuel-based timeouts are used where the specified fuel is all that the
|
||||||
/// provided wasm module is allowed to consume.
|
/// provided wasm module is allowed to consume.
|
||||||
Fuel(u64),
|
Fuel(u64),
|
||||||
|
/// An epoch-interruption-based timeout is used with a sleeping
|
||||||
|
/// thread bumping the epoch counter after the specified duration.
|
||||||
|
Epoch(Duration),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate the Wasm buffer, and implicitly fail if we have an unexpected
|
/// Instantiate the Wasm buffer, and implicitly fail if we have an unexpected
|
||||||
@@ -145,6 +148,12 @@ pub fn instantiate(wasm: &[u8], known_valid: bool, config: &generators::Config,
|
|||||||
let handle = store.interrupt_handle().unwrap();
|
let handle = store.interrupt_handle().unwrap();
|
||||||
timeout_state.spawn_timeout(timeout, move || handle.interrupt());
|
timeout_state.spawn_timeout(timeout, move || handle.interrupt());
|
||||||
}
|
}
|
||||||
|
// Similar to above, but we bump the epoch rather than set the
|
||||||
|
// interrupt flag.
|
||||||
|
Timeout::Epoch(timeout) => {
|
||||||
|
let engine = store.engine().clone();
|
||||||
|
timeout_state.spawn_timeout(timeout, move || engine.increment_epoch());
|
||||||
|
}
|
||||||
Timeout::None => {}
|
Timeout::None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user