Merge pull request from GHSA-wh6w-3828-g9qf
* Unconditionally use `MemoryImageSlot` This commit removes the internal branching within the pooling instance allocator to sometimes use a `MemoryImageSlot` and sometimes now. Instead this is now unconditionally used in all situations on all platforms. This fixes an issue where the state of a slot could get corrupted if modules being instantiated switched from having images to not having an image or vice versa. The bulk of this commit is the removal of the `memory-init-cow` compile-time feature in addition to adding Windows support to the `cow.rs` file. * Fix compile on Unix * Add a stricter assertion for static memory bounds Double-check that when a memory is allocated the configuration required is satisfied by the pooling allocator.
This commit is contained in:
@@ -10,6 +10,7 @@ use crate::Store;
|
||||
use anyhow::Error;
|
||||
use anyhow::{bail, format_err, Result};
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use wasmtime_environ::{MemoryPlan, MemoryStyle, WASM32_MAX_PAGES, WASM64_MAX_PAGES};
|
||||
@@ -351,14 +352,9 @@ struct StaticMemory {
|
||||
/// The current size, in bytes, of this memory.
|
||||
size: usize,
|
||||
|
||||
/// A callback which makes portions of `base` accessible for when memory
|
||||
/// is grown. Otherwise it's expected that accesses to `base` will
|
||||
/// fault.
|
||||
make_accessible: Option<fn(*mut u8, usize) -> Result<()>>,
|
||||
|
||||
/// The image management, if any, for this memory. Owned here and
|
||||
/// returned to the pooling allocator when termination occurs.
|
||||
memory_image: Option<MemoryImageSlot>,
|
||||
memory_image: MemoryImageSlot,
|
||||
}
|
||||
|
||||
impl StaticMemory {
|
||||
@@ -366,8 +362,7 @@ impl StaticMemory {
|
||||
base: &'static mut [u8],
|
||||
initial_size: usize,
|
||||
maximum_size: Option<usize>,
|
||||
make_accessible: Option<fn(*mut u8, usize) -> Result<()>>,
|
||||
memory_image: Option<MemoryImageSlot>,
|
||||
memory_image: MemoryImageSlot,
|
||||
) -> Result<Self> {
|
||||
if base.len() < initial_size {
|
||||
bail!(
|
||||
@@ -384,16 +379,9 @@ impl StaticMemory {
|
||||
_ => base,
|
||||
};
|
||||
|
||||
if let Some(make_accessible) = make_accessible {
|
||||
if initial_size > 0 {
|
||||
make_accessible(base.as_mut_ptr(), initial_size)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
base,
|
||||
size: initial_size,
|
||||
make_accessible,
|
||||
memory_image,
|
||||
})
|
||||
}
|
||||
@@ -413,21 +401,7 @@ impl RuntimeLinearMemory for StaticMemory {
|
||||
// prior to arriving here.
|
||||
assert!(new_byte_size <= self.base.len());
|
||||
|
||||
// Actually grow the memory.
|
||||
if let Some(image) = &mut self.memory_image {
|
||||
image.set_heap_limit(new_byte_size)?;
|
||||
} else {
|
||||
let make_accessible = self
|
||||
.make_accessible
|
||||
.expect("make_accessible must be Some if this is not a CoW memory");
|
||||
|
||||
// Operating system can fail to make memory accessible.
|
||||
let old_byte_size = self.byte_size();
|
||||
make_accessible(
|
||||
unsafe { self.base.as_mut_ptr().add(old_byte_size) },
|
||||
new_byte_size - old_byte_size,
|
||||
)?;
|
||||
}
|
||||
self.memory_image.set_heap_limit(new_byte_size)?;
|
||||
|
||||
// Update our accounting of the available size.
|
||||
self.size = new_byte_size;
|
||||
@@ -442,11 +416,7 @@ impl RuntimeLinearMemory for StaticMemory {
|
||||
}
|
||||
|
||||
fn needs_init(&self) -> bool {
|
||||
if let Some(slot) = &self.memory_image {
|
||||
!slot.has_image()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
!self.memory_image.has_image()
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
@@ -627,13 +597,11 @@ impl Memory {
|
||||
pub fn new_static(
|
||||
plan: &MemoryPlan,
|
||||
base: &'static mut [u8],
|
||||
make_accessible: Option<fn(*mut u8, usize) -> Result<()>>,
|
||||
memory_image: Option<MemoryImageSlot>,
|
||||
memory_image: MemoryImageSlot,
|
||||
store: &mut dyn Store,
|
||||
) -> Result<Self> {
|
||||
let (minimum, maximum) = Self::limit_new(plan, Some(store))?;
|
||||
let pooled_memory =
|
||||
StaticMemory::new(base, minimum, maximum, make_accessible, memory_image)?;
|
||||
let pooled_memory = StaticMemory::new(base, minimum, maximum, memory_image)?;
|
||||
let allocation = Box::new(pooled_memory);
|
||||
let allocation: Box<dyn RuntimeLinearMemory> = if plan.memory.shared {
|
||||
// FIXME: since the pooling allocator owns the memory allocation
|
||||
@@ -794,25 +762,13 @@ impl Memory {
|
||||
self.0.vmmemory()
|
||||
}
|
||||
|
||||
/// Check if the inner implementation of [`Memory`] is a memory created with
|
||||
/// [`Memory::new_static()`].
|
||||
#[cfg(feature = "pooling-allocator")]
|
||||
pub fn is_static(&mut self) -> bool {
|
||||
let as_any = self.0.as_any_mut();
|
||||
as_any.downcast_ref::<StaticMemory>().is_some()
|
||||
}
|
||||
|
||||
/// Consume the memory, returning its [`MemoryImageSlot`] if any is present.
|
||||
/// The image should only be present for a subset of memories created with
|
||||
/// [`Memory::new_static()`].
|
||||
#[cfg(feature = "pooling-allocator")]
|
||||
pub fn unwrap_static_image(mut self) -> Option<MemoryImageSlot> {
|
||||
let as_any = self.0.as_any_mut();
|
||||
if let Some(m) = as_any.downcast_mut::<StaticMemory>() {
|
||||
std::mem::take(&mut m.memory_image)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn unwrap_static_image(mut self) -> MemoryImageSlot {
|
||||
let mem = self.0.as_any_mut().downcast_mut::<StaticMemory>().unwrap();
|
||||
mem::replace(&mut mem.memory_image, MemoryImageSlot::dummy())
|
||||
}
|
||||
|
||||
/// If the [Memory] is a [SharedMemory], unwrap it and return a clone to
|
||||
|
||||
Reference in New Issue
Block a user