diff --git a/crates/environ/src/obj.rs b/crates/environ/src/obj.rs index 72ce32fd2e87..a501ddf57fe5 100644 --- a/crates/environ/src/obj.rs +++ b/crates/environ/src/obj.rs @@ -15,6 +15,12 @@ pub const EF_WASMTIME_MODULE: u32 = 1 << 0; /// component. pub const EF_WASMTIME_COMPONENT: u32 = 1 << 1; +/// Flag for the `sh_flags` field in the ELF text section that indicates that +/// the text section does not itself need to be executable. This is used for the +/// Pulley target, for example, to indicate that it does not need to be made +/// natively executable as it does not contain actual native code. +pub const SH_WASMTIME_NOT_EXECUTED: u64 = 1 << 0; + /// A custom Wasmtime-specific section of our compilation image which stores /// mapping data from offsets in the image to offset in the original wasm /// binary. diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 59172f9de8bf..e9e530ca719b 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -188,7 +188,11 @@ async = [ ] # Enables support for the pooling instance allocation strategy -pooling-allocator = ["runtime", "std"] +pooling-allocator = [ + "runtime", + "std", # not ported to no_std yet + "signals-based-traps", # pooling allocation always uses mmap at this time +] # Enables support for all architectures in Cranelift, allowing # cross-compilation using the `wasmtime` crate's API, notably the @@ -236,7 +240,6 @@ runtime = [ "dep:mach2", "dep:memfd", "dep:wasmtime-asm-macros", - "dep:wasmtime-jit-icache-coherence", "dep:wasmtime-slab", "dep:wasmtime-versioned-export-macros", "dep:windows-sys", @@ -263,7 +266,11 @@ runtime = [ # # You can additionally configure which GC implementations are enabled via the # `gc-drc` and `gc-null` features. -gc = ["wasmtime-environ/gc", "wasmtime-cranelift?/gc"] +gc = [ + "wasmtime-environ/gc", + "wasmtime-cranelift?/gc", + "signals-based-traps", # not ported to non-mmap schemes yet +] # Enable the deferred reference counting garbage collector. gc-drc = ["gc", "wasmtime-environ/gc-drc", "wasmtime-cranelift?/gc-drc"] @@ -325,4 +332,6 @@ reexport-wasmparser = [] # of implementations within Wasmtime that may rely on virtual memory, for # example. Embedded systems or smaller systems may wish to disable this feature # to reduce the runtime requirements of Wasmtime. -signals-based-traps = [] +signals-based-traps = [ + "dep:wasmtime-jit-icache-coherence", +] diff --git a/crates/wasmtime/src/runtime/code_memory.rs b/crates/wasmtime/src/runtime/code_memory.rs index 5ca7afdaf155..04ade1c15466 100644 --- a/crates/wasmtime/src/runtime/code_memory.rs +++ b/crates/wasmtime/src/runtime/code_memory.rs @@ -5,9 +5,8 @@ use crate::runtime::vm::{libcalls, MmapVec, UnwindRegistration}; use core::ops::Range; use object::endian::NativeEndian; use object::read::{elf::ElfFile64, Object, ObjectSection}; -use object::ObjectSymbol; +use object::{ObjectSymbol, SectionFlags}; use wasmtime_environ::{lookup_trap_code, obj, Trap}; -use wasmtime_jit_icache_coherence as icache_coherence; /// Management of executable memory within a `MmapVec` /// @@ -20,6 +19,7 @@ pub struct CodeMemory { debug_registration: Option, published: bool, enable_branch_protection: bool, + needs_executable: bool, #[cfg(feature = "debug-builtins")] has_native_debug_info: bool, @@ -65,6 +65,7 @@ impl CodeMemory { let mut text = 0..0; let mut unwind = 0..0; let mut enable_branch_protection = None; + let mut needs_executable = true; #[cfg(feature = "debug-builtins")] let mut has_native_debug_info = false; let mut trap_data = 0..0; @@ -97,6 +98,12 @@ impl CodeMemory { ".text" => { text = range; + if let SectionFlags::Elf { sh_flags } = section.flags() { + if sh_flags & obj::SH_WASMTIME_NOT_EXECUTED != 0 { + needs_executable = false; + } + } + // The text section might have relocations for things like // libcalls which need to be applied, so handle those here. // @@ -141,6 +148,7 @@ impl CodeMemory { published: false, enable_branch_protection: enable_branch_protection .ok_or_else(|| anyhow!("missing `{}` section", obj::ELF_WASM_BTI))?, + needs_executable, #[cfg(feature = "debug-builtins")] has_native_debug_info, text, @@ -253,24 +261,38 @@ impl CodeMemory { // loaded-from-disk images this shouldn't result in IPIs so long as // there weren't any relocations because nothing should have // otherwise written to the image at any point either. + // + // Note that if virtual memory is disabled this is skipped because + // we aren't able to make it readonly, but this is just a + // defense-in-depth measure and isn't required for correctness. + #[cfg(feature = "signals-based-traps")] self.mmap.make_readonly(0..self.mmap.len())?; - let text = self.text(); + // Switch the executable portion from readonly to read/execute. + if self.needs_executable { + #[cfg(feature = "signals-based-traps")] + { + let text = self.text(); - // Clear the newly allocated code from cache if the processor requires it - // - // Do this before marking the memory as R+X, technically we should be able to do it after - // but there are some CPU's that have had errata about doing this with read only memory. - icache_coherence::clear_cache(text.as_ptr().cast(), text.len()) - .expect("Failed cache clear"); + use wasmtime_jit_icache_coherence as icache_coherence; - // Switch the executable portion from readonly to read/execute. - self.mmap - .make_executable(self.text.clone(), self.enable_branch_protection) - .context("unable to make memory executable")?; + // Clear the newly allocated code from cache if the processor requires it + // + // Do this before marking the memory as R+X, technically we should be able to do it after + // but there are some CPU's that have had errata about doing this with read only memory. + icache_coherence::clear_cache(text.as_ptr().cast(), text.len()) + .expect("Failed cache clear"); + + self.mmap + .make_executable(self.text.clone(), self.enable_branch_protection) + .context("unable to make memory executable")?; - // Flush any in-flight instructions from the pipeline - icache_coherence::pipeline_flush_mt().expect("Failed pipeline flush"); + // Flush any in-flight instructions from the pipeline + icache_coherence::pipeline_flush_mt().expect("Failed pipeline flush"); + } + #[cfg(not(feature = "signals-based-traps"))] + bail!("this target requires virtual memory to be enabled"); + } // With all our memory set up use the platform-specific // `UnwindRegistration` implementation to inform the general diff --git a/crates/wasmtime/src/runtime/vm.rs b/crates/wasmtime/src/runtime/vm.rs index 61088c5cfe64..9d582fc05b8f 100644 --- a/crates/wasmtime/src/runtime/vm.rs +++ b/crates/wasmtime/src/runtime/vm.rs @@ -29,7 +29,6 @@ mod gc; mod imports; mod instance; mod memory; -mod mmap; mod mmap_vec; mod send_sync_ptr; mod send_sync_unsafe_cell; @@ -68,7 +67,6 @@ pub use crate::runtime::vm::instance::{ pub use crate::runtime::vm::memory::{ Memory, RuntimeLinearMemory, RuntimeMemoryCreator, SharedMemory, }; -pub use crate::runtime::vm::mmap::Mmap; pub use crate::runtime::vm::mmap_vec::MmapVec; pub use crate::runtime::vm::mpk::MpkEnabled; pub use crate::runtime::vm::store_box::*; @@ -86,8 +84,21 @@ pub use send_sync_unsafe_cell::SendSyncUnsafeCell; mod module_id; pub use module_id::CompiledModuleId; +#[cfg(feature = "signals-based-traps")] mod cow; -pub use crate::runtime::vm::cow::{MemoryImage, MemoryImageSlot, ModuleMemoryImages}; +#[cfg(not(feature = "signals-based-traps"))] +mod cow_disabled; +#[cfg(feature = "signals-based-traps")] +mod mmap; + +cfg_if::cfg_if! { + if #[cfg(feature = "signals-based-traps")] { + pub use crate::runtime::vm::mmap::Mmap; + pub use self::cow::{MemoryImage, MemoryImageSlot, ModuleMemoryImages}; + } else { + pub use self::cow_disabled::{MemoryImage, MemoryImageSlot, ModuleMemoryImages}; + } +} /// Dynamic runtime functionality needed by this crate throughout the execution /// of a wasm instance. @@ -337,6 +348,7 @@ impl ModuleRuntimeInfo { } /// Returns the host OS page size, in bytes. +#[cfg(feature = "signals-based-traps")] pub fn host_page_size() -> usize { static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); @@ -352,6 +364,7 @@ pub fn host_page_size() -> usize { } /// Is `bytes` a multiple of the host page size? +#[cfg(feature = "signals-based-traps")] pub fn usize_is_multiple_of_host_page_size(bytes: usize) -> bool { bytes % host_page_size() == 0 } @@ -359,6 +372,7 @@ pub fn usize_is_multiple_of_host_page_size(bytes: usize) -> bool { /// Round the given byte size up to a multiple of the host OS page size. /// /// Returns an error if rounding up overflows. +#[cfg(feature = "signals-based-traps")] pub fn round_u64_up_to_host_pages(bytes: u64) -> Result { let page_size = u64::try_from(crate::runtime::vm::host_page_size()).err2anyhow()?; debug_assert!(page_size.is_power_of_two()); @@ -371,6 +385,7 @@ pub fn round_u64_up_to_host_pages(bytes: u64) -> Result { } /// Same as `round_u64_up_to_host_pages` but for `usize`s. +#[cfg(feature = "signals-based-traps")] pub fn round_usize_up_to_host_pages(bytes: usize) -> Result { let bytes = u64::try_from(bytes).err2anyhow()?; let rounded = round_u64_up_to_host_pages(bytes)?; diff --git a/crates/wasmtime/src/runtime/vm/cow_disabled.rs b/crates/wasmtime/src/runtime/vm/cow_disabled.rs new file mode 100644 index 000000000000..8789380deb99 --- /dev/null +++ b/crates/wasmtime/src/runtime/vm/cow_disabled.rs @@ -0,0 +1,46 @@ +//! Small shims for CoW support when virtual memory is disabled, meaning that +//! none of the types in this module are supported. + +#![warn(dead_code, unused_imports)] + +use crate::prelude::*; +use crate::runtime::vm::MmapVec; +use alloc::sync::Arc; +use wasmtime_environ::{DefinedMemoryIndex, Module}; + +pub enum ModuleMemoryImages {} + +impl ModuleMemoryImages { + pub fn get_memory_image( + &self, + _defined_index: DefinedMemoryIndex, + ) -> Option<&Arc> { + None + } +} + +#[derive(Debug, PartialEq)] +pub enum MemoryImage {} + +impl ModuleMemoryImages { + pub fn new( + _module: &Module, + _wasm_data: &[u8], + _mmap: Option<&MmapVec>, + ) -> Result> { + Ok(None) + } +} + +#[derive(Debug)] +pub enum MemoryImageSlot {} + +impl MemoryImageSlot { + pub(crate) fn set_heap_limit(&mut self, _size_bytes: usize) -> Result<()> { + match *self {} + } + + pub(crate) fn has_image(&self) -> bool { + match *self {} + } +} diff --git a/crates/wasmtime/src/runtime/vm/memory.rs b/crates/wasmtime/src/runtime/vm/memory.rs index f89915b01c2f..585c46dd5523 100644 --- a/crates/wasmtime/src/runtime/vm/memory.rs +++ b/crates/wasmtime/src/runtime/vm/memory.rs @@ -82,7 +82,9 @@ use core::ops::Range; use core::time::Duration; use wasmtime_environ::{Trap, Tunables}; +#[cfg(feature = "signals-based-traps")] mod mmap; +#[cfg(feature = "signals-based-traps")] pub use self::mmap::MmapMemory; mod malloc; @@ -125,11 +127,13 @@ impl RuntimeMemoryCreator for DefaultMemoryCreator { minimum: usize, maximum: Option, ) -> Result> { + #[cfg(feature = "signals-based-traps")] if tunables.signals_based_traps || tunables.memory_guard_size > 0 { - Ok(Box::new(MmapMemory::new(ty, tunables, minimum, maximum)?)) - } else { - Ok(Box::new(MallocMemory::new(ty, tunables, minimum)?)) + return Ok(Box::new(MmapMemory::new(ty, tunables, minimum, maximum)?)); } + + let _ = maximum; + Ok(Box::new(MallocMemory::new(ty, tunables, minimum)?)) } } @@ -471,6 +475,7 @@ impl LocalMemory { // If a memory image was specified, try to create the MemoryImageSlot on // top of our mmap. let memory_image = match memory_image { + #[cfg(feature = "signals-based-traps")] Some(image) => { let mut slot = MemoryImageSlot::create( alloc.base_ptr().cast(), @@ -484,6 +489,8 @@ impl LocalMemory { slot.instantiate(alloc.byte_size(), Some(image), ty, tunables)?; Some(slot) } + #[cfg(not(feature = "signals-based-traps"))] + Some(_) => unreachable!(), None => None, }; Ok(LocalMemory { diff --git a/crates/wasmtime/src/runtime/vm/mmap.rs b/crates/wasmtime/src/runtime/vm/mmap.rs index ef0ead8e7507..4696bd7ee2c2 100644 --- a/crates/wasmtime/src/runtime/vm/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/mmap.rs @@ -156,11 +156,6 @@ impl Mmap { self.sys.len() } - /// Return whether any memory has been allocated or reserved. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - /// Makes the specified `range` within this `Mmap` to be read/execute. /// /// # Unsafety diff --git a/crates/wasmtime/src/runtime/vm/mmap_vec.rs b/crates/wasmtime/src/runtime/vm/mmap_vec.rs index 6c67eadc1aaf..c024714cf633 100644 --- a/crates/wasmtime/src/runtime/vm/mmap_vec.rs +++ b/crates/wasmtime/src/runtime/vm/mmap_vec.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +#[cfg(feature = "signals-based-traps")] use crate::runtime::vm::Mmap; use alloc::sync::Arc; use core::ops::{Deref, DerefMut, Range}; @@ -15,32 +16,53 @@ use std::{fs::File, path::Path}; /// /// An `MmapVec` is an owned value which means that owners have the ability to /// get exclusive access to the underlying bytes, enabling mutation. +/// +/// TODO: rename this type and reword docs now that this isn't always an mmap. pub struct MmapVec { - mmap: Arc, + mmap: Arc, range: Range, } +enum MmapVecStorage { + #[cfg(not(feature = "signals-based-traps"))] + Vec(Vec), + #[cfg(feature = "signals-based-traps")] + Mmap(Mmap), +} + impl MmapVec { /// Consumes an existing `mmap` and wraps it up into an `MmapVec`. /// /// The returned `MmapVec` will have the `size` specified, which can be /// smaller than the region mapped by the `Mmap`. The returned `MmapVec` /// will only have at most `size` bytes accessible. - pub fn new(mmap: Mmap, size: usize) -> MmapVec { + #[cfg(feature = "signals-based-traps")] + fn new_mmap(mmap: Mmap, size: usize) -> MmapVec { assert!(size <= mmap.len()); MmapVec { - mmap: Arc::new(mmap), + mmap: Arc::new(MmapVecStorage::Mmap(mmap)), range: 0..size, } } + #[cfg(not(feature = "signals-based-traps"))] + fn new_vec(vec: Vec) -> MmapVec { + MmapVec { + range: 0..vec.len(), + mmap: Arc::new(MmapVecStorage::Vec(vec)), + } + } + /// Creates a new zero-initialized `MmapVec` with the given `size`. /// /// This commit will return a new `MmapVec` suitably sized to hold `size` /// bytes. All bytes will be initialized to zero since this is a fresh OS /// page allocation. pub fn with_capacity(size: usize) -> Result { - Ok(MmapVec::new(Mmap::with_at_least(size)?, size)) + #[cfg(feature = "signals-based-traps")] + return Ok(MmapVec::new_mmap(Mmap::with_at_least(size)?, size)); + #[cfg(not(feature = "signals-based-traps"))] + return Ok(MmapVec::new_vec(vec![0; size])); } /// Creates a new `MmapVec` from the contents of an existing `slice`. @@ -63,13 +85,23 @@ impl MmapVec { /// it's too large to be fully mapped into memory. #[cfg(feature = "std")] pub fn from_file(path: &Path) -> Result { - let mmap = Mmap::from_file(path) - .with_context(|| format!("failed to create mmap for file: {}", path.display()))?; - let len = mmap.len(); - Ok(MmapVec::new(mmap, len)) + #[cfg(feature = "signals-based-traps")] + { + let mmap = Mmap::from_file(path) + .with_context(|| format!("failed to create mmap for file: {}", path.display()))?; + let len = mmap.len(); + Ok(MmapVec::new_mmap(mmap, len)) + } + #[cfg(not(feature = "signals-based-traps"))] + { + let contents = std::fs::read(path) + .with_context(|| format!("failed to create mmap for file: {}", path.display()))?; + Ok(MmapVec::new_vec(contents)) + } } /// Makes the specified `range` within this `mmap` to be read/execute. + #[cfg(feature = "signals-based-traps")] pub unsafe fn make_executable( &self, range: Range, @@ -77,24 +109,35 @@ impl MmapVec { ) -> Result<()> { assert!(range.start <= range.end); assert!(range.end <= self.range.len()); - self.mmap.make_executable( + let mmap = match &*self.mmap { + MmapVecStorage::Mmap(m) => m, + }; + mmap.make_executable( range.start + self.range.start..range.end + self.range.start, enable_branch_protection, ) } /// Makes the specified `range` within this `mmap` to be read-only. + #[cfg(feature = "signals-based-traps")] pub unsafe fn make_readonly(&self, range: Range) -> Result<()> { assert!(range.start <= range.end); assert!(range.end <= self.range.len()); - self.mmap - .make_readonly(range.start + self.range.start..range.end + self.range.start) + let mmap = match &*self.mmap { + MmapVecStorage::Mmap(m) => m, + }; + mmap.make_readonly(range.start + self.range.start..range.end + self.range.start) } /// Returns the underlying file that this mmap is mapping, if present. #[cfg(feature = "std")] pub fn original_file(&self) -> Option<&Arc> { - self.mmap.original_file() + match &*self.mmap { + #[cfg(not(feature = "signals-based-traps"))] + MmapVecStorage::Vec(_) => None, + #[cfg(feature = "signals-based-traps")] + MmapVecStorage::Mmap(m) => m.original_file(), + } } /// Returns the offset within the original mmap that this `MmapVec` is @@ -117,9 +160,16 @@ impl Deref for MmapVec { #[inline] fn deref(&self) -> &[u8] { - // SAFETY: this mmap owns its own range of the underlying mmap so it - // should be all good-to-read. - unsafe { self.mmap.slice(self.range.clone()) } + match &*self.mmap { + #[cfg(not(feature = "signals-based-traps"))] + MmapVecStorage::Vec(v) => v, + #[cfg(feature = "signals-based-traps")] + MmapVecStorage::Mmap(m) => { + // SAFETY: this mmap owns its own range of the underlying mmap so it + // should be all good-to-read. + unsafe { m.slice(self.range.clone()) } + } + } } } @@ -133,8 +183,16 @@ impl DerefMut for MmapVec { // specified in `self.range`. This should allow us to safely hand out // mutable access to these bytes if so desired. unsafe { - let slice = - core::slice::from_raw_parts_mut(self.mmap.as_ptr().cast_mut(), self.mmap.len()); + let slice = match &*self.mmap { + #[cfg(not(feature = "signals-based-traps"))] + MmapVecStorage::Vec(v) => { + core::slice::from_raw_parts_mut(v.as_ptr().cast_mut(), v.len()) + } + #[cfg(feature = "signals-based-traps")] + MmapVecStorage::Mmap(m) => { + core::slice::from_raw_parts_mut(m.as_ptr().cast_mut(), m.len()) + } + }; &mut slice[self.range.clone()] } } diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs b/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs index b1e3fc01dbd2..9bcd07f1c279 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs @@ -3,10 +3,13 @@ // Flags to either `wasmtime_mmap_{new,remap}` or `wasmtime_mprotect`. /// Indicates that the memory region should be readable. +#[cfg(feature = "signals-based-traps")] pub const WASMTIME_PROT_READ: u32 = 1 << 0; /// Indicates that the memory region should be writable. +#[cfg(feature = "signals-based-traps")] pub const WASMTIME_PROT_WRITE: u32 = 1 << 1; /// Indicates that the memory region should be executable. +#[cfg(feature = "signals-based-traps")] pub const WASMTIME_PROT_EXEC: u32 = 1 << 2; pub use WASMTIME_PROT_EXEC as PROT_EXEC; @@ -43,6 +46,7 @@ pub type wasmtime_trap_handler_t = /// Abstract pointer type used in the `wasmtime_memory_image_*` APIs which /// is defined by the embedder. +#[cfg(feature = "signals-based-traps")] pub enum wasmtime_memory_image {} extern "C" { @@ -56,6 +60,7 @@ extern "C" { /// Returns 0 on success and an error code on failure. /// /// Similar to `mmap(0, size, prot_flags, MAP_PRIVATE, 0, -1)` on Linux. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_mmap_new(size: usize, prot_flags: u32, ret: &mut *mut u8) -> i32; /// Remaps the virtual memory starting at `addr` going for `size` bytes to @@ -68,6 +73,7 @@ extern "C" { /// Returns 0 on success and an error code on failure. /// /// Similar to `mmap(addr, size, prot_flags, MAP_PRIVATE | MAP_FIXED, 0, -1)` on Linux. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_mmap_remap(addr: *mut u8, size: usize, prot_flags: u32) -> i32; /// Unmaps memory at the specified `ptr` for `size` bytes. @@ -78,6 +84,7 @@ extern "C" { /// Returns 0 on success and an error code on failure. /// /// Similar to `munmap` on Linux. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_munmap(ptr: *mut u8, size: usize) -> i32; /// Configures the protections associated with a region of virtual memory @@ -86,9 +93,11 @@ extern "C" { /// Returns 0 on success and an error code on failure. /// /// Similar to `mprotect` on Linux. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_mprotect(ptr: *mut u8, size: usize, prot_flags: u32) -> i32; /// Returns the page size, in bytes, of the current system. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_page_size() -> usize; /// Used to setup a frame on the stack to longjmp back to in the future. @@ -157,6 +166,7 @@ extern "C" { /// `NULL` into `ret` is not considered a failure, and failure is used to /// indicate that something fatal has happened and Wasmtime will propagate /// the error upwards. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_memory_image_new( ptr: *const u8, len: usize, @@ -177,6 +187,7 @@ extern "C" { /// the future. /// /// Aborts the process on failure. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_memory_image_map_at( image: *mut wasmtime_memory_image, addr: *mut u8, @@ -187,6 +198,7 @@ extern "C" { /// /// Note that mappings created from this image are not guaranteed to be /// deallocated and/or unmapped before this is called. + #[cfg(feature = "signals-based-traps")] pub fn wasmtime_memory_image_free(image: *mut wasmtime_memory_image); /// Wasmtime requires a single pointer's space of TLS to be used at runtime, diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs b/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs index ba77a1c94c87..3c8fbcccae5d 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs @@ -5,9 +5,11 @@ use core::cell::Cell; +#[cfg(feature = "signals-based-traps")] pub mod mmap; pub mod traphandlers; pub mod unwind; +#[cfg(feature = "signals-based-traps")] pub mod vm; #[cfg(all(feature = "signals-based-traps", target_os = "macos"))] diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs b/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs index 6615e08926e0..cf7a1d65203e 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs @@ -55,6 +55,7 @@ impl UnwindRegistration { unwind_info: *const u8, unwind_len: usize, ) -> Result { + #[cfg(feature = "signals-based-traps")] debug_assert_eq!( unwind_info as usize % crate::runtime::vm::host_page_size(), 0, diff --git a/examples/min-platform/embedding/wasmtime-platform.c b/examples/min-platform/embedding/wasmtime-platform.c index 0b2820b915bb..c6e7c38c46eb 100644 --- a/examples/min-platform/embedding/wasmtime-platform.c +++ b/examples/min-platform/embedding/wasmtime-platform.c @@ -9,6 +9,8 @@ #include "wasmtime-platform.h" +#ifdef WASMTIME_SIGNALS_BASED_TRAPS + static int wasmtime_to_mmap_prot_flags(uint32_t prot_flags) { int flags = 0; if (prot_flags & WASMTIME_PROT_READ) @@ -53,6 +55,8 @@ int wasmtime_mprotect(uint8_t *ptr, uintptr_t size, uint32_t prot_flags) { uintptr_t wasmtime_page_size(void) { return sysconf(_SC_PAGESIZE); } +#endif // WASMTIME_SIGNALS_BASED_TRAPS + int32_t wasmtime_setjmp(const uint8_t **jmp_buf_out, void (*callback)(uint8_t *, uint8_t *), uint8_t *payload, uint8_t *callee) { @@ -121,8 +125,6 @@ int wasmtime_init_traps(wasmtime_trap_handler_t handler) { return 0; } -#endif // WASMTIME_SIGNALS_BASED_TRAPS - int wasmtime_memory_image_new(const uint8_t *ptr, uintptr_t len, struct wasmtime_memory_image **ret) { *ret = NULL; @@ -138,6 +140,8 @@ void wasmtime_memory_image_free(struct wasmtime_memory_image *image) { abort(); } +#endif // WASMTIME_SIGNALS_BASED_TRAPS + // Pretend that this platform doesn't have threads where storing in a static is // ok. static uint8_t *WASMTIME_TLS = NULL; diff --git a/examples/min-platform/embedding/wasmtime-platform.h b/examples/min-platform/embedding/wasmtime-platform.h index 58ca3caeaf4f..a4996bdf9237 100644 --- a/examples/min-platform/embedding/wasmtime-platform.h +++ b/examples/min-platform/embedding/wasmtime-platform.h @@ -30,26 +30,34 @@ #include #include +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Indicates that the memory region should be readable. */ #define WASMTIME_PROT_READ (1 << 0) +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Indicates that the memory region should be writable. */ #define WASMTIME_PROT_WRITE (1 << 1) +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Indicates that the memory region should be executable. */ #define WASMTIME_PROT_EXEC (1 << 2) +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Abstract pointer type used in the `wasmtime_memory_image_*` APIs which * is defined by the embedder. */ typedef struct wasmtime_memory_image wasmtime_memory_image; +#endif #if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** @@ -88,6 +96,7 @@ typedef void (*wasmtime_trap_handler_t)(uintptr_t ip, extern "C" { #endif // __cplusplus +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Creates a new virtual memory mapping of the `size` specified with * protection bits specified in `prot_flags`. @@ -101,7 +110,9 @@ extern "C" { * Similar to `mmap(0, size, prot_flags, MAP_PRIVATE, 0, -1)` on Linux. */ extern int32_t wasmtime_mmap_new(uintptr_t size, uint32_t prot_flags, uint8_t **ret); +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Remaps the virtual memory starting at `addr` going for `size` bytes to * the protections specified with a new blank mapping. @@ -115,7 +126,9 @@ extern int32_t wasmtime_mmap_new(uintptr_t size, uint32_t prot_flags, uint8_t ** * Similar to `mmap(addr, size, prot_flags, MAP_PRIVATE | MAP_FIXED, 0, -1)` on Linux. */ extern int32_t wasmtime_mmap_remap(uint8_t *addr, uintptr_t size, uint32_t prot_flags); +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Unmaps memory at the specified `ptr` for `size` bytes. * @@ -127,7 +140,9 @@ extern int32_t wasmtime_mmap_remap(uint8_t *addr, uintptr_t size, uint32_t prot_ * Similar to `munmap` on Linux. */ extern int32_t wasmtime_munmap(uint8_t *ptr, uintptr_t size); +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Configures the protections associated with a region of virtual memory * starting at `ptr` and going to `size`. @@ -137,11 +152,14 @@ extern int32_t wasmtime_munmap(uint8_t *ptr, uintptr_t size); * Similar to `mprotect` on Linux. */ extern int32_t wasmtime_mprotect(uint8_t *ptr, uintptr_t size, uint32_t prot_flags); +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Returns the page size, in bytes, of the current system. */ extern uintptr_t wasmtime_page_size(void); +#endif /** * Used to setup a frame on the stack to longjmp back to in the future. @@ -195,6 +213,7 @@ extern void wasmtime_longjmp(const uint8_t *jmp_buf); extern int32_t wasmtime_init_traps(wasmtime_trap_handler_t handler); #endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Attempts to create a new in-memory image of the `ptr`/`len` combo which * can be mapped to virtual addresses in the future. @@ -219,7 +238,9 @@ extern int32_t wasmtime_init_traps(wasmtime_trap_handler_t handler); extern int32_t wasmtime_memory_image_new(const uint8_t *ptr, uintptr_t len, struct wasmtime_memory_image **ret); +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Maps the `image` provided to the virtual address at `addr` and `len`. * @@ -239,7 +260,9 @@ extern int32_t wasmtime_memory_image_new(const uint8_t *ptr, extern int32_t wasmtime_memory_image_map_at(struct wasmtime_memory_image *image, uint8_t *addr, uintptr_t len); +#endif +#if defined(WASMTIME_SIGNALS_BASED_TRAPS) /** * Deallocates the provided `wasmtime_memory_image`. * @@ -247,6 +270,7 @@ extern int32_t wasmtime_memory_image_map_at(struct wasmtime_memory_image *image, * deallocated and/or unmapped before this is called. */ extern void wasmtime_memory_image_free(struct wasmtime_memory_image *image); +#endif /** * Wasmtime requires a single pointer's space of TLS to be used at runtime,