|
| 1 | +diff --git a/crates/c_api/CMakeLists.txt b/crates/c_api/CMakeLists.txt |
| 2 | +index b15c787..54eaed2 100644 |
| 3 | +--- a/crates/c_api/CMakeLists.txt |
| 4 | ++++ b/crates/c_api/CMakeLists.txt |
| 5 | +@@ -6,6 +6,8 @@ option(BUILD_SHARED_LIBS "Build using shared libraries" OFF) |
| 6 | + option(WASMI_ALWAYS_BUILD "If cmake should always invoke cargo to build Wasmi" ON) |
| 7 | + set(WASMI_TARGET "" CACHE STRING "Rust target to build for") |
| 8 | + |
| 9 | ++add_compile_definitions(COMPILING_WASM_RUNTIME_API=1) |
| 10 | ++ |
| 11 | + if(NOT WASMI_TARGET) |
| 12 | + execute_process( |
| 13 | + COMMAND rustc -vV |
| 14 | +@@ -43,6 +45,10 @@ endif() |
| 15 | + list(TRANSFORM WASMI_SHARED_FILES PREPEND ${WASMI_TARGET_DIR}/) |
| 16 | + list(TRANSFORM WASMI_STATIC_FILES PREPEND ${WASMI_TARGET_DIR}/) |
| 17 | + |
| 18 | ++if(NOT BUILD_SHARED_LIBS) |
| 19 | ++ set(WASMI_SHARED_FILES) |
| 20 | ++endif() |
| 21 | ++ |
| 22 | + # Instructions on how to build and install the Wasmi Rust crate. |
| 23 | + find_program(WASMI_CARGO_BINARY cargo REQUIRED) |
| 24 | + include(ExternalProject) |
| 25 | +@@ -79,7 +85,6 @@ else() |
| 26 | + target_link_libraries(wasmi INTERFACE ${WASMI_STATIC_FILES}) |
| 27 | + |
| 28 | + if(WASMI_TARGET MATCHES "windows") |
| 29 | +- target_compile_options(wasmi INTERFACE -DWASM_API_EXTERN= -DWASI_API_EXTERN=) |
| 30 | + target_link_libraries(wasmi INTERFACE ws2_32 advapi32 userenv ntdll shell32 ole32 bcrypt) |
| 31 | + elseif(NOT WASMI_TARGET MATCHES "darwin") |
| 32 | + target_link_libraries(wasmi INTERFACE pthread dl m) |
| 33 | +@@ -112,6 +117,7 @@ install( |
| 34 | + DESTINATION ${CMAKE_INSTALL_LIBDIR} |
| 35 | + ) |
| 36 | + |
| 37 | ++if(BUILD_SHARED_LIBS) |
| 38 | + if(WASMI_TARGET MATCHES "darwin") |
| 39 | + set(INSTALLED_LIB "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libwasmi.dylib") |
| 40 | + install( |
| 41 | +@@ -131,6 +137,7 @@ if(WASMI_TARGET MATCHES "darwin") |
| 42 | + install(CODE "execute_process(COMMAND ${install_name_tool_cmd})") |
| 43 | + endif() |
| 44 | + endif() |
| 45 | ++endif() |
| 46 | + |
| 47 | + # Documentation Generation via Doxygen: |
| 48 | + set(DOXYGEN_CONF_IN ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.conf.in) |
| 49 | +@@ -141,19 +148,3 @@ add_custom_target(doc |
| 50 | + DEPENDS ${WASMI_GENERATED_CONF_H} ${DOXYGEN_CONF_OUT} |
| 51 | + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |
| 52 | + ) |
| 53 | +- |
| 54 | +-# C-Header Formatting via clang-format: |
| 55 | +-find_program(CLANG_FORMAT clang-format REQUIRED) |
| 56 | +-file(GLOB_RECURSE HEADER_FILES |
| 57 | +- ${CMAKE_CURRENT_SOURCE_DIR}/include/wasmi.h |
| 58 | +- ${CMAKE_CURRENT_SOURCE_DIR}/include/wasmi/*.h |
| 59 | +- ${CMAKE_CURRENT_SOURCE_DIR}/include/wasmi/*.hh |
| 60 | +-) |
| 61 | +-add_custom_target(check-format |
| 62 | +- COMMAND ${CLANG_FORMAT} -style=llvm -Werror --dry-run ${HEADER_FILES} |
| 63 | +- COMMENT "clang-format: Check formatting for Wasmi C-API header files" |
| 64 | +-) |
| 65 | +-add_custom_target(format |
| 66 | +- COMMAND ${CLANG_FORMAT} -style=llvm -i ${HEADER_FILES} |
| 67 | +- COMMENT "clang-format: Apply formatting rules for Wasmi C-API header files" |
| 68 | +-) |
| 69 | +diff --git a/crates/c_api/include/wasm.h b/crates/c_api/include/wasm.h |
| 70 | +index 5ee617f..a76f10e 100644 |
| 71 | +--- a/crates/c_api/include/wasm.h |
| 72 | ++++ b/crates/c_api/include/wasm.h |
| 73 | +@@ -13,11 +13,17 @@ |
| 74 | + #include <assert.h> |
| 75 | + |
| 76 | + #ifndef WASM_API_EXTERN |
| 77 | +-#if defined(_WIN32) && !defined(__MINGW32__) && !defined(LIBWASM_STATIC) |
| 78 | ++#if defined(_MSC_BUILD) |
| 79 | ++#if defined(COMPILING_WASM_RUNTIME_API) |
| 80 | ++#define WASM_API_EXTERN __declspec(dllexport) |
| 81 | ++#elif defined(_DLL) |
| 82 | + #define WASM_API_EXTERN __declspec(dllimport) |
| 83 | + #else |
| 84 | + #define WASM_API_EXTERN |
| 85 | + #endif |
| 86 | ++#else |
| 87 | ++#define WASM_API_EXTERN |
| 88 | ++#endif |
| 89 | + #endif |
| 90 | + |
| 91 | + #ifdef __cplusplus |
| 92 | +@@ -145,7 +151,13 @@ WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t |
| 93 | + WASM_DECLARE_OWN(store) |
| 94 | + |
| 95 | + WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*); |
| 96 | ++WASM_API_EXTERN own wasm_store_t* wasm_store_new_with_memory_max_pages(wasm_engine_t*, uint32_t max_pages); |
| 97 | ++ |
| 98 | ++// Store fuel functions (forward declarations) |
| 99 | ++struct wasmi_error; |
| 100 | + |
| 101 | ++WASM_API_EXTERN struct wasmi_error* wasm_store_get_fuel(const wasm_store_t*, uint64_t* fuel); |
| 102 | ++WASM_API_EXTERN struct wasmi_error* wasm_store_set_fuel(wasm_store_t*, uint64_t fuel); |
| 103 | + |
| 104 | + /////////////////////////////////////////////////////////////////////////////// |
| 105 | + // Type Representations |
| 106 | +diff --git a/crates/c_api/include/wasmi.h b/crates/c_api/include/wasmi.h |
| 107 | +index 2caffa3..0c0584e 100644 |
| 108 | +--- a/crates/c_api/include/wasmi.h |
| 109 | ++++ b/crates/c_api/include/wasmi.h |
| 110 | +@@ -10,7 +10,7 @@ |
| 111 | + /** |
| 112 | + * \brief Wasmi version string. |
| 113 | + */ |
| 114 | +-#define WASMI_VERSION "0.35.0" |
| 115 | ++#define WASMI_VERSION "0.42.1" |
| 116 | + /** |
| 117 | + * \brief Wasmi major version number. |
| 118 | + */ |
| 119 | +@@ -18,10 +18,10 @@ |
| 120 | + /** |
| 121 | + * \brief Wasmi minor version number. |
| 122 | + */ |
| 123 | +-#define WASMI_VERSION_MINOR 35 |
| 124 | ++#define WASMI_VERSION_MINOR 42 |
| 125 | + /** |
| 126 | + * \brief Wasmi patch version number. |
| 127 | + */ |
| 128 | +-#define WASMI_VERSION_PATCH 0 |
| 129 | ++#define WASMI_VERSION_PATCH 1 |
| 130 | + |
| 131 | + #endif // WASMI_H |
| 132 | +diff --git a/crates/c_api/src/store.rs b/crates/c_api/src/store.rs |
| 133 | +index 56d4898..9abda8e 100644 |
| 134 | +--- a/crates/c_api/src/store.rs |
| 135 | ++++ b/crates/c_api/src/store.rs |
| 136 | +@@ -1,7 +1,7 @@ |
| 137 | + use crate::{wasm_engine_t, wasmi_error_t, ForeignData}; |
| 138 | + use alloc::{boxed::Box, sync::Arc}; |
| 139 | + use core::{cell::UnsafeCell, ffi}; |
| 140 | +-use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut}; |
| 141 | ++use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut, StoreLimits, StoreLimitsBuilder}; |
| 142 | + |
| 143 | + /// This representation of a `Store` is used to implement the `wasm.h` API (and |
| 144 | + /// *not* the `wasmi.h` API!) |
| 145 | +@@ -16,7 +16,7 @@ use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut}; |
| 146 | + /// least Wasmi's implementation). |
| 147 | + #[derive(Clone)] |
| 148 | + pub struct WasmStoreRef { |
| 149 | +- inner: Arc<UnsafeCell<Store<()>>>, |
| 150 | ++ inner: Arc<UnsafeCell<Store<StoreLimits>>>, |
| 151 | + } |
| 152 | + |
| 153 | + impl WasmStoreRef { |
| 154 | +@@ -27,7 +27,7 @@ impl WasmStoreRef { |
| 155 | + /// # Safety |
| 156 | + /// |
| 157 | + /// It is the callers responsibility to provide a valid `self`. |
| 158 | +- pub unsafe fn context(&self) -> StoreContext<'_, ()> { |
| 159 | ++ pub unsafe fn context(&self) -> StoreContext<'_, StoreLimits> { |
| 160 | + (*self.inner.get()).as_context() |
| 161 | + } |
| 162 | + |
| 163 | +@@ -38,7 +38,7 @@ impl WasmStoreRef { |
| 164 | + /// # Safety |
| 165 | + /// |
| 166 | + /// It is the callers responsibility to provide a valid `self`. |
| 167 | +- pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, ()> { |
| 168 | ++ pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, StoreLimits> { |
| 169 | + (*self.inner.get()).as_context_mut() |
| 170 | + } |
| 171 | + } |
| 172 | +@@ -56,17 +56,71 @@ pub struct wasm_store_t { |
| 173 | + |
| 174 | + wasmi_c_api_macros::declare_own!(wasm_store_t); |
| 175 | + |
| 176 | +-/// Creates a new [`Store<()>`](wasmi::Store) for the given `engine`. |
| 177 | ++/// Creates a new [`Store<StoreLimits>`](wasmi::Store) for the given `engine`. |
| 178 | ++/// |
| 179 | ++/// The store is created with no resource limits (original behavior). |
| 180 | ++/// For memory-limited stores, use [`wasm_store_new_with_memory_max_pages`]. |
| 181 | + /// |
| 182 | + /// The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`]. |
| 183 | + /// |
| 184 | +-/// Wraps [`<wasmi::Store<()>>::new`](wasmi::Store::new). |
| 185 | ++/// Wraps [`<wasmi::Store<StoreLimits>>::new`](wasmi::Store::new). |
| 186 | + #[cfg_attr(not(feature = "prefix-symbols"), no_mangle)] |
| 187 | + #[allow(clippy::arc_with_non_send_sync)] |
| 188 | + #[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] |
| 189 | + pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> { |
| 190 | + let engine = &engine.inner; |
| 191 | +- let store = Store::new(engine, ()); |
| 192 | ++ |
| 193 | ++ // Create store with no resource limits (original behavior) |
| 194 | ++ let limits = StoreLimitsBuilder::new().build(); |
| 195 | ++ let store = Store::new(engine, limits); |
| 196 | ++ |
| 197 | ++ Box::new(wasm_store_t { |
| 198 | ++ inner: WasmStoreRef { |
| 199 | ++ inner: Arc::new(UnsafeCell::new(store)), |
| 200 | ++ }, |
| 201 | ++ }) |
| 202 | ++} |
| 203 | ++ |
| 204 | ++/// Creates a new [`Store<StoreLimits>`](wasmi::Store) for the given `engine` with memory limits. |
| 205 | ++/// |
| 206 | ++/// This function creates a store with resource limits suitable for blockchain smart contracts. |
| 207 | ++/// The memory limit is enforced during WebAssembly execution. |
| 208 | ++/// |
| 209 | ++/// If `max_pages` exceeds 1024 (64MB), this function will panic. |
| 210 | ++/// |
| 211 | ++/// The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`]. |
| 212 | ++/// |
| 213 | ++/// Wraps [`<wasmi::Store<StoreLimits>>::new`](wasmi::Store::new). |
| 214 | ++#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)] |
| 215 | ++#[allow(clippy::arc_with_non_send_sync)] |
| 216 | ++#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] |
| 217 | ++pub extern "C" fn wasm_store_new_with_memory_max_pages( |
| 218 | ++ engine: &wasm_engine_t, |
| 219 | ++ max_pages: u32, |
| 220 | ++) -> Box<wasm_store_t> { |
| 221 | ++ // Validate max_pages limit (64MB = 1024 pages) |
| 222 | ++ if max_pages > 1024 { |
| 223 | ++ panic!("max_pages ({}) exceeds maximum allowed value of 1024 pages (64MB)", max_pages); |
| 224 | ++ } |
| 225 | ++ |
| 226 | ++ // Convert pages to bytes (each page is 64KB) |
| 227 | ++ let max_memory_bytes = (max_pages as usize) * (64 * 1024); |
| 228 | ++ |
| 229 | ++ // Create store limits with blockchain-suitable defaults |
| 230 | ++ let limits = StoreLimitsBuilder::new() |
| 231 | ++ .memory_size(max_memory_bytes) // User-specified memory limit |
| 232 | ++ .instances(1) // Single instance for blockchain |
| 233 | ++ .tables(1) // Single table for blockchain |
| 234 | ++ .memories(1) // Single memory for blockchain |
| 235 | ++ .table_elements(64) // Limited table elements for blockchain |
| 236 | ++ .trap_on_grow_failure(false) // Return -1 on growth failure instead of trapping |
| 237 | ++ .build(); |
| 238 | ++ |
| 239 | ++ let mut store = Store::new(&engine.inner, limits); |
| 240 | ++ |
| 241 | ++ // Install the resource limiter |
| 242 | ++ store.limiter(|limits| limits); |
| 243 | ++ |
| 244 | + Box::new(wasm_store_t { |
| 245 | + inner: WasmStoreRef { |
| 246 | + inner: Arc::new(UnsafeCell::new(store)), |
| 247 | +@@ -175,3 +229,40 @@ pub extern "C" fn wasmi_context_set_fuel( |
| 248 | + ) -> Option<Box<wasmi_error_t>> { |
| 249 | + crate::handle_result(store.set_fuel(fuel), |()| {}) |
| 250 | + } |
| 251 | ++ |
| 252 | ++//////////////////////////////////////////////////////////////////////////////////////// |
| 253 | ++//////////////////////////////////////////////////////////////////////////////////////// |
| 254 | ++ |
| 255 | ++/// Returns the current fuel of the wasm store context in `fuel`. |
| 256 | ++/// |
| 257 | ++/// Wraps [`Store::get_fuel`]. |
| 258 | ++/// |
| 259 | ++/// # Errors |
| 260 | ++/// |
| 261 | ++/// If [`Store::get_fuel`] errors. |
| 262 | ++#[no_mangle] |
| 263 | ++pub extern "C" fn wasm_store_get_fuel( |
| 264 | ++ store: &wasm_store_t, |
| 265 | ++ fuel: &mut u64, |
| 266 | ++) -> Option<Box<wasmi_error_t>> { |
| 267 | ++ let context = unsafe { store.inner.context() }; |
| 268 | ++ crate::handle_result(context.get_fuel(), |amt| { |
| 269 | ++ *fuel = amt; |
| 270 | ++ }) |
| 271 | ++} |
| 272 | ++ |
| 273 | ++/// Sets the current fuel of the wasm store context to `fuel`. |
| 274 | ++/// |
| 275 | ++/// Wraps [`Store::set_fuel`]. |
| 276 | ++/// |
| 277 | ++/// # Errors |
| 278 | ++/// |
| 279 | ++/// If [`Store::set_fuel`] errors. |
| 280 | ++#[no_mangle] |
| 281 | ++pub extern "C" fn wasm_store_set_fuel( |
| 282 | ++ store: &mut wasm_store_t, |
| 283 | ++ fuel: u64, |
| 284 | ++) -> Option<Box<wasmi_error_t>> { |
| 285 | ++ let mut context = unsafe { store.inner.context_mut() }; |
| 286 | ++ crate::handle_result(context.set_fuel(fuel), |()| {}) |
| 287 | ++} |
0 commit comments