Repository: bytecodealliance/wasmtime
Pull request #2648 (2021-02-09 15:18:02)

Tweak C API for fuel
* Ensure `store` is in the function names
* Don't abort the process on `add_fuel` when fuel isn't configured
* Allow learning about failure in both `add_fuel` and `fuel_consumed`



Patch:
diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h
index d1fd3c2de..9d0986022 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 d1edb7a61..e303b0e38 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<Box<wasmtime_error_t>> {
+    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 2fc4532de..35e5e6601 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 10564d79d..a60d69a35 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(())
     }
 }
 


Test patch:
diff --git a/tests/all/fuel.rs b/tests/all/fuel.rs
index b1b73bc6a..92eb27a51 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"),