diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index d1fd3c2de0..9d09860228 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -655,17 +655,23 @@ WASM_API_EXTERN own wasmtime_interrupt_handle_t *wasmtime_interrupt_handle_new(w * * Note that at this time when fuel is entirely consumed it will cause * wasm to trap. More usages of fuel are planned for the future. + * + * If fuel is not enabled within this store then an error is returned. If fuel + * is successfully added then NULL is returned. */ -WASM_API_EXTERN void wasmtime_add_fuel(wasm_store_t *store, uint64_t fuel); +WASM_API_EXTERN own wasmtime_error_t *wasmtime_store_add_fuel(wasm_store_t *store, uint64_t fuel); /** * \brief Returns the amount of fuel consumed by this store's execution so far. * * If fuel consumption is not enabled via #wasmtime_config_consume_fuel_set - * then this function will return 0. Also note that fuel, if enabled, must be - * originally configured via #wasmtime_add_fuel. + * then this function will return false. Otherwise true is returned and the + * fuel parameter is filled in with fuel consuemd so far. + * + * Also note that fuel, if enabled, must be originally configured via + * #wasmtime_store_add_fuel. */ -WASM_API_EXTERN uint64_t wasmtime_fuel_consumed(wasm_store_t *store); +WASM_API_EXTERN bool wasmtime_store_fuel_consumed(wasm_store_t *store, uint64_t *fuel); /** * \brief Requests that WebAssembly code running in the store attached to this diff --git a/crates/c-api/src/store.rs b/crates/c-api/src/store.rs index d1edb7a617..e303b0e382 100644 --- a/crates/c-api/src/store.rs +++ b/crates/c-api/src/store.rs @@ -1,4 +1,4 @@ -use crate::wasm_engine_t; +use crate::{wasm_engine_t, wasmtime_error_t}; use wasmtime::{InterruptHandle, Store}; #[repr(C)] @@ -44,11 +44,20 @@ pub extern "C" fn wasmtime_interrupt_handle_interrupt(handle: &wasmtime_interrup } #[no_mangle] -pub extern "C" fn wasmtime_add_fuel(store: &wasm_store_t, fuel: u64) { - store.store.add_fuel(fuel); +pub extern "C" fn wasmtime_store_add_fuel( + store: &wasm_store_t, + fuel: u64, +) -> Option> { + crate::handle_result(store.store.add_fuel(fuel), |()| {}) } #[no_mangle] -pub extern "C" fn wasmtime_fuel_consumed(store: &wasm_store_t) -> u64 { - store.store.fuel_consumed().unwrap_or(0) +pub extern "C" fn wasmtime_store_fuel_consumed(store: &wasm_store_t, fuel: &mut u64) -> bool { + match store.store.fuel_consumed() { + Some(amt) => { + *fuel = amt; + true + } + None => false, + } } diff --git a/crates/fuzzing/src/oracles.rs b/crates/fuzzing/src/oracles.rs index 2fc4532de4..35e5e66013 100644 --- a/crates/fuzzing/src/oracles.rs +++ b/crates/fuzzing/src/oracles.rs @@ -95,7 +95,7 @@ pub fn instantiate_with_config( let mut timeout_state = SignalOnDrop::default(); match timeout { - Timeout::Fuel(fuel) => store.add_fuel(fuel), + Timeout::Fuel(fuel) => store.add_fuel(fuel).unwrap(), // If a timeout is requested then we spawn a helper thread to wait for // the requested time and then send us a signal to get interrupted. We // also arrange for the thread's sleep to get interrupted if we return @@ -418,7 +418,7 @@ pub fn spectest(fuzz_config: crate::generators::Config, test: crate::generators: config.wasm_bulk_memory(false); let store = Store::new(&Engine::new(&config)); if fuzz_config.consume_fuel { - store.add_fuel(u64::max_value()); + store.add_fuel(u64::max_value()).unwrap(); } let mut wast_context = WastContext::new(store); wast_context.register_spectest().unwrap(); @@ -442,7 +442,7 @@ pub fn table_ops( let engine = Engine::new(&config); let store = Store::new(&engine); if fuzz_config.consume_fuel { - store.add_fuel(u64::max_value()); + store.add_fuel(u64::max_value()).unwrap(); } let wasm = ops.to_wasm_binary(); @@ -557,7 +557,7 @@ pub fn differential_wasmi_execution(wasm: &[u8], config: &crate::generators::Con let wasmtime_engine = Engine::new(&wasmtime_config); let wasmtime_store = Store::new(&wasmtime_engine); if config.consume_fuel { - wasmtime_store.add_fuel(u64::max_value()); + wasmtime_store.add_fuel(u64::max_value()).unwrap(); } let wasmtime_module = Module::new(&wasmtime_engine, &wasm).expect("Wasmtime can compile module"); diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs index 10564d79dd..a60d69a350 100644 --- a/crates/wasmtime/src/store.rs +++ b/crates/wasmtime/src/store.rs @@ -463,8 +463,11 @@ impl Store { /// /// This function will panic if the store's [`Config`](crate::Config) did /// not have fuel consumption enabled. - pub fn add_fuel(&self, fuel: u64) { - assert!(self.engine().config().tunables.consume_fuel); + pub fn add_fuel(&self, fuel: u64) -> Result<()> { + anyhow::ensure!( + self.engine().config().tunables.consume_fuel, + "fuel is not configured in this store" + ); // Fuel is stored as an i64, so we need to cast it. If the provided fuel // value overflows that just assume that i64::max will suffice. Wasm @@ -490,6 +493,8 @@ impl Store { *consumed_ptr = (*consumed_ptr + adj) - i64::max_value(); } } + + Ok(()) } } diff --git a/tests/all/fuel.rs b/tests/all/fuel.rs index b1b73bc6a8..92eb27a511 100644 --- a/tests/all/fuel.rs +++ b/tests/all/fuel.rs @@ -51,7 +51,7 @@ fn fuel_consumed(wasm: &[u8]) -> u64 { let engine = Engine::new(&config); let module = Module::new(&engine, wasm).unwrap(); let store = Store::new(&engine); - store.add_fuel(u64::max_value()); + store.add_fuel(u64::max_value()).unwrap(); drop(Instance::new(&store, &module, &[])); store.fuel_consumed().unwrap() } @@ -113,7 +113,7 @@ fn iloop() { let engine = Engine::new(&config); let module = Module::new(&engine, wat).unwrap(); let store = Store::new(&engine); - store.add_fuel(10_000); + store.add_fuel(10_000).unwrap(); let error = Instance::new(&store, &module, &[]).err().unwrap(); assert!( error.to_string().contains("all fuel consumed"),