Fix access to VMMemoryDefinition::current_length on big-endian (#3013)
The current_length member is defined as "usize" in Rust code, but generated wasm code refers to it as if it were "u32". While this happens to mostly work on little-endian machines (as long as the length is < 4GB), it will always fail on big-endian machines. Fixed by making current_length "u32" in Rust as well, and ensuring the actual memory size is always less than 4GB.
This commit is contained in:
@@ -703,10 +703,10 @@ impl Instance {
|
|||||||
|
|
||||||
if src
|
if src
|
||||||
.checked_add(len)
|
.checked_add(len)
|
||||||
.map_or(true, |n| n as usize > src_mem.current_length)
|
.map_or(true, |n| n > src_mem.current_length)
|
||||||
|| dst
|
|| dst
|
||||||
.checked_add(len)
|
.checked_add(len)
|
||||||
.map_or(true, |m| m as usize > dst_mem.current_length)
|
.map_or(true, |m| m > dst_mem.current_length)
|
||||||
{
|
{
|
||||||
return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
|
return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
|
||||||
}
|
}
|
||||||
@@ -741,7 +741,7 @@ impl Instance {
|
|||||||
|
|
||||||
if dst
|
if dst
|
||||||
.checked_add(len)
|
.checked_add(len)
|
||||||
.map_or(true, |m| m as usize > memory.current_length)
|
.map_or(true, |m| m > memory.current_length)
|
||||||
{
|
{
|
||||||
return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
|
return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
|
||||||
}
|
}
|
||||||
@@ -825,7 +825,7 @@ impl Instance {
|
|||||||
.map_or(true, |n| n as usize > data.len())
|
.map_or(true, |n| n as usize > data.len())
|
||||||
|| dst
|
|| dst
|
||||||
.checked_add(len)
|
.checked_add(len)
|
||||||
.map_or(true, |m| m as usize > memory.current_length)
|
.map_or(true, |m| m > memory.current_length)
|
||||||
{
|
{
|
||||||
return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
|
return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ fn check_memory_init_bounds(
|
|||||||
let end = start.checked_add(init.data.len());
|
let end = start.checked_add(init.data.len());
|
||||||
|
|
||||||
match end {
|
match end {
|
||||||
Some(end) if end <= memory.current_length => {
|
Some(end) if end <= memory.current_length as usize => {
|
||||||
// Initializer is in bounds
|
// Initializer is in bounds
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -382,8 +382,9 @@ fn initialize_instance(
|
|||||||
MemoryInitialization::Paged { map, out_of_bounds } => {
|
MemoryInitialization::Paged { map, out_of_bounds } => {
|
||||||
for (index, pages) in map {
|
for (index, pages) in map {
|
||||||
let memory = instance.memory(index);
|
let memory = instance.memory(index);
|
||||||
let slice =
|
let slice = unsafe {
|
||||||
unsafe { slice::from_raw_parts_mut(memory.base, memory.current_length) };
|
slice::from_raw_parts_mut(memory.base, memory.current_length as usize)
|
||||||
|
};
|
||||||
|
|
||||||
for (page_index, page) in pages.iter().enumerate() {
|
for (page_index, page) in pages.iter().enumerate() {
|
||||||
if let Some(data) = page {
|
if let Some(data) = page {
|
||||||
|
|||||||
@@ -155,6 +155,10 @@ impl RuntimeLinearMemory for MmapMemory {
|
|||||||
// Linear memory size would exceed the index range.
|
// Linear memory size would exceed the index range.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
// FIXME: https://github.com/bytecodealliance/wasmtime/issues/3022
|
||||||
|
if new_pages == WASM_MAX_PAGES {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let delta_bytes = usize::try_from(delta).unwrap() * WASM_PAGE_SIZE as usize;
|
let delta_bytes = usize::try_from(delta).unwrap() * WASM_PAGE_SIZE as usize;
|
||||||
let prev_bytes = usize::try_from(prev_pages).unwrap() * WASM_PAGE_SIZE as usize;
|
let prev_bytes = usize::try_from(prev_pages).unwrap() * WASM_PAGE_SIZE as usize;
|
||||||
@@ -194,7 +198,8 @@ impl RuntimeLinearMemory for MmapMemory {
|
|||||||
fn vmmemory(&self) -> VMMemoryDefinition {
|
fn vmmemory(&self) -> VMMemoryDefinition {
|
||||||
VMMemoryDefinition {
|
VMMemoryDefinition {
|
||||||
base: unsafe { self.mmap.alloc.as_mut_ptr().add(self.pre_guard_size) },
|
base: unsafe { self.mmap.alloc.as_mut_ptr().add(self.pre_guard_size) },
|
||||||
current_length: self.mmap.size as usize * WASM_PAGE_SIZE as usize,
|
current_length: u32::try_from(self.mmap.size as usize * WASM_PAGE_SIZE as usize)
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,6 +276,13 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn limit_new(plan: &MemoryPlan, limiter: Option<&mut dyn ResourceLimiter>) -> Result<()> {
|
fn limit_new(plan: &MemoryPlan, limiter: Option<&mut dyn ResourceLimiter>) -> Result<()> {
|
||||||
|
// FIXME: https://github.com/bytecodealliance/wasmtime/issues/3022
|
||||||
|
if plan.memory.minimum == WASM_MAX_PAGES {
|
||||||
|
bail!(
|
||||||
|
"memory minimum size of {} pages exceeds memory limits",
|
||||||
|
plan.memory.minimum
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(limiter) = limiter {
|
if let Some(limiter) = limiter {
|
||||||
if !limiter.memory_growing(0, plan.memory.minimum, plan.memory.maximum) {
|
if !limiter.memory_growing(0, plan.memory.minimum, plan.memory.maximum) {
|
||||||
bail!(
|
bail!(
|
||||||
@@ -362,6 +374,10 @@ impl Memory {
|
|||||||
if new_size > maximum.unwrap_or(WASM_MAX_PAGES) {
|
if new_size > maximum.unwrap_or(WASM_MAX_PAGES) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
// FIXME: https://github.com/bytecodealliance/wasmtime/issues/3022
|
||||||
|
if new_size == WASM_MAX_PAGES {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let start = usize::try_from(old_size).unwrap() * WASM_PAGE_SIZE as usize;
|
let start = usize::try_from(old_size).unwrap() * WASM_PAGE_SIZE as usize;
|
||||||
let len = usize::try_from(delta).unwrap() * WASM_PAGE_SIZE as usize;
|
let len = usize::try_from(delta).unwrap() * WASM_PAGE_SIZE as usize;
|
||||||
@@ -381,7 +397,7 @@ impl Memory {
|
|||||||
match self {
|
match self {
|
||||||
Memory::Static { base, size, .. } => VMMemoryDefinition {
|
Memory::Static { base, size, .. } => VMMemoryDefinition {
|
||||||
base: base.as_ptr() as *mut _,
|
base: base.as_ptr() as *mut _,
|
||||||
current_length: *size as usize * WASM_PAGE_SIZE as usize,
|
current_length: u32::try_from(*size as usize * WASM_PAGE_SIZE as usize).unwrap(),
|
||||||
},
|
},
|
||||||
Memory::Dynamic(mem) => mem.vmmemory(),
|
Memory::Dynamic(mem) => mem.vmmemory(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ pub struct VMMemoryDefinition {
|
|||||||
pub base: *mut u8,
|
pub base: *mut u8,
|
||||||
|
|
||||||
/// The current logical size of this linear memory in bytes.
|
/// The current logical size of this linear memory in bytes.
|
||||||
pub current_length: usize,
|
pub current_length: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ impl Memory {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let store = store.into();
|
let store = store.into();
|
||||||
let definition = *store[self.0].definition;
|
let definition = *store[self.0].definition;
|
||||||
slice::from_raw_parts(definition.base, definition.current_length)
|
slice::from_raw_parts(definition.base, definition.current_length as usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ impl Memory {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let store = store.into();
|
let store = store.into();
|
||||||
let definition = *store[self.0].definition;
|
let definition = *store[self.0].definition;
|
||||||
slice::from_raw_parts_mut(definition.base, definition.current_length)
|
slice::from_raw_parts_mut(definition.base, definition.current_length as usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ impl Memory {
|
|||||||
///
|
///
|
||||||
/// Panics if this memory doesn't belong to `store`.
|
/// Panics if this memory doesn't belong to `store`.
|
||||||
pub fn data_size(&self, store: impl AsContext) -> usize {
|
pub fn data_size(&self, store: impl AsContext) -> usize {
|
||||||
unsafe { (*store.as_context()[self.0].definition).current_length }
|
unsafe { (*store.as_context()[self.0].definition).current_length as usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size, in WebAssembly pages, of this wasm memory.
|
/// Returns the size, in WebAssembly pages, of this wasm memory.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use wasmtime_environ::entity::PrimaryMap;
|
|||||||
use wasmtime_environ::{wasm, MemoryPlan, MemoryStyle, Module, WASM_PAGE_SIZE};
|
use wasmtime_environ::{wasm, MemoryPlan, MemoryStyle, Module, WASM_PAGE_SIZE};
|
||||||
use wasmtime_runtime::{RuntimeLinearMemory, RuntimeMemoryCreator, VMMemoryDefinition};
|
use wasmtime_runtime::{RuntimeLinearMemory, RuntimeMemoryCreator, VMMemoryDefinition};
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub fn create_memory(store: &mut StoreOpaque<'_>, memory: &MemoryType) -> Result<InstanceId> {
|
pub fn create_memory(store: &mut StoreOpaque<'_>, memory: &MemoryType) -> Result<InstanceId> {
|
||||||
@@ -48,7 +49,8 @@ impl RuntimeLinearMemory for LinearMemoryProxy {
|
|||||||
fn vmmemory(&self) -> VMMemoryDefinition {
|
fn vmmemory(&self) -> VMMemoryDefinition {
|
||||||
VMMemoryDefinition {
|
VMMemoryDefinition {
|
||||||
base: self.mem.as_ptr(),
|
base: self.mem.as_ptr(),
|
||||||
current_length: self.mem.size() as usize * WASM_PAGE_SIZE as usize,
|
current_length: u32::try_from(self.mem.size() as usize * WASM_PAGE_SIZE as usize)
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ fn linear_memory_limits() -> Result<()> {
|
|||||||
fn test(engine: &Engine) -> Result<()> {
|
fn test(engine: &Engine) -> Result<()> {
|
||||||
let wat = r#"
|
let wat = r#"
|
||||||
(module
|
(module
|
||||||
(memory 65535)
|
(memory 65534)
|
||||||
|
|
||||||
(func (export "foo") (result i32)
|
(func (export "foo") (result i32)
|
||||||
i32.const 1
|
i32.const 1
|
||||||
@@ -68,7 +68,7 @@ fn linear_memory_limits() -> Result<()> {
|
|||||||
let instance = Instance::new(&mut store, &module, &[])?;
|
let instance = Instance::new(&mut store, &module, &[])?;
|
||||||
let foo = instance.get_typed_func::<(), i32, _>(&mut store, "foo")?;
|
let foo = instance.get_typed_func::<(), i32, _>(&mut store, "foo")?;
|
||||||
|
|
||||||
assert_eq!(foo.call(&mut store, ())?, 65535);
|
assert_eq!(foo.call(&mut store, ())?, 65534);
|
||||||
assert_eq!(foo.call(&mut store, ())?, -1);
|
assert_eq!(foo.call(&mut store, ())?, -1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user