From afc879a2cb98e400fe8f291267581071b5fe56d3 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 10 Dec 2020 14:53:24 +0100 Subject: [PATCH] Handle overflow errors in Bytes -> Pages conversion --- CHANGELOG.md | 1 + lib/vm/src/memory.rs | 4 +-- lib/wasmer-types/src/units.rs | 46 ++++++++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8c5cc0b61d..bde09adbed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * [#1867](https://github.com/wasmerio/wasmer/pull/1867) Added `Metering::get_remaining_points` and `Metering::set_remaining_points` * [#1881](https://github.com/wasmerio/wasmer/pull/1881) Added `UnsupportedTarget` error to `CompileError` * [#1908](https://github.com/wasmerio/wasmer/pull/1908) Implemented `TryFrom>` for `i32`/`u32`/`i64`/`u64`/`f32`/`f64` +* [#1914](https://github.com/wasmerio/wasmer/pull/1914) Implemented `TryFrom for Pages` instead of `From for Pages` to properly handle overflow errors ### Changed diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index 137c03f6b34..96b3292d746 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -318,7 +318,7 @@ impl Memory for LinearMemory { unsafe { let md_ptr = self.get_vm_memory_definition(); let md = md_ptr.as_ref(); - Bytes::from(md.current_length).into() + Bytes::from(md.current_length).try_into().unwrap() } } @@ -376,7 +376,7 @@ impl Memory for LinearMemory { .checked_add(guard_bytes) .ok_or_else(|| MemoryError::CouldNotGrow { current: new_pages, - attempted_delta: Bytes(guard_bytes).into(), + attempted_delta: Bytes(guard_bytes).try_into().unwrap(), })?; let mut new_mmap = diff --git a/lib/wasmer-types/src/units.rs b/lib/wasmer-types/src/units.rs index 22aed031141..d30cc1e7e40 100644 --- a/lib/wasmer-types/src/units.rs +++ b/lib/wasmer-types/src/units.rs @@ -1,3 +1,4 @@ +use crate::lib::std::convert::TryFrom; use crate::lib::std::fmt; use crate::lib::std::ops::{Add, Sub}; #[cfg(feature = "enable-serde")] @@ -108,9 +109,16 @@ where } } -impl From for Pages { - fn from(bytes: Bytes) -> Self { - Self((bytes.0 / WASM_PAGE_SIZE) as u32) +const PAGES_EXCEED_UINT32: &'static str = "Number of pages exceeds uint32 range"; + +impl TryFrom for Pages { + type Error = &'static str; + + fn try_from(bytes: Bytes) -> Result { + let pages: u32 = (bytes.0 / WASM_PAGE_SIZE) + .try_into() + .or(Err(PAGES_EXCEED_UINT32))?; + Ok(Self(pages)) } } @@ -133,3 +141,35 @@ where Self(self.0 + rhs.into().0) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn convert_bytes_to_pages() { + // rounds down + let pages = Pages::try_from(Bytes(0)).unwrap(); + assert_eq!(pages, Pages(0)); + let pages = Pages::try_from(Bytes(1)).unwrap(); + assert_eq!(pages, Pages(0)); + let pages = Pages::try_from(Bytes(WASM_PAGE_SIZE - 1)).unwrap(); + assert_eq!(pages, Pages(0)); + let pages = Pages::try_from(Bytes(WASM_PAGE_SIZE)).unwrap(); + assert_eq!(pages, Pages(1)); + let pages = Pages::try_from(Bytes(WASM_PAGE_SIZE + 1)).unwrap(); + assert_eq!(pages, Pages(1)); + let pages = Pages::try_from(Bytes(28 * WASM_PAGE_SIZE + 42)).unwrap(); + assert_eq!(pages, Pages(28)); + let pages = Pages::try_from(Bytes((u32::MAX as usize) * WASM_PAGE_SIZE)).unwrap(); + assert_eq!(pages, Pages(u32::MAX)); + let pages = Pages::try_from(Bytes((u32::MAX as usize) * WASM_PAGE_SIZE + 1)).unwrap(); + assert_eq!(pages, Pages(u32::MAX)); + + // Errors when page count cannot be represented as u32 + let result = Pages::try_from(Bytes((u32::MAX as usize + 1) * WASM_PAGE_SIZE)); + assert_eq!(result.unwrap_err(), "Number of pages exceeds uint32 range"); + let result = Pages::try_from(Bytes(usize::MAX)); + assert_eq!(result.unwrap_err(), "Number of pages exceeds uint32 range"); + } +}