Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 159 additions & 11 deletions external/wasmi/patches/wasmi.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
From 383cea1996b4471735b87a55a77c5e0907a1da6b Mon Sep 17 00:00:00 2001
From: Peng Wang <[email protected]>
Date: Wed, 19 Nov 2025 18:24:35 -0500
Subject: [PATCH] wasm_store_new_with_memory_max_pages, fuel, build fix

---
.gitignore | 2 +
crates/c_api/CMakeLists.txt | 39 +++++++------
crates/c_api/Cargo.toml | 1 +
crates/c_api/include/wasm.h | 6 ++
crates/c_api/include/wasmi.h | 6 +-
crates/c_api/src/store.rs | 107 ++++++++++++++++++++++++++++++++---
6 files changed, 135 insertions(+), 26 deletions(-)

diff --git a/.gitignore b/.gitignore
index 08f2b95..e455195 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@ spec/target
**/fuzz/artifacts/
**/fuzz/crash-inputs/
**/fuzz/Cargo.lock
+.idea
+artifacts
\ No newline at end of file
diff --git a/crates/c_api/CMakeLists.txt b/crates/c_api/CMakeLists.txt
index b15c787a..2420bea2 100644
index b15c787..2420bea 100644
--- a/crates/c_api/CMakeLists.txt
+++ b/crates/c_api/CMakeLists.txt
@@ -43,6 +43,11 @@ endif()
Expand Down Expand Up @@ -56,26 +81,37 @@ index b15c787a..2420bea2 100644
endif()
endif()

diff --git a/crates/c_api/Cargo.toml b/crates/c_api/Cargo.toml
index 90c231e..369bfcf 100644
--- a/crates/c_api/Cargo.toml
+++ b/crates/c_api/Cargo.toml
@@ -22,6 +22,7 @@ wasmi_c_api_macros = { workspace = true }
name = "wasmi_c_api"
test = false
doctest = false
+crate-type = ["cdylib", "staticlib", "rlib"]

[features]
default = ["std"]
diff --git a/crates/c_api/include/wasm.h b/crates/c_api/include/wasm.h
index 5ee617ff..0199192d 100644
index 5ee617f..4226c29 100644
--- a/crates/c_api/include/wasm.h
+++ b/crates/c_api/include/wasm.h
@@ -146,6 +146,13 @@ WASM_DECLARE_OWN(store)
@@ -146,6 +146,12 @@ WASM_DECLARE_OWN(store)

WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*);

+WASM_API_EXTERN own wasm_store_t* wasm_store_new_with_memory_max_pages(wasm_engine_t*, uint32_t max_pages);
+
+// Store fuel functions (forward declarations)
+struct wasmi_error;
+
+WASM_API_EXTERN struct wasmi_error* wasm_store_get_fuel(const wasm_store_t*, uint64_t* fuel);
+WASM_API_EXTERN struct wasmi_error* wasm_store_set_fuel(wasm_store_t*, uint64_t fuel);
+//WASM_API_EXTERN void *wasm_store_get_data(const wasm_store_t*);
+//WASM_API_EXTERN void wasm_store_set_data(wasm_store_t*, void *data);

///////////////////////////////////////////////////////////////////////////////
// Type Representations
diff --git a/crates/c_api/include/wasmi.h b/crates/c_api/include/wasmi.h
index 2caffa37..0c0584ec 100644
index 2caffa3..0c0584e 100644
--- a/crates/c_api/include/wasmi.h
+++ b/crates/c_api/include/wasmi.h
@@ -10,7 +10,7 @@
Expand All @@ -101,10 +137,121 @@ index 2caffa37..0c0584ec 100644

#endif // WASMI_H
diff --git a/crates/c_api/src/store.rs b/crates/c_api/src/store.rs
index 56d4898f..543dbff8 100644
index 56d4898..1ba5337 100644
--- a/crates/c_api/src/store.rs
+++ b/crates/c_api/src/store.rs
@@ -175,3 +175,44 @@ pub extern "C" fn wasmi_context_set_fuel(
@@ -1,7 +1,7 @@
use crate::{wasm_engine_t, wasmi_error_t, ForeignData};
use alloc::{boxed::Box, sync::Arc};
use core::{cell::UnsafeCell, ffi};
-use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut};
+use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut, StoreLimits, StoreLimitsBuilder};

/// This representation of a `Store` is used to implement the `wasm.h` API (and
/// *not* the `wasmi.h` API!)
@@ -16,7 +16,7 @@ use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut};
/// least Wasmi's implementation).
#[derive(Clone)]
pub struct WasmStoreRef {
- inner: Arc<UnsafeCell<Store<()>>>,
+ inner: Arc<UnsafeCell<Store<StoreLimits>>>,
}

impl WasmStoreRef {
@@ -27,7 +27,7 @@ impl WasmStoreRef {
/// # Safety
///
/// It is the callers responsibility to provide a valid `self`.
- pub unsafe fn context(&self) -> StoreContext<'_, ()> {
+ pub unsafe fn context(&self) -> StoreContext<'_, StoreLimits> {
(*self.inner.get()).as_context()
}

@@ -38,7 +38,7 @@ impl WasmStoreRef {
/// # Safety
///
/// It is the callers responsibility to provide a valid `self`.
- pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, ()> {
+ pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, StoreLimits> {
(*self.inner.get()).as_context_mut()
}
}
@@ -56,17 +56,71 @@ pub struct wasm_store_t {

wasmi_c_api_macros::declare_own!(wasm_store_t);

-/// Creates a new [`Store<()>`](wasmi::Store) for the given `engine`.
+/// Creates a new [`Store<StoreLimits>`](wasmi::Store) for the given `engine`.
+///
+/// The store is created with no resource limits (original behavior).
+/// For memory-limited stores, use [`wasm_store_new_with_memory_max_pages`].
///
/// The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`].
///
-/// Wraps [`<wasmi::Store<()>>::new`](wasmi::Store::new).
+/// Wraps [`<wasmi::Store<StoreLimits>>::new`](wasmi::Store::new).
#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
#[allow(clippy::arc_with_non_send_sync)]
#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
let engine = &engine.inner;
- let store = Store::new(engine, ());
+
+ // Create store with no resource limits (original behavior)
+ let limits = StoreLimitsBuilder::new().build();
+ let store = Store::new(engine, limits);
+
+ Box::new(wasm_store_t {
+ inner: WasmStoreRef {
+ inner: Arc::new(UnsafeCell::new(store)),
+ },
+ })
+}
+
+/// Creates a new [`Store<StoreLimits>`](wasmi::Store) for the given `engine` with memory limits.
+///
+/// This function creates a store with resource limits suitable for blockchain smart contracts.
+/// The memory limit is enforced during WebAssembly execution.
+///
+/// If `max_pages` exceeds 1024 (64MB), this function will panic.
+///
+/// The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`].
+///
+/// Wraps [`<wasmi::Store<StoreLimits>>::new`](wasmi::Store::new).
+#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
+#[allow(clippy::arc_with_non_send_sync)]
+#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
+pub extern "C" fn wasm_store_new_with_memory_max_pages(
+ engine: &wasm_engine_t,
+ max_pages: u32,
+) -> Box<wasm_store_t> {
+ // Validate max_pages limit (64MB = 1024 pages)
+ if max_pages > 1024 {
+ panic!("max_pages ({}) exceeds maximum allowed value of 1024 pages (64MB)", max_pages);
+ }
+
+ // Convert pages to bytes (each page is 64KB)
+ let max_memory_bytes = (max_pages as usize) * (64 * 1024);
+
+ // Create store limits with blockchain-suitable defaults
+ let limits = StoreLimitsBuilder::new()
+ .memory_size(max_memory_bytes) // User-specified memory limit
+ .instances(1) // Single instance for blockchain
+ .tables(1) // Single table for blockchain
+ .memories(1) // Single memory for blockchain
+ .table_elements(64) // Limited table elements for blockchain
+ .trap_on_grow_failure(false) // Return -1 on growth failure instead of trapping
+ .build();
+
+ let mut store = Store::new(&engine.inner, limits);
+
+ // Install the resource limiter
+ store.limiter(|limits| limits);
+
Box::new(wasm_store_t {
inner: WasmStoreRef {
inner: Arc::new(UnsafeCell::new(store)),
@@ -175,3 +229,42 @@ pub extern "C" fn wasmi_context_set_fuel(
) -> Option<Box<wasmi_error_t>> {
crate::handle_result(store.set_fuel(fuel), |()| {})
}
Expand Down Expand Up @@ -144,8 +291,9 @@ index 56d4898f..543dbff8 100644
+ store: &mut wasm_store_t,
+ fuel: u64,
+) -> Option<Box<wasmi_error_t>> {
+
+ let mut context = unsafe { store.inner.context_mut() };
+ crate::handle_result(context.set_fuel(fuel), |()| {})
+}
+
--
2.37.3

15 changes: 7 additions & 8 deletions src/test/app/Wasm_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,9 @@ struct Wasm_test : public beast::unit_test::suite

auto const re = engine.run(wasm, "bellman_groth16_test");

if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 270'282'552, std::to_string(re->cost));
}
// the wasm code uses bulk-memory instructions that we disabled,
// so the module cannot be created.
BEAST_EXPECT(!re.has_value());
}

void
Expand Down Expand Up @@ -428,7 +426,7 @@ struct Wasm_test : public beast::unit_test::suite
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());

TestHostFunctionsSink nfs(env);
std::string funcName("recursive");
std::string funcName("finish");
auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 1'000'000'000);
BEAST_EXPECT(!re && re.error());
// std::cout << "bad case (deep recursion) result " << re.error()
Expand All @@ -450,7 +448,7 @@ struct Wasm_test : public beast::unit_test::suite
auto const s = sink.messages().str();
BEAST_EXPECT(
countSubstr(s, "WASMI Error: failure to call func") == 1);
BEAST_EXPECT(countSubstr(s, "exception: <recursive> failure") > 0);
BEAST_EXPECT(countSubstr(s, "exception: <finish> failure") > 0);
}

{
Expand Down Expand Up @@ -694,10 +692,11 @@ struct Wasm_test : public beast::unit_test::suite
testHFCost();

testEscrowWasmDN();

testFloat();

testCodecovWasm();
// testDisabledFloat();
testDisabledFloat();

// perfTest();
}
Expand Down
Loading
Loading