Remove dependency on the region crate (#4407)
This commit removes Wasmtime's dependency on the `region` crate. The motivation for this came about when I was updating dependencies and saw that `region` had a new major version at 3.0.0 as opposed to our currently used 2.3 track. In reviewing the use cases of `region` within Wasmtime I found two trends in particular which motivated this commit: * Some unix-specific areas of `wasmtime_runtime` use `rustix::mm::mprotect` instead of `region::protect` already. This means that the usage of `region::protect` for changing virtual memory protections was already inconsistent. * Many uses of `region::protect` were already in unix-specific regions which could make use of `rustix`. Overall I opted to remove the dependency on the `region` crate to avoid chasing its versions over time. Unix-specific changes of protections were easily changed to `rustix::mm::mprotect`. There were two locations where a windows/unix split is now required and I subjectively ruled "that seems ok". Finally removing `region` also meant that the "what is the current page size" query needed to be inlined into `wasmtime_runtime`, which I have also subjectively ruled "that seems fine". Finally one final refactoring here was that the `unix.rs` and `linux.rs` split for the pooling allocator was merged. These two files already only differed in one function so I slapped a `cfg_if!` in there to help reduce the duplication.
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -3323,7 +3323,6 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
"psm",
|
"psm",
|
||||||
"rayon",
|
"rayon",
|
||||||
"region",
|
|
||||||
"serde",
|
"serde",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@@ -3568,7 +3567,6 @@ dependencies = [
|
|||||||
"ittapi-rs",
|
"ittapi-rs",
|
||||||
"log",
|
"log",
|
||||||
"object",
|
"object",
|
||||||
"region",
|
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
"rustix",
|
"rustix",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3605,7 +3603,6 @@ dependencies = [
|
|||||||
"memoffset",
|
"memoffset",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"region",
|
|
||||||
"rustix",
|
"rustix",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ edition = "2021"
|
|||||||
wasmtime-environ = { path = "../environ", version = "=0.40.0" }
|
wasmtime-environ = { path = "../environ", version = "=0.40.0" }
|
||||||
wasmtime-jit-debug = { path = "../jit-debug", version = "=0.40.0", features = ["perf_jitdump"], optional = true }
|
wasmtime-jit-debug = { path = "../jit-debug", version = "=0.40.0", features = ["perf_jitdump"], optional = true }
|
||||||
wasmtime-runtime = { path = "../runtime", version = "=0.40.0" }
|
wasmtime-runtime = { path = "../runtime", version = "=0.40.0" }
|
||||||
region = "2.2.0"
|
|
||||||
thiserror = "1.0.4"
|
thiserror = "1.0.4"
|
||||||
target-lexicon = { version = "0.12.0", default-features = false }
|
target-lexicon = { version = "0.12.0", default-features = false }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ impl UnwindRegistration {
|
|||||||
unwind_len: usize,
|
unwind_len: usize,
|
||||||
) -> Result<UnwindRegistration> {
|
) -> Result<UnwindRegistration> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
unwind_info as usize % region::page::size(),
|
unwind_info as usize % wasmtime_runtime::page_size(),
|
||||||
0,
|
0,
|
||||||
"The unwind info must always be aligned to a page"
|
"The unwind info must always be aligned to a page"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ edition = "2021"
|
|||||||
wasmtime-environ = { path = "../environ", version = "=0.40.0" }
|
wasmtime-environ = { path = "../environ", version = "=0.40.0" }
|
||||||
wasmtime-fiber = { path = "../fiber", version = "=0.40.0", optional = true }
|
wasmtime-fiber = { path = "../fiber", version = "=0.40.0", optional = true }
|
||||||
wasmtime-jit-debug = { path = "../jit-debug", version = "=0.40.0", features = ["gdb_jit_int"] }
|
wasmtime-jit-debug = { path = "../jit-debug", version = "=0.40.0", features = ["gdb_jit_int"] }
|
||||||
region = "2.1.0"
|
|
||||||
libc = { version = "0.2.112", default-features = false }
|
libc = { version = "0.2.112", default-features = false }
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
memoffset = "0.6.0"
|
memoffset = "0.6.0"
|
||||||
@@ -39,6 +38,7 @@ features = [
|
|||||||
"Win32_System_Kernel",
|
"Win32_System_Kernel",
|
||||||
"Win32_System_Memory",
|
"Win32_System_Memory",
|
||||||
"Win32_System_Diagnostics_Debug",
|
"Win32_System_Diagnostics_Debug",
|
||||||
|
"Win32_System_SystemInformation",
|
||||||
"Win32_Storage_FileSystem",
|
"Win32_Storage_FileSystem",
|
||||||
"Win32_Security",
|
"Win32_Security",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ impl ModuleMemoryImages {
|
|||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
};
|
};
|
||||||
let mut memories = PrimaryMap::with_capacity(map.len());
|
let mut memories = PrimaryMap::with_capacity(map.len());
|
||||||
let page_size = region::page::size() as u32;
|
let page_size = crate::page_size() as u32;
|
||||||
for (memory_index, init) in map {
|
for (memory_index, init) in map {
|
||||||
// mmap-based-initialization only works for defined memories with a
|
// mmap-based-initialization only works for defined memories with a
|
||||||
// known starting point of all zeros, so bail out if the mmeory is
|
// known starting point of all zeros, so bail out if the mmeory is
|
||||||
@@ -596,7 +596,7 @@ mod test {
|
|||||||
|
|
||||||
fn create_memfd_with_data(offset: usize, data: &[u8]) -> Result<MemoryImage> {
|
fn create_memfd_with_data(offset: usize, data: &[u8]) -> Result<MemoryImage> {
|
||||||
// Offset must be page-aligned.
|
// Offset must be page-aligned.
|
||||||
let page_size = region::page::size();
|
let page_size = crate::page_size();
|
||||||
assert_eq!(offset & (page_size - 1), 0);
|
assert_eq!(offset & (page_size - 1), 0);
|
||||||
let memfd = create_memfd()?;
|
let memfd = create_memfd()?;
|
||||||
memfd.as_file().write_all(data)?;
|
memfd.as_file().write_all(data)?;
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ cfg_if::cfg_if! {
|
|||||||
if #[cfg(windows)] {
|
if #[cfg(windows)] {
|
||||||
mod windows;
|
mod windows;
|
||||||
use windows as imp;
|
use windows as imp;
|
||||||
} else if #[cfg(target_os = "linux")] {
|
|
||||||
mod linux;
|
|
||||||
use linux as imp;
|
|
||||||
} else {
|
} else {
|
||||||
mod unix;
|
mod unix;
|
||||||
use unix as imp;
|
use unix as imp;
|
||||||
@@ -217,7 +214,7 @@ impl InstancePool {
|
|||||||
instance_limits: &InstanceLimits,
|
instance_limits: &InstanceLimits,
|
||||||
tunables: &Tunables,
|
tunables: &Tunables,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let page_size = region::page::size();
|
let page_size = crate::page_size();
|
||||||
|
|
||||||
let instance_size = round_up_to_pow2(instance_limits.size, mem::align_of::<Instance>());
|
let instance_size = round_up_to_pow2(instance_limits.size, mem::align_of::<Instance>());
|
||||||
|
|
||||||
@@ -692,7 +689,7 @@ impl MemoryPool {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
memory_size % region::page::size() == 0,
|
memory_size % crate::page_size() == 0,
|
||||||
"memory size {} is not a multiple of system page size",
|
"memory size {} is not a multiple of system page size",
|
||||||
memory_size
|
memory_size
|
||||||
);
|
);
|
||||||
@@ -828,7 +825,7 @@ struct TablePool {
|
|||||||
|
|
||||||
impl TablePool {
|
impl TablePool {
|
||||||
fn new(instance_limits: &InstanceLimits) -> Result<Self> {
|
fn new(instance_limits: &InstanceLimits) -> Result<Self> {
|
||||||
let page_size = region::page::size();
|
let page_size = crate::page_size();
|
||||||
|
|
||||||
let table_size = round_up_to_pow2(
|
let table_size = round_up_to_pow2(
|
||||||
mem::size_of::<*mut u8>()
|
mem::size_of::<*mut u8>()
|
||||||
@@ -895,7 +892,9 @@ struct StackPool {
|
|||||||
#[cfg(all(feature = "async", unix))]
|
#[cfg(all(feature = "async", unix))]
|
||||||
impl StackPool {
|
impl StackPool {
|
||||||
fn new(instance_limits: &InstanceLimits, stack_size: usize) -> Result<Self> {
|
fn new(instance_limits: &InstanceLimits, stack_size: usize) -> Result<Self> {
|
||||||
let page_size = region::page::size();
|
use rustix::mm::{mprotect, MprotectFlags};
|
||||||
|
|
||||||
|
let page_size = crate::page_size();
|
||||||
|
|
||||||
// Add a page to the stack size for the guard page when using fiber stacks
|
// Add a page to the stack size for the guard page when using fiber stacks
|
||||||
let stack_size = if stack_size == 0 {
|
let stack_size = if stack_size == 0 {
|
||||||
@@ -921,7 +920,7 @@ impl StackPool {
|
|||||||
for i in 0..max_instances {
|
for i in 0..max_instances {
|
||||||
// Make the stack guard page inaccessible
|
// Make the stack guard page inaccessible
|
||||||
let bottom_of_stack = mapping.as_mut_ptr().add(i * stack_size);
|
let bottom_of_stack = mapping.as_mut_ptr().add(i * stack_size);
|
||||||
region::protect(bottom_of_stack, page_size, region::Protection::NONE)
|
mprotect(bottom_of_stack.cast(), page_size, MprotectFlags::empty())
|
||||||
.context("failed to protect stack guard page")?;
|
.context("failed to protect stack guard page")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1298,7 +1297,7 @@ mod test {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let host_page_size = region::page::size();
|
let host_page_size = crate::page_size();
|
||||||
|
|
||||||
assert_eq!(pool.table_size, host_page_size);
|
assert_eq!(pool.table_size, host_page_size);
|
||||||
assert_eq!(pool.max_tables, 4);
|
assert_eq!(pool.max_tables, 4);
|
||||||
@@ -1335,7 +1334,7 @@ mod test {
|
|||||||
1,
|
1,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let native_page_size = region::page::size();
|
let native_page_size = crate::page_size();
|
||||||
assert_eq!(pool.stack_size, 2 * native_page_size);
|
assert_eq!(pool.stack_size, 2 * native_page_size);
|
||||||
assert_eq!(pool.max_instances, 10);
|
assert_eq!(pool.max_instances, 10);
|
||||||
assert_eq!(pool.page_size, native_page_size);
|
assert_eq!(pool.page_size, native_page_size);
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
use anyhow::{Context, Result};
|
|
||||||
|
|
||||||
fn decommit(addr: *mut u8, len: usize, protect: bool) -> Result<()> {
|
|
||||||
if len == 0 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if protect {
|
|
||||||
region::protect(addr, len, region::Protection::NONE)
|
|
||||||
.context("failed to protect memory pages")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// On Linux, this is enough to cause the kernel to initialize the pages to 0 on next access
|
|
||||||
rustix::mm::madvise(addr as _, len, rustix::mm::Advice::LinuxDontNeed)
|
|
||||||
.context("madvise failed to decommit: {}")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit_memory_pages(addr: *mut u8, len: usize) -> Result<()> {
|
|
||||||
if len == 0 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just change the protection level to READ|WRITE
|
|
||||||
unsafe {
|
|
||||||
region::protect(addr, len, region::Protection::READ_WRITE)
|
|
||||||
.context("failed to make linear memory pages read/write")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decommit_memory_pages(addr: *mut u8, len: usize) -> Result<()> {
|
|
||||||
decommit(addr, len, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit_table_pages(_addr: *mut u8, _len: usize) -> Result<()> {
|
|
||||||
// A no-op as table pages remain READ|WRITE
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decommit_table_pages(addr: *mut u8, len: usize) -> Result<()> {
|
|
||||||
decommit(addr, len, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub fn commit_stack_pages(_addr: *mut u8, _len: usize) -> Result<()> {
|
|
||||||
// A no-op as stack pages remain READ|WRITE
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub fn decommit_stack_pages(addr: *mut u8, len: usize) -> Result<()> {
|
|
||||||
decommit(addr, len, false)
|
|
||||||
}
|
|
||||||
@@ -1,26 +1,45 @@
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use rustix::mm::{mprotect, MprotectFlags};
|
||||||
|
|
||||||
fn decommit(addr: *mut u8, len: usize, protect: bool) -> Result<()> {
|
fn decommit(addr: *mut u8, len: usize, protect: bool) -> Result<()> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// By creating a new mapping at the same location, this will discard the
|
|
||||||
// mapping for the pages in the given range.
|
|
||||||
// The new mapping will be to the CoW zero page, so this effectively
|
|
||||||
// zeroes the pages.
|
|
||||||
unsafe {
|
unsafe {
|
||||||
rustix::mm::mmap_anonymous(
|
cfg_if::cfg_if! {
|
||||||
addr as _,
|
if #[cfg(target_os = "linux")] {
|
||||||
len,
|
use rustix::mm::{madvise, Advice};
|
||||||
if protect {
|
|
||||||
rustix::mm::ProtFlags::empty()
|
if protect {
|
||||||
|
mprotect(addr.cast(), len, MprotectFlags::empty())
|
||||||
|
.context("failed to protect memory pages")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Linux, this is enough to cause the kernel to initialize
|
||||||
|
// the pages to 0 on next access
|
||||||
|
madvise(addr as _, len, Advice::LinuxDontNeed)
|
||||||
|
.context("madvise failed to decommit: {}")?;
|
||||||
} else {
|
} else {
|
||||||
rustix::mm::ProtFlags::READ | rustix::mm::ProtFlags::WRITE
|
use rustix::mm::{mmap_anonymous, ProtFlags, MapFlags};
|
||||||
},
|
|
||||||
rustix::mm::MapFlags::PRIVATE | rustix::mm::MapFlags::FIXED,
|
// By creating a new mapping at the same location, this will
|
||||||
)
|
// discard the mapping for the pages in the given range.
|
||||||
.context("mmap failed to remap pages: {}")?;
|
// The new mapping will be to the CoW zero page, so this
|
||||||
|
// effectively zeroes the pages.
|
||||||
|
mmap_anonymous(
|
||||||
|
addr as _,
|
||||||
|
len,
|
||||||
|
if protect {
|
||||||
|
ProtFlags::empty()
|
||||||
|
} else {
|
||||||
|
ProtFlags::READ | ProtFlags::WRITE
|
||||||
|
},
|
||||||
|
MapFlags::PRIVATE | MapFlags::FIXED,
|
||||||
|
)
|
||||||
|
.context("mmap failed to remap pages: {}")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -33,7 +52,7 @@ pub fn commit_memory_pages(addr: *mut u8, len: usize) -> Result<()> {
|
|||||||
|
|
||||||
// Just change the protection level to READ|WRITE
|
// Just change the protection level to READ|WRITE
|
||||||
unsafe {
|
unsafe {
|
||||||
region::protect(addr, len, region::Protection::READ_WRITE)
|
mprotect(addr.cast(), len, MprotectFlags::READ | MprotectFlags::WRITE)
|
||||||
.context("failed to make linear memory pages read/write")
|
.context("failed to make linear memory pages read/write")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,9 @@
|
|||||||
)]
|
)]
|
||||||
#![cfg_attr(not(memory_init_cow), allow(unused_variables, unreachable_code))]
|
#![cfg_attr(not(memory_init_cow), allow(unused_variables, unreachable_code))]
|
||||||
|
|
||||||
use std::sync::atomic::AtomicU64;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
use wasmtime_environ::DefinedFuncIndex;
|
use wasmtime_environ::DefinedFuncIndex;
|
||||||
use wasmtime_environ::DefinedMemoryIndex;
|
use wasmtime_environ::DefinedMemoryIndex;
|
||||||
use wasmtime_environ::FunctionInfo;
|
use wasmtime_environ::FunctionInfo;
|
||||||
@@ -200,3 +199,35 @@ pub trait ModuleRuntimeInfo: Send + Sync + 'static {
|
|||||||
/// `VMSharedSignatureIndex` entries corresponding to the `SignatureIndex`.
|
/// `VMSharedSignatureIndex` entries corresponding to the `SignatureIndex`.
|
||||||
fn signature_ids(&self) -> &[VMSharedSignatureIndex];
|
fn signature_ids(&self) -> &[VMSharedSignatureIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the host OS page size, in bytes.
|
||||||
|
pub fn page_size() -> usize {
|
||||||
|
static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
return match PAGE_SIZE.load(Ordering::Relaxed) {
|
||||||
|
0 => {
|
||||||
|
let size = get_page_size();
|
||||||
|
assert!(size != 0);
|
||||||
|
PAGE_SIZE.store(size, Ordering::Relaxed);
|
||||||
|
size
|
||||||
|
}
|
||||||
|
n => n,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn get_page_size() -> usize {
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
use windows_sys::Win32::System::SystemInformation::*;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut info = MaybeUninit::uninit();
|
||||||
|
GetSystemInfo(info.as_mut_ptr());
|
||||||
|
info.assume_init_ref().dwPageSize as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn get_page_size() -> usize {
|
||||||
|
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ impl Mmap {
|
|||||||
|
|
||||||
/// Create a new `Mmap` pointing to at least `size` bytes of page-aligned accessible memory.
|
/// Create a new `Mmap` pointing to at least `size` bytes of page-aligned accessible memory.
|
||||||
pub fn with_at_least(size: usize) -> Result<Self> {
|
pub fn with_at_least(size: usize) -> Result<Self> {
|
||||||
let rounded_size = region::page::ceil(size);
|
let page_size = crate::page_size();
|
||||||
|
let rounded_size = (size + (page_size - 1)) & !(page_size - 1);
|
||||||
Self::accessible_reserved(rounded_size, rounded_size)
|
Self::accessible_reserved(rounded_size, rounded_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ impl Mmap {
|
|||||||
/// must be native page-size multiples.
|
/// must be native page-size multiples.
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
pub fn accessible_reserved(accessible_size: usize, mapping_size: usize) -> Result<Self> {
|
pub fn accessible_reserved(accessible_size: usize, mapping_size: usize) -> Result<Self> {
|
||||||
let page_size = region::page::size();
|
let page_size = crate::page_size();
|
||||||
assert_le!(accessible_size, mapping_size);
|
assert_le!(accessible_size, mapping_size);
|
||||||
assert_eq!(mapping_size & (page_size - 1), 0);
|
assert_eq!(mapping_size & (page_size - 1), 0);
|
||||||
assert_eq!(accessible_size & (page_size - 1), 0);
|
assert_eq!(accessible_size & (page_size - 1), 0);
|
||||||
@@ -226,7 +227,7 @@ impl Mmap {
|
|||||||
return Ok(Self::new());
|
return Ok(Self::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let page_size = region::page::size();
|
let page_size = crate::page_size();
|
||||||
assert_le!(accessible_size, mapping_size);
|
assert_le!(accessible_size, mapping_size);
|
||||||
assert_eq!(mapping_size & (page_size - 1), 0);
|
assert_eq!(mapping_size & (page_size - 1), 0);
|
||||||
assert_eq!(accessible_size & (page_size - 1), 0);
|
assert_eq!(accessible_size & (page_size - 1), 0);
|
||||||
@@ -278,16 +279,22 @@ impl Mmap {
|
|||||||
/// `self`'s reserved memory.
|
/// `self`'s reserved memory.
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
pub fn make_accessible(&mut self, start: usize, len: usize) -> Result<()> {
|
pub fn make_accessible(&mut self, start: usize, len: usize) -> Result<()> {
|
||||||
let page_size = region::page::size();
|
use rustix::mm::{mprotect, MprotectFlags};
|
||||||
|
|
||||||
|
let page_size = crate::page_size();
|
||||||
assert_eq!(start & (page_size - 1), 0);
|
assert_eq!(start & (page_size - 1), 0);
|
||||||
assert_eq!(len & (page_size - 1), 0);
|
assert_eq!(len & (page_size - 1), 0);
|
||||||
assert_le!(len, self.len);
|
assert_le!(len, self.len);
|
||||||
assert_le!(start, self.len - len);
|
assert_le!(start, self.len - len);
|
||||||
|
|
||||||
// Commit the accessible size.
|
// Commit the accessible size.
|
||||||
let ptr = self.ptr as *const u8;
|
let ptr = self.ptr as *mut u8;
|
||||||
unsafe {
|
unsafe {
|
||||||
region::protect(ptr.add(start), len, region::Protection::READ_WRITE)?;
|
mprotect(
|
||||||
|
ptr.add(start).cast(),
|
||||||
|
len,
|
||||||
|
MprotectFlags::READ | MprotectFlags::WRITE,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -303,7 +310,7 @@ impl Mmap {
|
|||||||
use std::io;
|
use std::io;
|
||||||
use windows_sys::Win32::System::Memory::*;
|
use windows_sys::Win32::System::Memory::*;
|
||||||
|
|
||||||
let page_size = region::page::size();
|
let page_size = crate::page_size();
|
||||||
assert_eq!(start & (page_size - 1), 0);
|
assert_eq!(start & (page_size - 1), 0);
|
||||||
assert_eq!(len & (page_size - 1), 0);
|
assert_eq!(len & (page_size - 1), 0);
|
||||||
assert_le!(len, self.len);
|
assert_le!(len, self.len);
|
||||||
@@ -370,11 +377,11 @@ impl Mmap {
|
|||||||
assert!(range.end <= self.len());
|
assert!(range.end <= self.len());
|
||||||
assert!(range.start <= range.end);
|
assert!(range.start <= range.end);
|
||||||
assert!(
|
assert!(
|
||||||
range.start % region::page::size() == 0,
|
range.start % crate::page_size() == 0,
|
||||||
"changing of protections isn't page-aligned",
|
"changing of protections isn't page-aligned",
|
||||||
);
|
);
|
||||||
|
|
||||||
let base = self.as_ptr().add(range.start);
|
let base = self.as_ptr().add(range.start) as *mut _;
|
||||||
let len = range.end - range.start;
|
let len = range.end - range.start;
|
||||||
|
|
||||||
// On Windows when we have a file mapping we need to specifically use
|
// On Windows when we have a file mapping we need to specifically use
|
||||||
@@ -385,19 +392,23 @@ impl Mmap {
|
|||||||
use std::io;
|
use std::io;
|
||||||
use windows_sys::Win32::System::Memory::*;
|
use windows_sys::Win32::System::Memory::*;
|
||||||
|
|
||||||
if self.file.is_some() {
|
let mut old = 0;
|
||||||
let mut old = 0;
|
let result = if self.file.is_some() {
|
||||||
if VirtualProtect(base as *mut _, len, PAGE_WRITECOPY, &mut old) == 0 {
|
VirtualProtect(base, len, PAGE_WRITECOPY, &mut old)
|
||||||
return Err(io::Error::last_os_error())
|
} else {
|
||||||
.context("failed to change pages to `PAGE_WRITECOPY`");
|
VirtualProtect(base, len, PAGE_READWRITE, &mut old)
|
||||||
}
|
};
|
||||||
return Ok(());
|
if result == 0 {
|
||||||
|
return Err(io::Error::last_os_error().into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're not on Windows or if we're on Windows with an anonymous
|
#[cfg(not(windows))]
|
||||||
// mapping then we can use the `region` crate.
|
{
|
||||||
region::protect(base, len, region::Protection::READ_WRITE)?;
|
use rustix::mm::{mprotect, MprotectFlags};
|
||||||
|
mprotect(base, len, MprotectFlags::READ | MprotectFlags::WRITE)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,15 +418,29 @@ impl Mmap {
|
|||||||
assert!(range.end <= self.len());
|
assert!(range.end <= self.len());
|
||||||
assert!(range.start <= range.end);
|
assert!(range.start <= range.end);
|
||||||
assert!(
|
assert!(
|
||||||
range.start % region::page::size() == 0,
|
range.start % crate::page_size() == 0,
|
||||||
"changing of protections isn't page-aligned",
|
"changing of protections isn't page-aligned",
|
||||||
);
|
);
|
||||||
|
let base = self.as_ptr().add(range.start) as *mut _;
|
||||||
|
let len = range.end - range.start;
|
||||||
|
|
||||||
region::protect(
|
#[cfg(windows)]
|
||||||
self.as_ptr().add(range.start),
|
{
|
||||||
range.end - range.start,
|
use std::io;
|
||||||
region::Protection::READ_EXECUTE,
|
use windows_sys::Win32::System::Memory::*;
|
||||||
)?;
|
|
||||||
|
let mut old = 0;
|
||||||
|
let result = VirtualProtect(base, len, PAGE_EXECUTE_READ, &mut old);
|
||||||
|
if result == 0 {
|
||||||
|
return Err(io::Error::last_os_error().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
{
|
||||||
|
use rustix::mm::{mprotect, MprotectFlags};
|
||||||
|
mprotect(base, len, MprotectFlags::READ | MprotectFlags::EXEC)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ pub fn lazy_per_thread_init() {
|
|||||||
|
|
||||||
// ... but failing that we need to allocate our own, so do all that
|
// ... but failing that we need to allocate our own, so do all that
|
||||||
// here.
|
// here.
|
||||||
let page_size: usize = region::page::size();
|
let page_size = crate::page_size();
|
||||||
let guard_size = page_size;
|
let guard_size = page_size;
|
||||||
let alloc_size = guard_size + MIN_STACK_SIZE;
|
let alloc_size = guard_size + MIN_STACK_SIZE;
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ wasmtime-component-macro = { path = "../component-macro", version = "=0.40.0", o
|
|||||||
target-lexicon = { version = "0.12.0", default-features = false }
|
target-lexicon = { version = "0.12.0", default-features = false }
|
||||||
wasmparser = "0.87.0"
|
wasmparser = "0.87.0"
|
||||||
anyhow = "1.0.19"
|
anyhow = "1.0.19"
|
||||||
region = "2.2.0"
|
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
backtrace = { version = "0.3.61" }
|
backtrace = { version = "0.3.61" }
|
||||||
|
|||||||
@@ -1458,7 +1458,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn round_up_to_pages(val: u64) -> u64 {
|
fn round_up_to_pages(val: u64) -> u64 {
|
||||||
let page_size = region::page::size() as u64;
|
let page_size = wasmtime_runtime::page_size() as u64;
|
||||||
debug_assert!(page_size.is_power_of_two());
|
debug_assert!(page_size.is_power_of_two());
|
||||||
val.checked_add(page_size - 1)
|
val.checked_add(page_size - 1)
|
||||||
.map(|val| val & !(page_size - 1))
|
.map(|val| val & !(page_size - 1))
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ fn custom_limiter_detect_os_oom_failure() -> Result<()> {
|
|||||||
// The memory_grow_failed hook should show Linux gave OOM:
|
// The memory_grow_failed hook should show Linux gave OOM:
|
||||||
let err_msg = store.data().error.as_ref().unwrap();
|
let err_msg = store.data().error.as_ref().unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
err_msg.starts_with("System call failed: Cannot allocate memory"),
|
err_msg.starts_with("Cannot allocate memory"),
|
||||||
"unexpected error: {}",
|
"unexpected error: {}",
|
||||||
err_msg
|
err_msg
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user