diff --git a/Cargo.lock b/Cargo.lock index 83051c53f..0b062168f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "wasmer" -version = "0.1.4" +version = "0.2.0" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index f19380cdb..f52076d28 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -208,14 +208,13 @@ pub extern "C" fn wasmer_memory_grow( delta: uint32_t, ) -> wasmer_result_t { let memory = unsafe { &*(memory as *mut Memory) }; - let maybe_delta = memory.grow(Pages(delta)); - if let Some(_delta) = maybe_delta { - wasmer_result_t::WASMER_OK - } else { - update_last_error(CApiError { - msg: "unable to grow memory".to_string(), - }); - wasmer_result_t::WASMER_ERROR + let delta_result = memory.grow(Pages(delta)); + match delta_result { + Ok(_) => wasmer_result_t::WASMER_OK, + Err(grow_error) => { + update_last_error(grow_error); + wasmer_result_t::WASMER_ERROR + } } } @@ -277,14 +276,13 @@ pub extern "C" fn wasmer_table_grow( delta: uint32_t, ) -> wasmer_result_t { let table = unsafe { &*(table as *mut Table) }; - let maybe_delta = table.grow(delta); - if let Some(_delta) = maybe_delta { - wasmer_result_t::WASMER_OK - } else { - update_last_error(CApiError { - msg: "unable to grow table".to_string(), - }); - wasmer_result_t::WASMER_ERROR + let delta_result = table.grow(delta); + match delta_result { + Ok(_) => wasmer_result_t::WASMER_OK, + Err(grow_error) => { + update_last_error(grow_error); + wasmer_result_t::WASMER_ERROR + } } } diff --git a/lib/runtime-c-api/tests/test-memory.c b/lib/runtime-c-api/tests/test-memory.c index 63913c73b..64e028693 100644 --- a/lib/runtime-c-api/tests/test-memory.c +++ b/lib/runtime-c-api/tests/test-memory.c @@ -23,13 +23,13 @@ int main() wasmer_result_t grow_result = wasmer_memory_grow(memory, 2); assert(grow_result == WASMER_OK); - uint32_t new_len = wasmer_memory_length(memory); + uint32_t new_len = wasmer_memory_length(memory); printf("Memory pages length: %d\n", new_len); assert(new_len == 12); - uint32_t bytes_len = wasmer_memory_data_length(memory); + uint32_t bytes_len = wasmer_memory_data_length(memory); printf("Memory bytes length: %d\n", bytes_len); - assert(bytes_len == 12 * 65536); + assert(bytes_len == 12 * 65536); // Err, grow beyond max wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10); @@ -38,23 +38,26 @@ int main() char *error_str = malloc(error_len); wasmer_last_error_message(error_str, error_len); printf("Error str: `%s`\n", error_str); - assert(0 == strcmp(error_str, "unable to grow memory")); + assert(0 == strcmp(error_str, "Failed to add pages because would exceed maximum number of pages for the memory. Left: 22, Added: 15")); free(error_str); + wasmer_memory_t *bad_memory = NULL; + wasmer_limits_t bad_descriptor; + bad_descriptor.min = 15; + wasmer_limit_option_t max2; + max2.has_some = true; + max2.some = 10; + bad_descriptor.max = max2; + wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor); + printf("Bad memory result: %d\n", bad_memory_result); + assert(bad_memory_result == WASMER_ERROR); -// wasmer_memory_t *bad_memory = NULL; -// wasmer_limits_t bad_descriptor; -// bad_descriptor.min = 15; -// bad_descriptor.max = 10; -// wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor); -// printf("Bad memory result: %d\n", bad_memory_result); -// assert(memory_result == WASMER_MEMORY_ERROR); -// -// int error_len = wasmer_last_error_length(); -// char *error_str = malloc(error_len); -// wasmer_last_error_message(error_str, error_len); -// assert(0 == strcmp(error_str, "Creation error")); -// free(error_str); + int error_len2 = wasmer_last_error_length(); + char *error_str2 = malloc(error_len2); + wasmer_last_error_message(error_str2, error_len2); + printf("Error str 2: `%s`\n", error_str2); + assert(0 == strcmp(error_str2, "Unable to create because the supplied descriptor is invalid: \"Max number of memory pages is less than the minimum number of pages\"")); + free(error_str2); printf("Destroy memory\n"); wasmer_memory_destroy(memory); diff --git a/lib/runtime-c-api/tests/test-tables.c b/lib/runtime-c-api/tests/test-tables.c index 48b7be710..ac093d182 100644 --- a/lib/runtime-c-api/tests/test-tables.c +++ b/lib/runtime-c-api/tests/test-tables.c @@ -9,7 +9,7 @@ int main() wasmer_limits_t descriptor; descriptor.min = 10; wasmer_limit_option_t max; -// max.has_some = false; + // max.has_some = false; max.has_some = true; max.some = 15; descriptor.max = max; @@ -21,26 +21,29 @@ int main() printf("Table length: %d\n", len); assert(len == 10); -// wasmer_result_t grow_result1 = wasmer_table_grow(table, 5); -// assert(grow_result1 == WASMER_OK); -// uint32_t len_grow1 = wasmer_table_length(table); -// printf("Table length: %d\n", len_grow1); -// assert(len_grow1 == 15); + wasmer_result_t grow_result1 = wasmer_table_grow(table, 5); + assert(grow_result1 == WASMER_OK); + uint32_t len_grow1 = wasmer_table_length(table); + printf("Table length: %d\n", len_grow1); + assert(len_grow1 == 15); - // // Try to grow beyond max - // wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1); - // assert(grow_result2 == WASMER_ERROR); - // uint32_t len_grow2 = wasmer_table_length(table); - // printf("Table length: %d\n", len_grow2); - // assert(len_grow2 == 15); + // Try to grow beyond max + wasmer_result_t grow_result2 = wasmer_table_grow(table, 1); + assert(grow_result2 == WASMER_ERROR); + uint32_t len_grow2 = wasmer_table_length(table); + printf("Table length: %d\n", len_grow2); + assert(len_grow2 == 15); -// wasmer_table_t *table_bad = NULL; -// wasmer_limits_t bad_descriptor; -// bad_descriptor.min = 15; -// bad_descriptor.max = 10; -// wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor); -// printf("Table result: %d\n", table_bad_result); -// assert(table_result == WASMER_ERROR); + wasmer_table_t *table_bad = NULL; + wasmer_limits_t bad_descriptor; + bad_descriptor.min = 15; + wasmer_limit_option_t max2; + max2.has_some = true; + max2.some = 10; + bad_descriptor.max = max2; + wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor); + printf("Table result: %d\n", table_bad_result); + assert(table_bad_result == WASMER_ERROR); printf("Destroy table\n"); wasmer_table_destroy(table); diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index 33c9fd15f..1f9f60c61 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -1,3 +1,4 @@ +use crate::sys::Memory; use crate::types::{ FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type, }; @@ -369,3 +370,105 @@ impl std::fmt::Display for Error { } impl std::error::Error for Error {} + +#[derive(Debug)] +pub enum GrowError { + MemoryGrowError, + TableGrowError, + ExceededMaxPages(PageError), + ExceededMaxPagesForMemory(usize, usize), + CouldNotProtectMemory(MemoryProtectionError), + CouldNotCreateMemory(MemoryCreationError), +} + +impl std::fmt::Display for GrowError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + GrowError::MemoryGrowError => write!(f, "Unable to grow memory"), + GrowError::TableGrowError => write!(f, "Unable to grow table"), + GrowError::ExceededMaxPages(e) => write!(f, "Grow Error: {}", e), + GrowError::ExceededMaxPagesForMemory(left, added) => write!(f, "Failed to add pages because would exceed maximum number of pages for the memory. Left: {}, Added: {}", left, added), + GrowError::CouldNotCreateMemory(e) => write!(f, "Grow Error: {}", e), + GrowError::CouldNotProtectMemory(e) => write!(f, "Grow Error: {}", e), + } + } +} + +impl std::error::Error for GrowError {} + +#[derive(Debug)] +pub enum PageError { + // left, right, added + ExceededMaxPages(usize, usize, usize), +} + +impl std::fmt::Display for PageError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + PageError::ExceededMaxPages(left, right, added) => write!(f, "Failed to add pages because would exceed maximum number of pages. Left: {}, Right: {}, Pages added: {}", left, right, added), + } + } +} +impl std::error::Error for PageError {} + +impl Into for PageError { + fn into(self) -> GrowError { + GrowError::ExceededMaxPages(self) + } +} + +#[derive(Debug)] +pub enum MemoryCreationError { + VirtualMemoryAllocationFailed(usize, String), + CouldNotCreateMemoryFromFile(std::io::Error), +} + +impl std::fmt::Display for MemoryCreationError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + MemoryCreationError::VirtualMemoryAllocationFailed(size, msg) => write!( + f, + "Allocation virtual memory with size {} failed. \nErrno message: {}", + size, msg + ), + MemoryCreationError::CouldNotCreateMemoryFromFile(e) => write!(f, "IO Error: {}", e), + } + } +} +impl std::error::Error for MemoryCreationError {} + +impl Into for MemoryCreationError { + fn into(self) -> GrowError { + GrowError::CouldNotCreateMemory(self) + } +} + +impl From for MemoryCreationError { + fn from(io_error: std::io::Error) -> Self { + MemoryCreationError::CouldNotCreateMemoryFromFile(io_error) + } +} + +#[derive(Debug)] +pub enum MemoryProtectionError { + ProtectionFailed(usize, usize, String), +} + +impl std::fmt::Display for MemoryProtectionError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + MemoryProtectionError::ProtectionFailed(start, size, msg) => write!( + f, + "Allocation virtual memory starting at {} with size {} failed. \nErrno message: {}", + start, size, msg + ), + } + } +} +impl std::error::Error for MemoryProtectionError {} + +impl Into for MemoryProtectionError { + fn into(self) -> GrowError { + GrowError::CouldNotProtectMemory(self) + } +} diff --git a/lib/runtime-core/src/memory/dynamic.rs b/lib/runtime-core/src/memory/dynamic.rs index bfe731a83..332a37acb 100644 --- a/lib/runtime-core/src/memory/dynamic.rs +++ b/lib/runtime-core/src/memory/dynamic.rs @@ -1,3 +1,4 @@ +use crate::error::GrowError; use crate::{ error::CreationError, sys, @@ -14,9 +15,9 @@ pub const DYNAMIC_GUARD_SIZE: usize = 4096; /// when first created. Over time, as it grows, it may reallocate to /// a different location and size. /// -/// Dynamic memories are signifigantly faster to create than static +/// Dynamic memories are significantly faster to create than static /// memories and use much less virtual memory, however, they require -/// the webassembly module to bounds-check memory accesses. +/// the WebAssembly module to bounds-check memory accesses. /// /// While, a dynamic memory could use a vector of some sort as its /// backing memory, we use mmap (or the platform-equivalent) to allow @@ -65,26 +66,29 @@ impl DynamicMemory { self.current } - pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option { + pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result { if delta == Pages(0) { - return Some(self.current); + return Ok(self.current); } - let new_pages = self.current.checked_add(delta)?; + let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?; if let Some(max) = self.max { if new_pages > max { - return None; + return Err(GrowError::ExceededMaxPagesForMemory( + new_pages.0 as usize, + max.0 as usize, + )); } } - let mut new_memory = - sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE).ok()?; + let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE) + .map_err(|e| e.into())?; unsafe { new_memory .protect(0..new_pages.bytes().0, sys::Protect::ReadWrite) - .ok()?; + .map_err(|e| e.into())?; new_memory.as_slice_mut()[..self.current.bytes().0] .copy_from_slice(&self.memory.as_slice()[..self.current.bytes().0]); @@ -97,7 +101,7 @@ impl DynamicMemory { let old_pages = self.current; self.current = new_pages; - Some(old_pages) + Ok(old_pages) } pub fn as_slice(&self) -> &[u8] { diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index bc706b564..4a9dccba7 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -1,5 +1,5 @@ use crate::{ - error::CreationError, + error::{CreationError, GrowError}, export::Export, import::IsExport, memory::dynamic::DYNAMIC_GUARD_SIZE, @@ -89,8 +89,8 @@ impl Memory { self.desc } - /// Grow this memory by the specfied number of pages. - pub fn grow(&self, delta: Pages) -> Option { + /// Grow this memory by the specified number of pages. + pub fn grow(&self, delta: Pages) -> Result { match &self.variant { MemoryVariant::Unshared(unshared_mem) => unshared_mem.grow(delta), MemoryVariant::Shared(shared_mem) => shared_mem.grow(delta), @@ -244,7 +244,7 @@ impl UnsharedMemory { }) } - pub fn grow(&self, delta: Pages) -> Option { + pub fn grow(&self, delta: Pages) -> Result { let mut storage = self.internal.storage.borrow_mut(); let mut local = self.internal.local.get(); @@ -292,7 +292,7 @@ impl SharedMemory { Ok(Self { desc }) } - pub fn grow(&self, _delta: Pages) -> Option { + pub fn grow(&self, _delta: Pages) -> Result { unimplemented!() } diff --git a/lib/runtime-core/src/memory/static_/unshared.rs b/lib/runtime-core/src/memory/static_/unshared.rs index 420fdc716..b9e66de0a 100644 --- a/lib/runtime-core/src/memory/static_/unshared.rs +++ b/lib/runtime-core/src/memory/static_/unshared.rs @@ -1,3 +1,4 @@ +use crate::error::GrowError; use crate::{ error::CreationError, memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE}, @@ -61,27 +62,30 @@ impl StaticMemory { self.current } - pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option { + pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result { if delta == Pages(0) { - return Some(self.current); + return Ok(self.current); } - let new_pages = self.current.checked_add(delta)?; + let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?; if let Some(max) = self.max { if new_pages > max { - return None; + return Err(GrowError::ExceededMaxPagesForMemory( + new_pages.0 as usize, + max.0 as usize, + )); } } - unsafe { + let _ = unsafe { self.memory .protect( self.current.bytes().0..new_pages.bytes().0, sys::Protect::ReadWrite, ) - .ok()?; - } + .map_err(|e| e.into()) + }?; local.bound = new_pages.bytes().0; @@ -89,7 +93,7 @@ impl StaticMemory { self.current = new_pages; - Some(old_pages) + Ok(old_pages) } pub fn as_slice(&self) -> &[u8] { diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index 8c76e6c14..338024d09 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -1,3 +1,5 @@ +use crate::error::MemoryCreationError; +use crate::error::MemoryProtectionError; use errno; use nix::libc; use page_size; @@ -16,13 +18,13 @@ pub struct Memory { } impl Memory { - pub fn from_file_path

(path: P, protection: Protect) -> Result + pub fn from_file_path

(path: P, protection: Protect) -> Result where P: AsRef, { - let file = File::open(path).map_err(|e| e.to_string())?; + let file = File::open(path)?; - let file_len = file.metadata().map_err(|e| e.to_string())?.len(); + let file_len = file.metadata()?.len(); let raw_fd = RawFd::from_file(file); @@ -38,7 +40,10 @@ impl Memory { }; if ptr == -1 as _ { - Err(errno::errno().to_string()) + Err(MemoryCreationError::VirtualMemoryAllocationFailed( + file_len as usize, + errno::errno().to_string(), + )) } else { Ok(Self { ptr: ptr as *mut u8, @@ -84,7 +89,7 @@ impl Memory { } } - pub fn with_size(size: usize) -> Result { + pub fn with_size(size: usize) -> Result { if size == 0 { return Ok(Self { ptr: ptr::null_mut(), @@ -108,7 +113,10 @@ impl Memory { }; if ptr == -1 as _ { - Err(errno::errno().to_string()) + Err(MemoryCreationError::VirtualMemoryAllocationFailed( + size, + errno::errno().to_string(), + )) } else { Ok(Self { ptr: ptr as *mut u8, @@ -123,7 +131,7 @@ impl Memory { &mut self, range: impl RangeBounds, protection: Protect, - ) -> Result<(), String> { + ) -> Result<(), MemoryProtectionError> { let protect = protection.to_protect_const(); let range_start = match range.start_bound() { @@ -147,7 +155,11 @@ impl Memory { let success = libc::mprotect(start as _, size, protect as i32); if success == -1 { - Err(errno::errno().to_string()) + Err(MemoryProtectionError::ProtectionFailed( + start as usize, + size, + errno::errno().to_string(), + )) } else { self.protection = protection; Ok(()) diff --git a/lib/runtime-core/src/sys/windows/memory.rs b/lib/runtime-core/src/sys/windows/memory.rs index 771ac6788..d47388170 100644 --- a/lib/runtime-core/src/sys/windows/memory.rs +++ b/lib/runtime-core/src/sys/windows/memory.rs @@ -1,3 +1,5 @@ +use crate::error::MemoryCreationError; +use crate::error::MemoryProtectionError; use page_size; use std::ops::{Bound, RangeBounds}; use std::{ptr, slice}; @@ -44,7 +46,7 @@ impl Memory { } } - pub fn with_size(size: usize) -> Result { + pub fn with_size(size: usize) -> Result { if size == 0 { return Ok(Self { ptr: ptr::null_mut(), @@ -58,7 +60,10 @@ impl Memory { let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, PAGE_NOACCESS) }; if ptr.is_null() { - Err("unable to allocate memory".to_string()) + Err(MemoryCreationError::VirtualMemoryAllocationFailed( + size, + "unable to allocate memory".to_string(), + )) } else { Ok(Self { ptr: ptr as *mut u8, @@ -72,7 +77,7 @@ impl Memory { &mut self, range: impl RangeBounds, protect: Protect, - ) -> Result<(), String> { + ) -> Result<(), MemoryProtectionError> { let protect_const = protect.to_protect_const(); let range_start = match range.start_bound() { @@ -98,7 +103,11 @@ impl Memory { let ptr = VirtualAlloc(start as _, size, MEM_COMMIT, protect_const); if ptr.is_null() { - Err("unable to protect memory".to_string()) + Err(MemoryProtectionError::ProtectionFailed( + start as usize, + size, + "unable to protect memory".to_string(), + )) } else { self.protection = protect; Ok(()) diff --git a/lib/runtime-core/src/table/mod.rs b/lib/runtime-core/src/table/mod.rs index a45593802..1c97b89f3 100644 --- a/lib/runtime-core/src/table/mod.rs +++ b/lib/runtime-core/src/table/mod.rs @@ -11,6 +11,7 @@ mod anyfunc; pub use self::anyfunc::Anyfunc; use self::anyfunc::AnyfuncTable; +use crate::error::GrowError; pub enum Element<'a> { Anyfunc(Anyfunc<'a>), @@ -108,15 +109,15 @@ impl Table { } /// Grow this table by `delta`. - pub fn grow(&self, delta: u32) -> Option { + pub fn grow(&self, delta: u32) -> Result { if delta == 0 { - return Some(self.size()); + return Ok(self.size()); } match &mut *self.storage.borrow_mut() { - (TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => { - anyfunc_table.grow(delta, local) - } + (TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => anyfunc_table + .grow(delta, local) + .ok_or(GrowError::TableGrowError), } } diff --git a/lib/runtime-core/src/units.rs b/lib/runtime-core/src/units.rs index 2486c5738..56d501438 100644 --- a/lib/runtime-core/src/units.rs +++ b/lib/runtime-core/src/units.rs @@ -1,3 +1,4 @@ +use crate::error::PageError; use std::{ fmt, ops::{Add, Sub}, @@ -11,12 +12,16 @@ const WASM_MAX_PAGES: usize = 65_536; pub struct Pages(pub u32); impl Pages { - pub fn checked_add(self, rhs: Pages) -> Option { + pub fn checked_add(self, rhs: Pages) -> Result { let added = (self.0 as usize) + (rhs.0 as usize); if added <= WASM_MAX_PAGES { - Some(Pages(added as u32)) + Ok(Pages(added as u32)) } else { - None + Err(PageError::ExceededMaxPages( + self.0 as usize, + rhs.0 as usize, + added, + )) } } diff --git a/lib/runtime-core/src/vmcalls.rs b/lib/runtime-core/src/vmcalls.rs index 576ca34ce..b428fb24e 100644 --- a/lib/runtime-core/src/vmcalls.rs +++ b/lib/runtime-core/src/vmcalls.rs @@ -20,10 +20,9 @@ pub unsafe extern "C" fn local_static_memory_grow( let local_memory = *ctx.memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut StaticMemory; - if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old.0 as i32 - } else { - -1 + match (*memory).grow(delta, &mut *local_memory) { + Ok(old) => old.0 as i32, + Err(_) => -1, } } @@ -45,10 +44,9 @@ pub unsafe extern "C" fn local_dynamic_memory_grow( let local_memory = *ctx.memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut DynamicMemory; - if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old.0 as i32 - } else { - -1 + match (*memory).grow(delta, &mut *local_memory) { + Ok(old) => old.0 as i32, + Err(_) => -1, } } @@ -74,10 +72,9 @@ pub unsafe extern "C" fn imported_static_memory_grow( let local_memory = *ctx.imported_memories.add(import_memory_index.index()); let memory = (*local_memory).memory as *mut StaticMemory; - if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old.0 as i32 - } else { - -1 + match (*memory).grow(delta, &mut *local_memory) { + Ok(old) => old.0 as i32, + Err(_) => -1, } } @@ -99,10 +96,9 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow( let local_memory = *ctx.imported_memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut DynamicMemory; - if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old.0 as i32 - } else { - -1 + match (*memory).grow(delta, &mut *local_memory) { + Ok(old) => old.0 as i32, + Err(_) => -1, } }