diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f2b6c7e8fde6..4e7b94a77757 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -588,6 +588,51 @@ jobs: env: GH_TOKEN: ${{ github.token }} + # Run a subset of tests under MIRI on CI to help check the `unsafe` code in + # Wasmtime to make sure it's at least not obviously incorrect for basic usage. + # Note that this doesn't run the full test suite since MIRI can't actually run + # WebAssembly itself at this time (aka it doesn't support a JIT). There are a + # number of annotations throughout the code which gates some tests on MIRI not + # being run. + # + # Note that `cargo nextest` is used here additionally to get parallel test + # execution by default to help cut down on the time in CI. + miri: + needs: determine + if: needs.determine.outputs.run-full + name: Miri + runs-on: ubuntu-latest + env: + CARGO_NEXTEST_VERSION: 0.9.51 + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: ./.github/actions/install-rust + with: + toolchain: nightly-2023-03-20 + - run: rustup component add rust-src miri + - uses: actions/cache@v3 + with: + path: ${{ runner.tool_cache }}/cargo-nextest + key: cargo-nextest-bin-${{ env.CARGO_NEXTEST_VERSION }} + - run: echo "${{ runner.tool_cache }}/cargo-nextest/bin" >> $GITHUB_PATH + - run: cargo install --root ${{ runner.tool_cache }}/cargo-nextest --version ${{ env.CARGO_NEXTEST_VERSION }} cargo-nextest + - run: | + cargo miri nextest run -j4 --no-fail-fast \ + -p wasmtime \ + -p wasmtime-cli \ + -p wasmtime-runtime \ + -p wasmtime-environ + env: + MIRIFLAGS: -Zmiri-tree-borrows + + # common logic to cancel the entire run if this job fails + - run: gh run cancel ${{ github.run_id }} + if: failure() && github.event_name != 'pull_request' + env: + GH_TOKEN: ${{ github.token }} + # Perform release builds of `wasmtime` and `libwasmtime.so`. Builds a variety # of platforms and architectures and then uploads the release artifacts to # this workflow run's list of artifacts. @@ -694,6 +739,7 @@ jobs: - meta_deterministic_check - verify-publish - determine + - miri if: always() steps: - name: Dump needs context diff --git a/build.rs b/build.rs index 564133438413..ab728b739ab7 100644 --- a/build.rs +++ b/build.rs @@ -155,6 +155,8 @@ fn write_testsuite_tests( // Ignore when using QEMU for running tests (limited memory). if ignore(testsuite, &testname, strategy) { writeln!(out, "#[ignore]")?; + } else { + writeln!(out, "#[cfg_attr(miri, ignore)]")?; } writeln!( diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 77c55fd73125..18badd6cb0ef 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -214,7 +214,7 @@ fn isa_constructor( // Check for compatibility between flags and ISA level // requested. In particular, SIMD support requires SSE4.2. - if shared_flags.enable_simd() { + if !cfg!(miri) && shared_flags.enable_simd() { if !isa_flags.has_sse3() || !isa_flags.has_ssse3() || !isa_flags.has_sse41() { return Err(CodegenError::Unsupported( "SIMD support requires SSE3, SSSE3, and SSE4.1 on x86_64.".into(), diff --git a/crates/environ/src/tunables.rs b/crates/environ/src/tunables.rs index 4b37cd08b935..97a9d0802ff6 100644 --- a/crates/environ/src/tunables.rs +++ b/crates/environ/src/tunables.rs @@ -53,23 +53,26 @@ pub struct Tunables { impl Default for Tunables { fn default() -> Self { - let (static_memory_bound, static_memory_offset_guard_size) = - if cfg!(target_pointer_width = "64") { - // 64-bit has tons of address space to static memories can have 4gb - // address space reservations liberally by default, allowing us to - // help eliminate bounds checks. - // - // Coupled with a 2 GiB address space guard it lets us translate - // wasm offsets into x86 offsets as aggressively as we can. - (0x1_0000, 0x8000_0000) - } else if cfg!(target_pointer_width = "32") { - // For 32-bit we scale way down to 10MB of reserved memory. This - // impacts performance severely but allows us to have more than a - // few instances running around. - ((10 * (1 << 20)) / crate::WASM_PAGE_SIZE as u64, 0x1_0000) - } else { - panic!("unsupported target_pointer_width"); - }; + let (static_memory_bound, static_memory_offset_guard_size) = if cfg!(miri) { + // No virtual memory tricks are available on miri so make these + // limits quite conservative. + ((1 << 20) / crate::WASM_PAGE_SIZE as u64, 0) + } else if cfg!(target_pointer_width = "64") { + // 64-bit has tons of address space to static memories can have 4gb + // address space reservations liberally by default, allowing us to + // help eliminate bounds checks. + // + // Coupled with a 2 GiB address space guard it lets us translate + // wasm offsets into x86 offsets as aggressively as we can. + (0x1_0000, 0x8000_0000) + } else if cfg!(target_pointer_width = "32") { + // For 32-bit we scale way down to 10MB of reserved memory. This + // impacts performance severely but allows us to have more than a + // few instances running around. + ((10 * (1 << 20)) / crate::WASM_PAGE_SIZE as u64, 0x1_0000) + } else { + panic!("unsupported target_pointer_width"); + }; Self { static_memory_bound, static_memory_offset_guard_size, @@ -78,14 +81,21 @@ impl Default for Tunables { // // Allocate a small guard to optimize common cases but without // wasting too much memory. - dynamic_memory_offset_guard_size: 0x1_0000, + dynamic_memory_offset_guard_size: if cfg!(miri) { 0 } else { 0x1_0000 }, // We've got lots of address space on 64-bit so use a larger - // grow-into-this area, but on 32-bit we aren't as lucky. - #[cfg(target_pointer_width = "64")] - dynamic_memory_growth_reserve: 2 << 30, // 2GB - #[cfg(target_pointer_width = "32")] - dynamic_memory_growth_reserve: 1 << 20, // 1MB + // grow-into-this area, but on 32-bit we aren't as lucky. Miri is + // not exactly fast so reduce memory consumption instead of trying + // to avoid memory movement. + dynamic_memory_growth_reserve: if cfg!(miri) { + 0 + } else if cfg!(target_pointer_width = "64") { + 2 << 30 // 2GB + } else if cfg!(target_pointer_width = "32") { + 1 << 20 // 1MB + } else { + panic!("unsupported target_pointer_width"); + }, generate_native_debuginfo: false, parse_wasm_debuginfo: true, diff --git a/crates/jit-icache-coherence/src/lib.rs b/crates/jit-icache-coherence/src/lib.rs index e47e53971489..8964372b729e 100644 --- a/crates/jit-icache-coherence/src/lib.rs +++ b/crates/jit-icache-coherence/src/lib.rs @@ -74,6 +74,9 @@ cfg_if::cfg_if! { if #[cfg(target_os = "windows")] { mod win; use win as imp; + } else if #[cfg(miri)] { + mod miri; + use crate::miri as imp; } else { mod libc; use crate::libc as imp; diff --git a/crates/jit-icache-coherence/src/miri.rs b/crates/jit-icache-coherence/src/miri.rs new file mode 100644 index 000000000000..1ff641046a87 --- /dev/null +++ b/crates/jit-icache-coherence/src/miri.rs @@ -0,0 +1,10 @@ +use std::ffi::c_void; +use std::io::Result; + +pub(crate) fn pipeline_flush_mt() -> Result<()> { + Ok(()) +} + +pub(crate) fn clear_cache(_ptr: *const c_void, _len: usize) -> Result<()> { + Ok(()) +} diff --git a/crates/jit/src/unwind.rs b/crates/jit/src/unwind.rs index 72284872ce1d..9ce8660f36c9 100644 --- a/crates/jit/src/unwind.rs +++ b/crates/jit/src/unwind.rs @@ -2,6 +2,9 @@ cfg_if::cfg_if! { if #[cfg(all(windows, any(target_arch = "x86_64", target_arch = "aarch64")))] { mod winx64; pub use self::winx64::*; + } else if #[cfg(miri)] { + mod miri; + pub use self::miri::*; } else if #[cfg(unix)] { mod systemv; pub use self::systemv::*; diff --git a/crates/jit/src/unwind/miri.rs b/crates/jit/src/unwind/miri.rs new file mode 100644 index 000000000000..8e7113f7be40 --- /dev/null +++ b/crates/jit/src/unwind/miri.rs @@ -0,0 +1,15 @@ +use anyhow::Result; + +pub struct UnwindRegistration {} + +impl UnwindRegistration { + pub const SECTION_NAME: &str = ".eh_frame"; + + pub unsafe fn new( + _base_address: *const u8, + _unwind_info: *const u8, + _unwind_len: usize, + ) -> Result { + Ok(UnwindRegistration {}) + } +} diff --git a/crates/runtime/src/component.rs b/crates/runtime/src/component.rs index 9a7650f5b7cc..aa167ca6b3e9 100644 --- a/crates/runtime/src/component.rs +++ b/crates/runtime/src/component.rs @@ -40,11 +40,37 @@ pub struct ComponentInstance { /// Size and offset information for the trailing `VMComponentContext`. offsets: VMComponentOffsets, + /// A self-referential pointer to the `ComponentInstance` itself. + /// + /// The reason for this field's existence is a bit subtle because if you + /// have a pointer to `ComponentInstance` then why have this field which has + /// the same information? The subtlety here is due to the fact that this is + /// here to handle provenance and aliasing issues with optimizations in LLVM + /// and Rustc. Put another way, this is here to make MIRI happy. That's an + /// oversimplification, though, since this is actually required for + /// correctness to communicate the actual intent to LLVM's optimizations and + /// such. + /// + /// This field is chiefly used during `ComponentInstance::vmctx`. If you + /// think of pointers as a pair of address and provenance, this type stores + /// the provenance of the entire allocation. That's technically all we need + /// here, just the provenance, but that can only be done with storage of a + /// pointer hence the storage here. + /// + /// Finally note that there's a small wrapper around this to add `Send` and + /// `Sync` bounds, but serves no other purpose. + self_reference: RawComponentInstance, + /// A zero-sized field which represents the end of the struct for the actual /// `VMComponentContext` to be allocated behind. vmctx: VMComponentContext, } +struct RawComponentInstance(NonNull); + +unsafe impl Send for RawComponentInstance {} +unsafe impl Sync for RawComponentInstance {} + /// Type signature for host-defined trampolines that are called from /// WebAssembly. /// @@ -108,9 +134,8 @@ pub struct VMLowering { /// `ComponentInstance`. #[repr(C)] // Set an appropriate alignment for this structure where the most-aligned value -// internally right now is a pointer. -#[cfg_attr(target_pointer_width = "32", repr(align(4)))] -#[cfg_attr(target_pointer_width = "64", repr(align(8)))] +// internally right now `VMGlobalDefinition` which has an alignment of 16 bytes. +#[repr(align(16))] pub struct VMComponentContext { /// For more information about this see the equivalent field in `VMContext` _marker: marker::PhantomPinned, @@ -138,7 +163,7 @@ impl ComponentInstance { /// the shape of the component being instantiated and `store` is a pointer /// back to the Wasmtime store for host functions to have access to. unsafe fn new_at( - ptr: *mut ComponentInstance, + ptr: NonNull, alloc_size: usize, offsets: VMComponentOffsets, store: *mut dyn Store, @@ -146,23 +171,37 @@ impl ComponentInstance { assert!(alloc_size >= Self::alloc_layout(&offsets).size()); ptr::write( - ptr, + ptr.as_ptr(), ComponentInstance { offsets, + self_reference: RawComponentInstance(ptr), vmctx: VMComponentContext { _marker: marker::PhantomPinned, }, }, ); - (*ptr).initialize_vmctx(store); + (*ptr.as_ptr()).initialize_vmctx(store); } fn vmctx(&self) -> *mut VMComponentContext { - &self.vmctx as *const VMComponentContext as *mut VMComponentContext + let self_ref = self.self_reference.0.as_ptr(); + unsafe { + self_ref + .cast::() + .add(mem::size_of::()) + .cast() + } } - unsafe fn vmctx_plus_offset(&self, offset: u32) -> *mut T { + unsafe fn vmctx_plus_offset(&self, offset: u32) -> *const T { + self.vmctx() + .cast::() + .add(usize::try_from(offset).unwrap()) + .cast() + } + + unsafe fn vmctx_plus_offset_mut(&mut self, offset: u32) -> *mut T { self.vmctx() .cast::() .add(usize::try_from(offset).unwrap()) @@ -172,7 +211,12 @@ impl ComponentInstance { /// Returns a pointer to the "may leave" flag for this instance specified /// for canonical lowering and lifting operations. pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags { - unsafe { InstanceFlags(self.vmctx_plus_offset(self.offsets.instance_flags(instance))) } + unsafe { + InstanceFlags( + self.vmctx_plus_offset::(self.offsets.instance_flags(instance)) + .cast_mut(), + ) + } } /// Returns the store that this component was created with. @@ -264,7 +308,7 @@ impl ComponentInstance { != INVALID_PTR ); debug_assert!((*ret).vmctx as usize != INVALID_PTR); - NonNull::new(ret).unwrap() + NonNull::new(ret.cast_mut()).unwrap() } /// Stores the runtime memory pointer at the index specified. @@ -278,7 +322,7 @@ impl ComponentInstance { pub fn set_runtime_memory(&mut self, idx: RuntimeMemoryIndex, ptr: *mut VMMemoryDefinition) { unsafe { debug_assert!(!ptr.is_null()); - let storage = self.vmctx_plus_offset(self.offsets.runtime_memory(idx)); + let storage = self.vmctx_plus_offset_mut(self.offsets.runtime_memory(idx)); debug_assert!(*storage as usize == INVALID_PTR); *storage = ptr; } @@ -287,7 +331,7 @@ impl ComponentInstance { /// Same as `set_runtime_memory` but for realloc function pointers. pub fn set_runtime_realloc(&mut self, idx: RuntimeReallocIndex, ptr: NonNull) { unsafe { - let storage = self.vmctx_plus_offset(self.offsets.runtime_realloc(idx)); + let storage = self.vmctx_plus_offset_mut(self.offsets.runtime_realloc(idx)); debug_assert!(*storage as usize == INVALID_PTR); *storage = ptr.as_ptr(); } @@ -300,7 +344,7 @@ impl ComponentInstance { ptr: NonNull, ) { unsafe { - let storage = self.vmctx_plus_offset(self.offsets.runtime_post_return(idx)); + let storage = self.vmctx_plus_offset_mut(self.offsets.runtime_post_return(idx)); debug_assert!(*storage as usize == INVALID_PTR); *storage = ptr.as_ptr(); } @@ -331,7 +375,7 @@ impl ComponentInstance { debug_assert!( *self.vmctx_plus_offset::(self.offsets.lowering_data(idx)) == INVALID_PTR ); - *self.vmctx_plus_offset(self.offsets.lowering(idx)) = lowering; + *self.vmctx_plus_offset_mut(self.offsets.lowering(idx)) = lowering; self.set_func_ref( self.offsets.lowering_func_ref(idx), wasm_call, @@ -392,7 +436,7 @@ impl ComponentInstance { ) { debug_assert!(*self.vmctx_plus_offset::(offset) == INVALID_PTR); let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx()); - *self.vmctx_plus_offset(offset) = VMFuncRef { + *self.vmctx_plus_offset_mut(offset) = VMFuncRef { wasm_call: Some(wasm_call), native_call, array_call, @@ -402,11 +446,11 @@ impl ComponentInstance { } unsafe fn initialize_vmctx(&mut self, store: *mut dyn Store) { - *self.vmctx_plus_offset(self.offsets.magic()) = VMCOMPONENT_MAGIC; - *self.vmctx_plus_offset(self.offsets.transcode_libcalls()) = + *self.vmctx_plus_offset_mut(self.offsets.magic()) = VMCOMPONENT_MAGIC; + *self.vmctx_plus_offset_mut(self.offsets.transcode_libcalls()) = &transcode::VMBuiltinTranscodeArray::INIT; - *self.vmctx_plus_offset(self.offsets.store()) = store; - *self.vmctx_plus_offset(self.offsets.limits()) = (*store).vmruntime_limits(); + *self.vmctx_plus_offset_mut(self.offsets.store()) = store; + *self.vmctx_plus_offset_mut(self.offsets.limits()) = (*store).vmruntime_limits(); for i in 0..self.offsets.num_runtime_component_instances { let i = RuntimeComponentInstanceIndex::from_u32(i); @@ -423,36 +467,36 @@ impl ComponentInstance { for i in 0..self.offsets.num_lowerings { let i = LoweredIndex::from_u32(i); let offset = self.offsets.lowering_callee(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; let offset = self.offsets.lowering_data(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; let offset = self.offsets.lowering_func_ref(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; } for i in 0..self.offsets.num_always_trap { let i = RuntimeAlwaysTrapIndex::from_u32(i); let offset = self.offsets.always_trap_func_ref(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; } for i in 0..self.offsets.num_transcoders { let i = RuntimeTranscoderIndex::from_u32(i); let offset = self.offsets.transcoder_func_ref(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; } for i in 0..self.offsets.num_runtime_memories { let i = RuntimeMemoryIndex::from_u32(i); let offset = self.offsets.runtime_memory(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; } for i in 0..self.offsets.num_runtime_reallocs { let i = RuntimeReallocIndex::from_u32(i); let offset = self.offsets.runtime_realloc(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; } for i in 0..self.offsets.num_runtime_post_returns { let i = RuntimePostReturnIndex::from_u32(i); let offset = self.offsets.runtime_post_return(i); - *self.vmctx_plus_offset(offset) = INVALID_PTR; + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; } } } @@ -503,7 +547,7 @@ impl OwnedComponentInstance { let ptr = alloc::alloc_zeroed(layout) as *mut ComponentInstance; let ptr = ptr::NonNull::new(ptr).unwrap(); - ComponentInstance::new_at(ptr.as_ptr(), layout.size(), offsets, store); + ComponentInstance::new_at(ptr, layout.size(), offsets, store); OwnedComponentInstance { ptr } } diff --git a/crates/runtime/src/cow.rs b/crates/runtime/src/cow.rs index 6bced64b69fa..20fea79343f1 100644 --- a/crates/runtime/src/cow.rs +++ b/crates/runtime/src/cow.rs @@ -1,7 +1,7 @@ //! Copy-on-write initialization support: creation of backing images for //! modules, and logic to support mapping these backing images into memory. -#![cfg_attr(not(unix), allow(unused_imports, unused_variables))] +#![cfg_attr(any(not(unix), miri), allow(unused_imports, unused_variables))] use crate::MmapVec; use anyhow::Result; @@ -62,14 +62,14 @@ pub struct MemoryImage { #[derive(Debug)] enum FdSource { - #[cfg(unix)] + #[cfg(all(unix, not(miri)))] Mmap(Arc), - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(miri)))] Memfd(memfd::Memfd), } impl FdSource { - #[cfg(unix)] + #[cfg(all(unix, not(miri)))] fn as_file(&self) -> &File { match self { FdSource::Mmap(ref file) => file, @@ -82,7 +82,7 @@ impl FdSource { impl PartialEq for FdSource { fn eq(&self, other: &FdSource) -> bool { cfg_if::cfg_if! { - if #[cfg(unix)] { + if #[cfg(all(unix, not(miri)))] { use rustix::fd::AsRawFd; self.as_file().as_raw_fd() == other.as_file().as_raw_fd() } else { @@ -123,7 +123,7 @@ impl MemoryImage { // files, but for now this is still a Linux-specific region of Wasmtime. // Some work will be needed to get this file compiling for macOS and // Windows. - #[cfg(not(windows))] + #[cfg(not(any(windows, miri)))] if let Some(mmap) = mmap { let start = mmap.as_ptr() as usize; let end = start + mmap.len(); @@ -150,7 +150,7 @@ impl MemoryImage { // may be used to place the data in a form that's amenable to an mmap. cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { + if #[cfg(all(target_os = "linux", not(miri)))] { // On Linux `memfd_create` is used to create an anonymous // in-memory file to represent the heap image. This anonymous // file is then used as the basis for further mmaps. @@ -204,7 +204,7 @@ impl MemoryImage { unsafe fn map_at(&self, base: usize) -> Result<()> { cfg_if::cfg_if! { - if #[cfg(unix)] { + if #[cfg(all(unix, not(miri)))] { let ptr = rustix::mm::mmap( (base + self.linear_memory_offset) as *mut c_void, self.len, @@ -239,7 +239,7 @@ impl MemoryImage { } } -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(miri)))] fn create_memfd() -> Result> { use std::io::ErrorKind; @@ -592,7 +592,7 @@ impl MemoryImageSlot { #[allow(dead_code)] // ignore warnings as this is only used in some cfgs unsafe fn reset_all_memory_contents(&mut self, keep_resident: usize) -> Result<()> { - if !cfg!(target_os = "linux") { + if !cfg!(target_os = "linux") || cfg!(miri) { // If we're not on Linux then there's no generic platform way to // reset memory back to its original state, so instead reset memory // back to entirely zeros with an anonymous backing. @@ -730,7 +730,11 @@ impl MemoryImageSlot { unsafe { cfg_if::cfg_if! { - if #[cfg(unix)] { + if #[cfg(miri)] { + if readwrite { + std::ptr::write_bytes(start as *mut u8, 0u8, range.len()); + } + } else if #[cfg(unix)] { let flags = if readwrite { rustix::mm::MprotectFlags::READ | rustix::mm::MprotectFlags::WRITE } else { @@ -775,7 +779,9 @@ impl MemoryImageSlot { unsafe { cfg_if::cfg_if! { - if #[cfg(unix)] { + if #[cfg(miri)] { + std::ptr::write_bytes(self.base as *mut u8, 0, self.static_size); + } else if #[cfg(unix)] { let ptr = rustix::mm::mmap_anonymous( self.base as *mut c_void, self.static_size, @@ -838,7 +844,7 @@ impl Drop for MemoryImageSlot { } } -#[cfg(all(test, target_os = "linux"))] +#[cfg(all(test, target_os = "linux", not(miri)))] mod test { use std::sync::Arc; diff --git a/crates/runtime/src/debug_builtins.rs b/crates/runtime/src/debug_builtins.rs index 411300008b7e..8354c1146687 100644 --- a/crates/runtime/src/debug_builtins.rs +++ b/crates/runtime/src/debug_builtins.rs @@ -45,6 +45,9 @@ pub unsafe extern "C" fn set_vmctx_memory(vmctx_ptr: *mut VMContext) { // exported as symbols. It is a workaround: the executable normally ignores // `pub extern "C"`, see rust-lang/rust#25057. pub fn ensure_exported() { + if cfg!(miri) { + return; + } unsafe { std::ptr::read_volatile(resolve_vmctx_memory_ptr as *const u8); std::ptr::read_volatile(set_vmctx_memory as *const u8); diff --git a/crates/runtime/src/instance/allocator/pooling.rs b/crates/runtime/src/instance/allocator/pooling.rs index 917f16c62670..54e7588e3abd 100644 --- a/crates/runtime/src/instance/allocator/pooling.rs +++ b/crates/runtime/src/instance/allocator/pooling.rs @@ -35,7 +35,7 @@ cfg_if::cfg_if! { use imp::{commit_table_pages, decommit_table_pages}; -#[cfg(all(feature = "async", unix))] +#[cfg(all(feature = "async", unix, not(miri)))] use imp::{commit_stack_pages, reset_stack_pages_to_zero}; fn round_up_to_pow2(n: usize, to: usize) -> usize { @@ -368,7 +368,7 @@ impl TablePool { /// /// The top of the stack (starting stack pointer) is returned when a stack is allocated /// from the pool. -#[cfg(all(feature = "async", unix))] +#[cfg(all(feature = "async", unix, not(miri)))] #[derive(Debug)] struct StackPool { mapping: Mmap, @@ -380,7 +380,7 @@ struct StackPool { async_stack_keep_resident: usize, } -#[cfg(all(feature = "async", unix))] +#[cfg(all(feature = "async", unix, not(miri)))] impl StackPool { fn new(config: &PoolingInstanceAllocatorConfig) -> Result { use rustix::mm::{mprotect, MprotectFlags}; @@ -578,7 +578,7 @@ pub struct PoolingInstanceAllocator { linear_memory_keep_resident: usize, table_keep_resident: usize, - #[cfg(all(feature = "async", unix))] + #[cfg(all(feature = "async", unix, not(miri)))] stacks: StackPool, #[cfg(all(feature = "async", windows))] stack_size: usize, @@ -601,7 +601,7 @@ impl PoolingInstanceAllocator { tables: TablePool::new(&config.limits)?, linear_memory_keep_resident: config.linear_memory_keep_resident, table_keep_resident: config.table_keep_resident, - #[cfg(all(feature = "async", unix))] + #[cfg(all(feature = "async", unix, not(miri)))] stacks: StackPool::new(config)?, #[cfg(all(feature = "async", windows))] stack_size: config.stack_size, @@ -612,7 +612,8 @@ impl PoolingInstanceAllocator { let size_to_memset = size.min(self.table_keep_resident); unsafe { std::ptr::write_bytes(base, 0, size_to_memset); - decommit_table_pages(base.add(size_to_memset), size - size_to_memset)?; + decommit_table_pages(base.add(size_to_memset), size - size_to_memset) + .context("failed to decommit table page")?; } Ok(()) } @@ -895,30 +896,43 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator { } } - #[cfg(all(feature = "async", unix))] + #[cfg(feature = "async")] fn allocate_fiber_stack(&self) -> Result { - self.stacks.allocate() - } - - #[cfg(all(feature = "async", unix))] - unsafe fn deallocate_fiber_stack(&self, stack: &wasmtime_fiber::FiberStack) { - self.stacks.deallocate(stack); - } + cfg_if::cfg_if! { + if #[cfg(miri)] { + unimplemented!() + } else if #[cfg(unix)] { + self.stacks.allocate() + } else if #[cfg(windows)] { + if self.stack_size == 0 { + bail!("fiber stack allocation not supported") + } - #[cfg(all(feature = "async", windows))] - fn allocate_fiber_stack(&self) -> Result { - if self.stack_size == 0 { - bail!("fiber stack allocation not supported") + // On windows, we don't use a stack pool as we use the native + // fiber implementation + let stack = wasmtime_fiber::FiberStack::new(self.stack_size)?; + Ok(stack) + } else { + compile_error!("not implemented"); + } } - - // On windows, we don't use a stack pool as we use the native fiber implementation - let stack = wasmtime_fiber::FiberStack::new(self.stack_size)?; - Ok(stack) } - #[cfg(all(feature = "async", windows))] - unsafe fn deallocate_fiber_stack(&self, _stack: &wasmtime_fiber::FiberStack) { - // A no-op as we don't own the fiber stack on Windows + #[cfg(feature = "async")] + unsafe fn deallocate_fiber_stack(&self, stack: &wasmtime_fiber::FiberStack) { + cfg_if::cfg_if! { + if #[cfg(miri)] { + let _ = stack; + unimplemented!() + } else if #[cfg(unix)] { + self.stacks.deallocate(stack); + } else if #[cfg(windows)] { + // A no-op as we don't own the fiber stack on Windows + let _ = stack; + } else { + compile_error!("not implemented"); + } + } } fn purge_module(&self, module: CompiledModuleId) { @@ -1160,7 +1174,7 @@ mod test { Ok(()) } - #[cfg(all(unix, target_pointer_width = "64", feature = "async"))] + #[cfg(all(unix, target_pointer_width = "64", feature = "async", not(miri)))] #[test] fn test_stack_pool() -> Result<()> { let config = PoolingInstanceAllocatorConfig { @@ -1283,7 +1297,7 @@ mod test { assert_eq!(pool.memories.memory_size, 2 * 65536); } - #[cfg(all(unix, target_pointer_width = "64", feature = "async"))] + #[cfg(all(unix, target_pointer_width = "64", feature = "async", not(miri)))] #[test] fn test_stack_zeroed() -> Result<()> { let config = PoolingInstanceAllocatorConfig { @@ -1319,7 +1333,7 @@ mod test { Ok(()) } - #[cfg(all(unix, target_pointer_width = "64", feature = "async"))] + #[cfg(all(unix, target_pointer_width = "64", feature = "async", not(miri)))] #[test] fn test_stack_unzeroed() -> Result<()> { let config = PoolingInstanceAllocatorConfig { diff --git a/crates/runtime/src/instance/allocator/pooling/index_allocator.rs b/crates/runtime/src/instance/allocator/pooling/index_allocator.rs index b68e294560ff..94a001f4e6b1 100644 --- a/crates/runtime/src/instance/allocator/pooling/index_allocator.rs +++ b/crates/runtime/src/instance/allocator/pooling/index_allocator.rs @@ -509,7 +509,8 @@ mod test { let mut last_id = vec![None; 1000]; let mut hits = 0; - for _ in 0..100_000 { + let amt = if cfg!(miri) { 100 } else { 100_000 }; + for _ in 0..amt { loop { if !allocated.is_empty() && rng.gen_bool(0.5) { let i = rng.gen_range(0..allocated.len()); @@ -535,7 +536,7 @@ mod test { // IDs). Check for at least double that to ensure some sort of // affinity is occurring. assert!( - hits > 20000, + hits > (amt / 5), "expected at least 20000 (20%) ID-reuses but got {}", hits ); diff --git a/crates/runtime/src/instance/allocator/pooling/unix.rs b/crates/runtime/src/instance/allocator/pooling/unix.rs index ab246c3b4434..00259f4b0afd 100644 --- a/crates/runtime/src/instance/allocator/pooling/unix.rs +++ b/crates/runtime/src/instance/allocator/pooling/unix.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::Result; fn decommit(addr: *mut u8, len: usize) -> Result<()> { if len == 0 { @@ -7,13 +7,14 @@ fn decommit(addr: *mut u8, len: usize) -> Result<()> { unsafe { cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { + if #[cfg(miri)] { + std::ptr::write_bytes(addr, 0, len); + } else if #[cfg(target_os = "linux")] { use rustix::mm::{madvise, Advice}; // 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: {}")?; + madvise(addr as _, len, Advice::LinuxDontNeed)?; } else { use rustix::mm::{mmap_anonymous, ProtFlags, MapFlags}; @@ -26,8 +27,7 @@ fn decommit(addr: *mut u8, len: usize) -> Result<()> { len, ProtFlags::READ | ProtFlags::WRITE, MapFlags::PRIVATE | MapFlags::FIXED, - ) - .context("mmap failed to remap pages: {}")?; + )?; } } } @@ -44,13 +44,13 @@ pub fn decommit_table_pages(addr: *mut u8, len: usize) -> Result<()> { decommit(addr, len) } -#[cfg(feature = "async")] +#[cfg(all(feature = "async", not(miri)))] pub fn commit_stack_pages(_addr: *mut u8, _len: usize) -> Result<()> { // A no-op as stack pages remain READ|WRITE Ok(()) } -#[cfg(feature = "async")] +#[cfg(all(feature = "async", not(miri)))] pub fn reset_stack_pages_to_zero(addr: *mut u8, len: usize) -> Result<()> { decommit(addr, len) } diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index 28a8f699879c..47b854b2b0ae 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -40,6 +40,7 @@ mod memory; mod mmap; mod mmap_vec; mod parking_spot; +mod store_box; mod table; mod traphandlers; mod vmcontext; @@ -65,6 +66,7 @@ pub use crate::memory::{ }; pub use crate::mmap::Mmap; pub use crate::mmap_vec::MmapVec; +pub use crate::store_box::*; pub use crate::table::{Table, TableElement}; pub use crate::traphandlers::{ catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, tls_eager_initialize, diff --git a/crates/runtime/src/mmap.rs b/crates/runtime/src/mmap.rs index fd322dd8c275..1c077890c35b 100644 --- a/crates/runtime/src/mmap.rs +++ b/crates/runtime/src/mmap.rs @@ -11,6 +11,9 @@ cfg_if::cfg_if! { if #[cfg(windows)] { mod windows; use windows as sys; + } else if #[cfg(miri)] { + mod miri; + use miri as sys; } else { mod unix; use unix as sys; diff --git a/crates/runtime/src/mmap/miri.rs b/crates/runtime/src/mmap/miri.rs new file mode 100644 index 000000000000..bb5e9e7511a7 --- /dev/null +++ b/crates/runtime/src/mmap/miri.rs @@ -0,0 +1,93 @@ +//! A "dummy" implementation of mmaps for miri where "we do the best we can" +//! +//! Namely this uses `alloc` to allocate memory for the "mmap" specifically to +//! create page-aligned allocations. This allocation doesn't handle oeprations +//! like becoming executable or becoming readonly or being created from files, +//! but it's enough to get various tests running relying on memories and such. + +use anyhow::{bail, Result}; +use std::alloc::{self, Layout}; +use std::fs::File; +use std::ops::Range; +use std::path::Path; + +#[derive(Debug)] +pub struct Mmap { + memory: *mut [u8], +} + +unsafe impl Send for Mmap {} +unsafe impl Sync for Mmap {} + +impl Mmap { + pub fn new_empty() -> Mmap { + Mmap { memory: &mut [] } + } + + pub fn new(size: usize) -> Result { + let mut ret = Mmap::reserve(size)?; + ret.make_accessible(0, size)?; + Ok(ret) + } + + pub fn reserve(size: usize) -> Result { + let layout = Layout::from_size_align(size, crate::page_size()).unwrap(); + let ptr = unsafe { alloc::alloc(layout) }; + if ptr.is_null() { + bail!("failed to allocate memory"); + } + + Ok(Mmap { + memory: std::ptr::slice_from_raw_parts_mut(ptr, size), + }) + } + + pub fn from_file(_path: &Path) -> Result<(Self, File)> { + bail!("not supported on miri"); + } + + pub fn make_accessible(&mut self, start: usize, len: usize) -> Result<()> { + // The memory is technically always accessible but this marks it as + // initialized for miri-level checking. + unsafe { + std::ptr::write_bytes(self.memory.cast::().add(start), 0u8, len); + } + Ok(()) + } + + pub fn as_ptr(&self) -> *const u8 { + self.memory as *const u8 + } + + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self.memory.cast() + } + + pub fn len(&self) -> usize { + unsafe { (*self.memory).len() } + } + + pub unsafe fn make_executable( + &self, + _range: Range, + _enable_branch_protection: bool, + ) -> Result<()> { + Ok(()) + } + + pub unsafe fn make_readonly(&self, _range: Range) -> Result<()> { + Ok(()) + } +} + +impl Drop for Mmap { + fn drop(&mut self) { + if self.len() == 0 { + return; + } + unsafe { + let layout = Layout::from_size_align(self.len(), crate::page_size()).unwrap(); + alloc::dealloc(self.as_mut_ptr(), layout); + } + } +} diff --git a/crates/runtime/src/parking_spot.rs b/crates/runtime/src/parking_spot.rs index 33f9bce0ff80..8b974fde758f 100644 --- a/crates/runtime/src/parking_spot.rs +++ b/crates/runtime/src/parking_spot.rs @@ -279,6 +279,7 @@ mod tests { )* ) => { $( #[test] + #[cfg_attr(miri, ignore)] fn $name() { if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() { return; @@ -490,7 +491,7 @@ mod tests { let atomic_key = addr_of!(atomic) as u64; const N: u64 = 5; - const M: u64 = 1000; + const M: u64 = if cfg!(miri) { 10 } else { 1000 }; let thread = s.spawn(move || { while atomic.load(Ordering::SeqCst) != N * M { diff --git a/crates/runtime/src/store_box.rs b/crates/runtime/src/store_box.rs new file mode 100644 index 000000000000..00929e540a65 --- /dev/null +++ b/crates/runtime/src/store_box.rs @@ -0,0 +1,35 @@ +/// A `Box` lookalike for memory that's stored in a `Store` +/// +/// This is intended to be quite similar to a `Box` except without the +/// `Deref` implementations. The main motivation for this type's existence is to +/// appease the aliasing rules in miri to ensure that `StoreBox` can be moved +/// around without invalidating pointers to the contents within the box. The +/// standard `Box` type does not implement this for example and moving that +/// will invalidate derived pointers. +pub struct StoreBox(*mut T); + +unsafe impl Send for StoreBox {} +unsafe impl Sync for StoreBox {} + +impl StoreBox { + /// Allocates space on the heap to store `val` and returns a pointer to it + /// living on the heap. + pub fn new(val: T) -> StoreBox { + StoreBox(Box::into_raw(Box::new(val))) + } +} + +impl StoreBox { + /// Returns the underlying pointer to `T` which is owned by the store. + pub fn get(&self) -> *mut T { + self.0 + } +} + +impl Drop for StoreBox { + fn drop(&mut self) { + unsafe { + drop(Box::from_raw(self.0)); + } + } +} diff --git a/crates/runtime/src/traphandlers.rs b/crates/runtime/src/traphandlers.rs index bfae1568c41d..28a0ead6aeee 100644 --- a/crates/runtime/src/traphandlers.rs +++ b/crates/runtime/src/traphandlers.rs @@ -14,16 +14,54 @@ use std::sync::Once; pub use self::backtrace::{Backtrace, Frame}; pub use self::tls::{tls_eager_initialize, TlsRestore}; -#[link(name = "wasmtime-helpers")] -extern "C" { - #[allow(improper_ctypes)] - fn wasmtime_setjmp( - jmp_buf: *mut *const u8, - callback: extern "C" fn(*mut u8, *mut VMContext), - payload: *mut u8, - callee: *mut VMContext, - ) -> i32; - fn wasmtime_longjmp(jmp_buf: *const u8) -> !; +cfg_if::cfg_if! { + if #[cfg(miri)] { + // With MIRI set up just enough of a setjmp/longjmp with catching panics + // to get a few tests working that use this. + // + // Note that no actual JIT code runs in MIRI so this is purely here for + // host-to-host calls. + + struct WasmtimeLongjmp; + + unsafe extern "C" fn wasmtime_setjmp( + _jmp_buf: *mut *const u8, + callback: extern "C" fn(*mut u8, *mut VMContext), + payload: *mut u8, + callee: *mut VMContext, + ) -> i32 { + use std::panic::{self, AssertUnwindSafe}; + let result = panic::catch_unwind(AssertUnwindSafe(|| { + callback(payload, callee); + })); + match result { + Ok(()) => 1, + Err(e) => { + if e.is::() { + 0 + } else { + panic::resume_unwind(e) + } + } + } + } + + unsafe extern "C" fn wasmtime_longjmp(_jmp_buf: *const u8) -> ! { + std::panic::panic_any(WasmtimeLongjmp) + } + } else { + #[link(name = "wasmtime-helpers")] + extern "C" { + #[allow(improper_ctypes)] + fn wasmtime_setjmp( + jmp_buf: *mut *const u8, + callback: extern "C" fn(*mut u8, *mut VMContext), + payload: *mut u8, + callee: *mut VMContext, + ) -> i32; + fn wasmtime_longjmp(jmp_buf: *const u8) -> !; + } + } } cfg_if::cfg_if! { diff --git a/crates/runtime/src/traphandlers/unix.rs b/crates/runtime/src/traphandlers/unix.rs index 183773370633..022e32d9b28d 100644 --- a/crates/runtime/src/traphandlers/unix.rs +++ b/crates/runtime/src/traphandlers/unix.rs @@ -14,6 +14,9 @@ static mut PREV_SIGILL: MaybeUninit = MaybeUninit::uninit(); static mut PREV_SIGFPE: MaybeUninit = MaybeUninit::uninit(); pub unsafe fn platform_init() { + if cfg!(miri) { + return; + } let register = |slot: &mut MaybeUninit, signal: i32| { let mut handler: libc::sigaction = mem::zeroed(); // The flags here are relatively careful, and they are... @@ -312,6 +315,10 @@ pub fn lazy_per_thread_init() { }); unsafe fn allocate_sigaltstack() -> Option { + if cfg!(miri) { + return None; + } + // Check to see if the existing sigaltstack, if it exists, is big // enough. If so we don't need to allocate our own. let mut old_stack = mem::zeroed(); diff --git a/crates/runtime/src/vmcontext/vm_host_func_context.rs b/crates/runtime/src/vmcontext/vm_host_func_context.rs index ba6f9fbc84a9..e939dba4d45c 100644 --- a/crates/runtime/src/vmcontext/vm_host_func_context.rs +++ b/crates/runtime/src/vmcontext/vm_host_func_context.rs @@ -2,9 +2,8 @@ //! //! Keep in sync with `wasmtime_environ::VMHostFuncOffsets`. -use crate::VMFuncRef; - use super::VMOpaqueContext; +use crate::{StoreBox, VMFuncRef}; use std::any::Any; use wasmtime_environ::{VM_ARRAY_CALL_HOST_FUNC_MAGIC, VM_NATIVE_CALL_HOST_FUNC_MAGIC}; @@ -37,14 +36,17 @@ impl VMArrayCallHostFuncContext { pub unsafe fn new( func_ref: VMFuncRef, host_state: Box, - ) -> Box { + ) -> StoreBox { debug_assert!(func_ref.vmctx.is_null()); - let mut ctx = Box::new(VMArrayCallHostFuncContext { + let ctx = StoreBox::new(VMArrayCallHostFuncContext { magic: wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC, func_ref, host_state, }); - ctx.func_ref.vmctx = VMOpaqueContext::from_vm_array_call_host_func_context(&mut *ctx); + let vmctx = VMOpaqueContext::from_vm_array_call_host_func_context(ctx.get()); + unsafe { + (*ctx.get()).func_ref.vmctx = vmctx; + } ctx } @@ -109,13 +111,16 @@ impl VMNativeCallHostFuncContext { pub unsafe fn new( func_ref: VMFuncRef, host_state: Box, - ) -> Box { - let mut ctx = Box::new(VMNativeCallHostFuncContext { + ) -> StoreBox { + let ctx = StoreBox::new(VMNativeCallHostFuncContext { magic: wasmtime_environ::VM_NATIVE_CALL_HOST_FUNC_MAGIC, func_ref, host_state, }); - ctx.func_ref.vmctx = VMOpaqueContext::from_vm_native_call_host_func_context(&mut *ctx); + let vmctx = VMOpaqueContext::from_vm_native_call_host_func_context(ctx.get()); + unsafe { + (*ctx.get()).func_ref.vmctx = vmctx; + } ctx } diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 55acdb38b685..4beeb71ab206 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -185,7 +185,7 @@ impl Config { async_stack_size: 2 << 20, async_support: false, module_version: ModuleVersionStrategy::default(), - parallel_compilation: true, + parallel_compilation: !cfg!(miri), memory_init_cow: true, memory_guaranteed_dense_image_size: 16 << 20, force_memory_init_memfd: false, diff --git a/crates/wasmtime/src/engine.rs b/crates/wasmtime/src/engine.rs index 31eddbe5d269..054ea2521ae7 100644 --- a/crates/wasmtime/src/engine.rs +++ b/crates/wasmtime/src/engine.rs @@ -650,6 +650,7 @@ mod tests { use tempfile::TempDir; #[test] + #[cfg_attr(miri, ignore)] fn cache_accounts_for_opt_level() -> Result<()> { let td = TempDir::new()?; let config_path = td.path().join("config.toml"); diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index f8b2f83e8e43..3979f0612dc9 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -532,6 +532,7 @@ Caused by: } #[test] + #[cfg_attr(miri, ignore)] fn test_tunables_int_mismatch() -> Result<()> { let engine = Engine::default(); let mut metadata = Metadata::new(&engine); diff --git a/crates/wasmtime/src/func.rs b/crates/wasmtime/src/func.rs index 104c5f386027..906b80427514 100644 --- a/crates/wasmtime/src/func.rs +++ b/crates/wasmtime/src/func.rs @@ -11,7 +11,7 @@ use std::pin::Pin; use std::ptr::{self, NonNull}; use std::sync::Arc; use wasmtime_runtime::{ - ExportFunction, InstanceHandle, VMArrayCallHostFuncContext, VMContext, VMFuncRef, + ExportFunction, InstanceHandle, StoreBox, VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMFunctionImport, VMNativeCallHostFuncContext, VMOpaqueContext, VMSharedSignatureIndex, }; @@ -1426,6 +1426,13 @@ fn enter_wasm(store: &mut StoreContextMut<'_, T>) -> Option { return None; } + // Ignore this stack pointer business on miri since we can't execute wasm + // anyway and the concept of a stack pointer on miri is a bit nebulous + // regardless. + if cfg!(miri) { + return None; + } + let stack_pointer = psm::stack_pointer() as usize; // Determine the stack pointer where, after which, any wasm code will @@ -2104,18 +2111,18 @@ for_each_function_signature!(impl_into_func); #[doc(hidden)] pub enum HostContext { - Native(Box), - Array(Box), + Native(StoreBox), + Array(StoreBox), } -impl From> for HostContext { - fn from(ctx: Box) -> Self { +impl From> for HostContext { + fn from(ctx: StoreBox) -> Self { HostContext::Native(ctx) } } -impl From> for HostContext { - fn from(ctx: Box) -> Self { +impl From> for HostContext { + fn from(ctx: StoreBox) -> Self { HostContext::Array(ctx) } } @@ -2267,8 +2274,8 @@ impl HostFunc { pub(crate) fn func_ref(&self) -> &VMFuncRef { match &self.ctx { - HostContext::Native(ctx) => ctx.func_ref(), - HostContext::Array(ctx) => ctx.func_ref(), + HostContext::Native(ctx) => unsafe { (*ctx.get()).func_ref() }, + HostContext::Array(ctx) => unsafe { (*ctx.get()).func_ref() }, } } diff --git a/crates/wasmtime/src/memory.rs b/crates/wasmtime/src/memory.rs index c3d17784fc56..1d309f995e5c 100644 --- a/crates/wasmtime/src/memory.rs +++ b/crates/wasmtime/src/memory.rs @@ -769,7 +769,7 @@ impl SharedMemory { pub fn data(&self) -> &[UnsafeCell] { unsafe { let definition = &*self.0.vmmemory_ptr(); - slice::from_raw_parts_mut(definition.base.cast(), definition.current_length()) + slice::from_raw_parts(definition.base.cast(), definition.current_length()) } } diff --git a/crates/wasmtime/src/module/registry.rs b/crates/wasmtime/src/module/registry.rs index 459c139bb530..de6fee9f179a 100644 --- a/crates/wasmtime/src/module/registry.rs +++ b/crates/wasmtime/src/module/registry.rs @@ -274,6 +274,7 @@ pub fn unregister_code(code: &Arc) { } #[test] +#[cfg_attr(miri, ignore)] fn test_frame_info() -> Result<(), anyhow::Error> { use crate::*; let mut store = Store::<()>::default(); diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs index 240955aa18b5..40771ed2df76 100644 --- a/crates/wasmtime/src/store.rs +++ b/crates/wasmtime/src/store.rs @@ -96,7 +96,7 @@ use std::sync::Arc; use std::task::{Context, Poll}; use wasmtime_runtime::{ InstanceAllocationRequest, InstanceAllocator, InstanceHandle, ModuleInfo, - OnDemandInstanceAllocator, SignalHandler, StorePtr, VMContext, VMExternRef, + OnDemandInstanceAllocator, SignalHandler, StoreBox, StorePtr, VMContext, VMExternRef, VMExternRefActivationsTable, VMRuntimeLimits, WasmFault, }; @@ -281,7 +281,7 @@ pub struct StoreOpaque { externref_activations_table: VMExternRefActivationsTable, modules: ModuleRegistry, func_refs: FuncRefs, - host_globals: Vec>, + host_globals: Vec>, // Numbers of resources instantiated in this store, and their limits instance_count: usize, @@ -1190,7 +1190,7 @@ impl StoreOpaque { self.func_refs.push_instance_pre_func_refs(func_refs); } - pub(crate) fn host_globals(&mut self) -> &mut Vec> { + pub(crate) fn host_globals(&mut self) -> &mut Vec> { &mut self.host_globals } diff --git a/crates/wasmtime/src/store/func_refs.rs b/crates/wasmtime/src/store/func_refs.rs index 0e600866cf4e..814f680c6f7e 100644 --- a/crates/wasmtime/src/store/func_refs.rs +++ b/crates/wasmtime/src/store/func_refs.rs @@ -49,7 +49,7 @@ mod unpatched_func_ref { impl UnpatchedFuncRef { /// Safety: Callers must ensure that the given `func_ref` and resulting /// wrapped value are used in a `Send + Sync` compatible way. - pub unsafe fn new(func_ref: &VMFuncRef) -> UnpatchedFuncRef { + pub unsafe fn new(func_ref: &mut VMFuncRef) -> UnpatchedFuncRef { debug_assert!(func_ref.wasm_call.is_none()); UnpatchedFuncRef(NonNull::from(func_ref)) } @@ -80,8 +80,10 @@ impl FuncRefs { let _ = unsafe { VMNativeCallHostFuncContext::from_opaque(func_ref.vmctx) }; let func_ref = self.bump.alloc(func_ref); - self.with_holes.push(UnpatchedFuncRef::new(func_ref)); - NonNull::from(func_ref) + let unpatched = UnpatchedFuncRef::new(func_ref); + let ret = unpatched.func_ref(); + self.with_holes.push(unpatched); + ret } /// Patch any `VMFuncRef::wasm_call`s that need filling in. diff --git a/crates/wasmtime/src/trampoline/func.rs b/crates/wasmtime/src/trampoline/func.rs index efb402b84147..e719186d89d9 100644 --- a/crates/wasmtime/src/trampoline/func.rs +++ b/crates/wasmtime/src/trampoline/func.rs @@ -5,7 +5,9 @@ use anyhow::Result; use std::panic::{self, AssertUnwindSafe}; use std::ptr::NonNull; use wasmtime_jit::{CodeMemory, ProfilingAgent}; -use wasmtime_runtime::{VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMOpaqueContext}; +use wasmtime_runtime::{ + StoreBox, VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMOpaqueContext, +}; struct TrampolineState { func: F, @@ -113,7 +115,7 @@ pub fn create_array_call_function( ft: &FuncType, func: F, engine: &Engine, -) -> Result> +) -> Result> where F: Fn(*mut VMContext, &mut [ValRaw]) -> Result<()> + Send + Sync + 'static, { diff --git a/crates/wasmtime/src/trampoline/global.rs b/crates/wasmtime/src/trampoline/global.rs index 32940504ed67..cadc0f3f1b8e 100644 --- a/crates/wasmtime/src/trampoline/global.rs +++ b/crates/wasmtime/src/trampoline/global.rs @@ -2,7 +2,7 @@ use crate::store::StoreOpaque; use crate::{GlobalType, Mutability, Val}; use std::ptr; use wasmtime_environ::GlobalInit; -use wasmtime_runtime::VMGlobalDefinition; +use wasmtime_runtime::{StoreBox, VMGlobalDefinition}; #[repr(C)] pub struct VMHostGlobalContext { @@ -33,40 +33,39 @@ pub fn generate_global_export( ty: GlobalType, val: Val, ) -> wasmtime_runtime::ExportGlobal { - let mut ctx = Box::new(VMHostGlobalContext { + let global = wasmtime_environ::Global { + wasm_ty: ty.content().to_wasm_type(), + mutability: match ty.mutability() { + Mutability::Const => false, + Mutability::Var => true, + }, + // TODO: This is just a dummy value; nothing should actually read + // this. We should probably remove this field from the struct. + initializer: GlobalInit::I32Const(0), + }; + let ctx = StoreBox::new(VMHostGlobalContext { ty, global: VMGlobalDefinition::new(), }); - unsafe { + let definition = unsafe { + let global = &mut (*ctx.get()).global; match val { - Val::I32(x) => *ctx.global.as_i32_mut() = x, - Val::I64(x) => *ctx.global.as_i64_mut() = x, - Val::F32(x) => *ctx.global.as_f32_bits_mut() = x, - Val::F64(x) => *ctx.global.as_f64_bits_mut() = x, - Val::V128(x) => *ctx.global.as_u128_mut() = x, + Val::I32(x) => *global.as_i32_mut() = x, + Val::I64(x) => *global.as_i64_mut() = x, + Val::F32(x) => *global.as_f32_bits_mut() = x, + Val::F64(x) => *global.as_f64_bits_mut() = x, + Val::V128(x) => *global.as_u128_mut() = x, Val::FuncRef(f) => { - *ctx.global.as_func_ref_mut() = f.map_or(ptr::null_mut(), |f| { + *global.as_func_ref_mut() = f.map_or(ptr::null_mut(), |f| { f.caller_checked_func_ref(store).as_ptr() }) } - Val::ExternRef(x) => *ctx.global.as_externref_mut() = x.map(|x| x.inner), + Val::ExternRef(x) => *global.as_externref_mut() = x.map(|x| x.inner), } - } - - let ret = wasmtime_runtime::ExportGlobal { - definition: &mut ctx.global as *mut _, - global: wasmtime_environ::Global { - wasm_ty: ctx.ty.content().to_wasm_type(), - mutability: match ctx.ty.mutability() { - Mutability::Const => false, - Mutability::Var => true, - }, - // TODO: This is just a dummy value; nothing should actually read - // this. We should probably remove this field from the struct. - initializer: GlobalInit::I32Const(0), - }, + global }; + store.host_globals().push(ctx); - ret + wasmtime_runtime::ExportGlobal { definition, global } } diff --git a/src/commands/compile.rs b/src/commands/compile.rs index e218fbcba559..a80b171f5b16 100644 --- a/src/commands/compile.rs +++ b/src/commands/compile.rs @@ -122,7 +122,7 @@ impl CompileCommand { } } -#[cfg(test)] +#[cfg(all(test, not(miri)))] mod test { use super::*; use std::io::Write; diff --git a/tests/all/async_functions.rs b/tests/all/async_functions.rs index aec49b3fb17d..8bb9f006b007 100644 --- a/tests/all/async_functions.rs +++ b/tests/all/async_functions.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::{anyhow, bail, Result}; use std::future::Future; use std::pin::Pin; diff --git a/tests/all/call_hook.rs b/tests/all/call_hook.rs index f5c61fdf4560..9d47ecb85d8b 100644 --- a/tests/all/call_hook.rs +++ b/tests/all/call_hook.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::{bail, Error, Result}; use std::future::Future; use std::pin::Pin; diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs index 6a1baa47ed08..ca815bd77771 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::{bail, Context, Result}; use std::fs::File; use std::io::{Read, Write}; diff --git a/tests/all/component_model.rs b/tests/all/component_model.rs index fba2739a3cad..87b483d8b7bf 100644 --- a/tests/all/component_model.rs +++ b/tests/all/component_model.rs @@ -18,6 +18,7 @@ mod post_return; mod strings; #[test] +#[cfg_attr(miri, ignore)] fn components_importing_modules() -> Result<()> { let engine = engine(); diff --git a/tests/all/component_model/aot.rs b/tests/all/component_model/aot.rs index 2a86655a8e47..3b03aef23755 100644 --- a/tests/all/component_model/aot.rs +++ b/tests/all/component_model/aot.rs @@ -30,6 +30,7 @@ fn bare_bones() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn mildly_more_interesting() -> Result<()> { let engine = super::engine(); let component = Component::new( diff --git a/tests/all/component_model/async.rs b/tests/all/component_model/async.rs index 01c7341a6a4e..44877a1b0485 100644 --- a/tests/all/component_model/async.rs +++ b/tests/all/component_model/async.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::Result; use wasmtime::component::*; use wasmtime::{Store, StoreContextMut, Trap}; diff --git a/tests/all/component_model/bindgen.rs b/tests/all/component_model/bindgen.rs index 70681b6bfb22..d8c8f3023cd4 100644 --- a/tests/all/component_model/bindgen.rs +++ b/tests/all/component_model/bindgen.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use super::engine; use anyhow::Result; use wasmtime::{ diff --git a/tests/all/component_model/dynamic.rs b/tests/all/component_model/dynamic.rs index b71553493c60..ff93a049a607 100644 --- a/tests/all/component_model/dynamic.rs +++ b/tests/all/component_model/dynamic.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use super::{make_echo_component, make_echo_component_with_params, Param, Type}; use anyhow::Result; use component_test_util::FuncExt; diff --git a/tests/all/component_model/func.rs b/tests/all/component_model/func.rs index 94c0cb38e29b..85bc25fc2001 100644 --- a/tests/all/component_model/func.rs +++ b/tests/all/component_model/func.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use super::{TypedFuncExt, REALLOC_AND_FREE}; use anyhow::Result; use std::rc::Rc; diff --git a/tests/all/component_model/import.rs b/tests/all/component_model/import.rs index dd479a8726b8..be5ba39bedf5 100644 --- a/tests/all/component_model/import.rs +++ b/tests/all/component_model/import.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use super::REALLOC_AND_FREE; use anyhow::Result; use std::ops::Deref; diff --git a/tests/all/component_model/macros.rs b/tests/all/component_model/macros.rs index f6c83e592db3..30b2f3ca2e22 100644 --- a/tests/all/component_model/macros.rs +++ b/tests/all/component_model/macros.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use super::{make_echo_component, TypedFuncExt}; use anyhow::Result; use component_macro_test::{add_variants, flags_test}; diff --git a/tests/all/component_model/nested.rs b/tests/all/component_model/nested.rs index 473c6b751b78..35349c2e73f6 100644 --- a/tests/all/component_model/nested.rs +++ b/tests/all/component_model/nested.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use super::REALLOC_AND_FREE; use anyhow::Result; use wasmtime::component::*; diff --git a/tests/all/component_model/post_return.rs b/tests/all/component_model/post_return.rs index d35be4337a05..8cd5d934a9b0 100644 --- a/tests/all/component_model/post_return.rs +++ b/tests/all/component_model/post_return.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::Result; use wasmtime::component::*; use wasmtime::{Store, StoreContextMut, Trap}; diff --git a/tests/all/component_model/strings.rs b/tests/all/component_model/strings.rs index 3cabe9161686..ad46ddb0a6ab 100644 --- a/tests/all/component_model/strings.rs +++ b/tests/all/component_model/strings.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use super::REALLOC_AND_FREE; use anyhow::Result; use wasmtime::component::{Component, Linker}; diff --git a/tests/all/custom_signal_handler.rs b/tests/all/custom_signal_handler.rs index 498014093548..fdfc22a7fef3 100644 --- a/tests/all/custom_signal_handler.rs +++ b/tests/all/custom_signal_handler.rs @@ -2,6 +2,7 @@ target_os = "linux", all(target_os = "macos", feature = "posix-signals-on-macos") ))] +#[cfg(not(miri))] mod tests { use anyhow::Result; use rustix::mm::{mprotect, MprotectFlags}; diff --git a/tests/all/epoch_interruption.rs b/tests/all/epoch_interruption.rs index a340ef658341..8e32881c2dc3 100644 --- a/tests/all/epoch_interruption.rs +++ b/tests/all/epoch_interruption.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use crate::async_functions::{CountPending, PollOnce}; use anyhow::{anyhow, Result}; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/all/externals.rs b/tests/all/externals.rs index baf15c9d14ec..680b533198d1 100644 --- a/tests/all/externals.rs +++ b/tests/all/externals.rs @@ -57,6 +57,7 @@ fn bad_tables() { } #[test] +#[cfg_attr(miri, ignore)] fn cross_store() -> anyhow::Result<()> { let mut cfg = Config::new(); cfg.wasm_reference_types(true); diff --git a/tests/all/fuel.rs b/tests/all/fuel.rs index 730d56b44b78..0936458351cf 100644 --- a/tests/all/fuel.rs +++ b/tests/all/fuel.rs @@ -25,6 +25,7 @@ impl<'a> Parse<'a> for FuelWast<'a> { } #[test] +#[cfg_attr(miri, ignore)] fn run() -> Result<()> { let test = std::fs::read_to_string("tests/all/fuel.wast")?; let buf = ParseBuffer::new(&test)?; @@ -58,6 +59,7 @@ fn fuel_consumed(wasm: &[u8]) -> u64 { } #[test] +#[cfg_attr(miri, ignore)] fn iloop() { iloop_aborts( r#" @@ -141,6 +143,7 @@ fn manual_fuel() { } #[test] +#[cfg_attr(miri, ignore)] fn host_function_consumes_all() { const FUEL: u64 = 10_000; let mut config = Config::new(); @@ -185,6 +188,7 @@ fn manual_edge_cases() { } #[test] +#[cfg_attr(miri, ignore)] fn unconditionally_trapping_memory_accesses_save_fuel_before_trapping() { let mut config = Config::new(); config.consume_fuel(true); diff --git a/tests/all/func.rs b/tests/all/func.rs index a1d37f174f82..7c8021478519 100644 --- a/tests/all/func.rs +++ b/tests/all/func.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use wasmtime::*; #[test] +#[cfg_attr(miri, ignore)] fn call_wasm_to_wasm() -> Result<()> { let wasm = wat::parse_str( r#" @@ -31,6 +32,7 @@ fn call_wasm_to_wasm() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_wasm_to_native() -> Result<()> { let wasm = wat::parse_str( r#" @@ -55,6 +57,7 @@ fn call_wasm_to_native() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_wasm_to_array() -> Result<()> { let wasm = wat::parse_str( r#" @@ -88,6 +91,7 @@ fn call_wasm_to_array() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_native_to_wasm() -> Result<()> { let wasm = wat::parse_str( r#" @@ -125,6 +129,7 @@ fn call_native_to_native() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_native_to_array() -> Result<()> { let mut store = Store::<()>::default(); @@ -148,6 +153,7 @@ fn call_native_to_array() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_array_to_wasm() -> Result<()> { let wasm = wat::parse_str( r#" @@ -195,6 +201,7 @@ fn call_array_to_native() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_array_to_array() -> Result<()> { let mut store = Store::<()>::default(); let func = Func::new( @@ -223,6 +230,7 @@ fn call_array_to_array() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_indirect_native_from_wasm_import_global() -> Result<()> { let wasm = wat::parse_str( r#" @@ -255,6 +263,7 @@ fn call_indirect_native_from_wasm_import_global() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_indirect_native_from_wasm_import_table() -> Result<()> { let wasm = wat::parse_str( r#" @@ -283,6 +292,7 @@ fn call_indirect_native_from_wasm_import_table() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_indirect_native_from_wasm_import_func_returns_funcref() -> Result<()> { let wasm = wat::parse_str( r#" @@ -311,6 +321,7 @@ fn call_indirect_native_from_wasm_import_func_returns_funcref() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_indirect_native_from_exported_table() -> Result<()> { let wasm = wat::parse_str( r#" @@ -337,6 +348,7 @@ fn call_indirect_native_from_exported_table() -> Result<()> { // wasm exports global, host puts native-call funcref in global, wasm calls funcref #[test] +#[cfg_attr(miri, ignore)] fn call_indirect_native_from_exported_global() -> Result<()> { let wasm = wat::parse_str( r#" @@ -482,6 +494,7 @@ fn signatures_match() { } #[test] +#[cfg_attr(miri, ignore)] fn import_works() -> Result<()> { static HITS: AtomicUsize = AtomicUsize::new(0); @@ -589,6 +602,7 @@ fn trap_smoke() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn trap_import() -> Result<()> { let wasm = wat::parse_str( r#" @@ -645,6 +659,7 @@ fn get_from_wrapper() { } #[test] +#[cfg_attr(miri, ignore)] fn get_from_signature() { let mut store = Store::<()>::default(); let ty = FuncType::new(None, None); @@ -662,6 +677,7 @@ fn get_from_signature() { } #[test] +#[cfg_attr(miri, ignore)] fn get_from_module() -> anyhow::Result<()> { let mut store = Store::<()>::default(); let module = Module::new( @@ -733,6 +749,7 @@ fn call_wrapped_func() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn caller_memory() -> anyhow::Result<()> { let mut store = Store::<()>::default(); let f = Func::wrap(&mut store, |mut c: Caller<'_, ()>| { @@ -798,6 +815,7 @@ fn caller_memory() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn func_write_nothing() -> anyhow::Result<()> { let mut store = Store::<()>::default(); let ty = FuncType::new(None, Some(ValType::I32)); @@ -810,6 +828,7 @@ fn func_write_nothing() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn return_cross_store_value() -> anyhow::Result<()> { let _ = env_logger::try_init(); @@ -875,6 +894,7 @@ fn pass_cross_store_arg() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn externref_signature_no_reference_types() -> anyhow::Result<()> { let mut config = Config::new(); config.wasm_reference_types(false); @@ -892,6 +912,7 @@ fn externref_signature_no_reference_types() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn trampolines_always_valid() -> anyhow::Result<()> { // Compile two modules up front let mut store = Store::<()>::default(); @@ -918,6 +939,7 @@ fn trampolines_always_valid() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn typed_multiple_results() -> anyhow::Result<()> { let mut store = Store::<()>::default(); let module = Module::new( @@ -954,6 +976,7 @@ fn typed_multiple_results() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn trap_doesnt_leak() -> anyhow::Result<()> { #[derive(Default)] struct Canary(Arc); @@ -994,6 +1017,7 @@ fn trap_doesnt_leak() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn wrap_multiple_results() -> anyhow::Result<()> { fn test(store: &mut Store<()>, t: T) -> anyhow::Result<()> where @@ -1158,6 +1182,7 @@ fn wrap_multiple_results() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn trampoline_for_declared_elem() -> anyhow::Result<()> { let engine = Engine::default(); @@ -1185,6 +1210,7 @@ fn trampoline_for_declared_elem() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn wasm_ty_roundtrip() -> Result<(), anyhow::Error> { let mut store = Store::<()>::default(); let debug = Func::wrap( @@ -1240,6 +1266,7 @@ fn wasm_ty_roundtrip() -> Result<(), anyhow::Error> { } #[test] +#[cfg_attr(miri, ignore)] fn typed_funcs_count_params_correctly_in_error_messages() -> anyhow::Result<()> { let mut store = Store::<()>::default(); let module = Module::new( diff --git a/tests/all/funcref.rs b/tests/all/funcref.rs index 74980bb21cda..e11b5ab02ff4 100644 --- a/tests/all/funcref.rs +++ b/tests/all/funcref.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use wasmtime::*; #[test] +#[cfg_attr(miri, ignore)] fn pass_funcref_in_and_out_of_wasm() -> anyhow::Result<()> { let (mut store, module) = ref_types_module( false, @@ -77,6 +78,7 @@ fn pass_funcref_in_and_out_of_wasm() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn receive_null_funcref_from_wasm() -> anyhow::Result<()> { let (mut store, module) = ref_types_module( false, @@ -126,6 +128,7 @@ fn wrong_store() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn func_new_returns_wrong_store() -> anyhow::Result<()> { let dropped = Arc::new(AtomicBool::new(false)); { diff --git a/tests/all/gc.rs b/tests/all/gc.rs index e9b1e0abd0ea..096a3bec2952 100644 --- a/tests/all/gc.rs +++ b/tests/all/gc.rs @@ -13,11 +13,13 @@ impl Drop for SetFlagOnDrop { } #[test] +#[cfg_attr(miri, ignore)] fn smoke_test_gc() -> anyhow::Result<()> { smoke_test_gc_impl(false) } #[test] +#[cfg_attr(miri, ignore)] fn smoke_test_gc_epochs() -> anyhow::Result<()> { smoke_test_gc_impl(true) } @@ -77,6 +79,7 @@ fn smoke_test_gc_impl(use_epochs: bool) -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn wasm_dropping_refs() -> anyhow::Result<()> { let (mut store, module) = ref_types_module( false, @@ -120,6 +123,7 @@ fn wasm_dropping_refs() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn many_live_refs() -> anyhow::Result<()> { let mut wat = r#" (module @@ -200,6 +204,7 @@ fn many_live_refs() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn drop_externref_via_table_set() -> anyhow::Result<()> { let (mut store, module) = ref_types_module( false, @@ -247,6 +252,7 @@ fn drop_externref_via_table_set() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn global_drops_externref() -> anyhow::Result<()> { test_engine(&Engine::default())?; @@ -296,6 +302,7 @@ fn global_drops_externref() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn table_drops_externref() -> anyhow::Result<()> { test_engine(&Engine::default())?; @@ -346,6 +353,7 @@ fn table_drops_externref() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn gee_i_sure_hope_refcounting_is_atomic() -> anyhow::Result<()> { let mut config = Config::new(); config.wasm_reference_types(true); @@ -435,6 +443,7 @@ fn global_init_no_leak() -> anyhow::Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn no_gc_middle_of_args() -> anyhow::Result<()> { let (mut store, module) = ref_types_module( false, diff --git a/tests/all/host_funcs.rs b/tests/all/host_funcs.rs index 795305efb433..efa582eea1ee 100644 --- a/tests/all/host_funcs.rs +++ b/tests/all/host_funcs.rs @@ -210,6 +210,7 @@ fn signatures_match() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn import_works() -> Result<()> { static HITS: AtomicUsize = AtomicUsize::new(0); @@ -311,6 +312,7 @@ fn import_works() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_import_many_args() -> Result<()> { let wasm = wat::parse_str( r#" @@ -370,6 +372,7 @@ fn call_import_many_args() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_wasm_many_args() -> Result<()> { let wasm = wat::parse_str( r#" @@ -459,6 +462,7 @@ fn trap_smoke() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn trap_import() -> Result<()> { let wasm = wat::parse_str( r#" @@ -482,6 +486,7 @@ fn trap_import() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn new_from_signature() -> Result<()> { let engine = Engine::default(); let mut linker = Linker::new(&engine); @@ -592,6 +597,7 @@ fn call_wrapped_func() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn func_return_nothing() -> Result<()> { let engine = Engine::default(); let mut linker = Linker::new(&engine); @@ -608,6 +614,7 @@ fn func_return_nothing() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn call_via_funcref() -> Result<()> { static HITS: AtomicUsize = AtomicUsize::new(0); @@ -695,6 +702,7 @@ fn store_with_context() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn wasi_imports() -> Result<()> { let engine = Engine::default(); let mut linker = Linker::new(&engine); diff --git a/tests/all/iloop.rs b/tests/all/iloop.rs index fedef6f6dbcf..6e7077e87427 100644 --- a/tests/all/iloop.rs +++ b/tests/all/iloop.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst}; use wasmtime::*; diff --git a/tests/all/import_calling_export.rs b/tests/all/import_calling_export.rs index 5b17d6937e15..247fbcd1ebc0 100644 --- a/tests/all/import_calling_export.rs +++ b/tests/all/import_calling_export.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::Result; use wasmtime::*; diff --git a/tests/all/import_indexes.rs b/tests/all/import_indexes.rs index d6718f166597..6383d576e34c 100644 --- a/tests/all/import_indexes.rs +++ b/tests/all/import_indexes.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use wasmtime::*; #[test] diff --git a/tests/all/instance.rs b/tests/all/instance.rs index 95ed175df359..23d734a1cc39 100644 --- a/tests/all/instance.rs +++ b/tests/all/instance.rs @@ -13,6 +13,7 @@ fn wrong_import_numbers() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn initializes_linear_memory() -> Result<()> { // Test for https://github.com/bytecodealliance/wasmtime/issues/2784 let wat = r#" @@ -33,6 +34,7 @@ fn initializes_linear_memory() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn linear_memory_limits() -> Result<()> { // this test will allocate 4GB of virtual memory space, and may not work in // situations like CI QEMU emulation where it triggers SIGKILL. diff --git a/tests/all/invoke_func_via_table.rs b/tests/all/invoke_func_via_table.rs index a50d30ceeec2..8edb1838645b 100644 --- a/tests/all/invoke_func_via_table.rs +++ b/tests/all/invoke_func_via_table.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::{Context as _, Result}; use wasmtime::*; diff --git a/tests/all/limits.rs b/tests/all/limits.rs index 3dee9f3a0b68..810902f11332 100644 --- a/tests/all/limits.rs +++ b/tests/all/limits.rs @@ -4,6 +4,7 @@ use wasmtime::*; const WASM_PAGE_SIZE: usize = wasmtime_environ::WASM_PAGE_SIZE as usize; #[test] +#[cfg_attr(miri, ignore)] fn test_limits() -> Result<()> { let engine = Engine::default(); let module = Module::new( @@ -91,6 +92,7 @@ fn test_limits() -> Result<()> { } #[tokio::test] +#[cfg_attr(miri, ignore)] async fn test_limits_async() -> Result<()> { let mut config = Config::new(); config.async_support(true); @@ -425,6 +427,7 @@ impl ResourceLimiter for MemoryContext { } #[test] +#[cfg_attr(miri, ignore)] fn test_custom_memory_limiter() -> Result<()> { let engine = Engine::default(); let mut linker = Linker::new(&engine); @@ -540,6 +543,7 @@ impl ResourceLimiterAsync for MemoryContext { } #[tokio::test] +#[cfg_attr(miri, ignore)] async fn test_custom_memory_limiter_async() -> Result<()> { let mut config = Config::new(); config.async_support(true); @@ -840,6 +844,7 @@ impl ResourceLimiterAsync for FailureDetector { } #[tokio::test] +#[cfg_attr(miri, ignore)] async fn custom_limiter_async_detect_grow_failure() -> Result<()> { if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() { return Ok(()); @@ -979,6 +984,7 @@ fn panic_in_memory_limiter() { #[test] #[should_panic(expected = "resource limiter memory growing")] +#[cfg_attr(miri, ignore)] fn panic_in_memory_limiter_wasm_stack() { // Like the test above, except the memory.grow happens in wasm code // instead of a host function call. @@ -1025,6 +1031,7 @@ fn panic_in_table_limiter() { #[tokio::test] #[should_panic(expected = "async resource limiter memory growing")] +#[cfg_attr(miri, ignore)] async fn panic_in_async_memory_limiter() { let mut config = Config::new(); config.async_support(true); @@ -1044,6 +1051,7 @@ async fn panic_in_async_memory_limiter() { #[tokio::test] #[should_panic(expected = "async resource limiter memory growing")] +#[cfg_attr(miri, ignore)] async fn panic_in_async_memory_limiter_wasm_stack() { // Like the test above, except the memory.grow happens in // wasm code instead of a host function call. @@ -1075,6 +1083,7 @@ async fn panic_in_async_memory_limiter_wasm_stack() { #[tokio::test] #[should_panic(expected = "async resource limiter table growing")] +#[cfg_attr(miri, ignore)] async fn panic_in_async_table_limiter() { let mut config = Config::new(); config.async_support(true); @@ -1096,6 +1105,7 @@ async fn panic_in_async_table_limiter() { } #[test] +#[cfg_attr(miri, ignore)] fn growth_trap() -> Result<()> { let engine = Engine::default(); let module = Module::new( diff --git a/tests/all/linker.rs b/tests/all/linker.rs index 7fe580b4c32c..737b2b498117 100644 --- a/tests/all/linker.rs +++ b/tests/all/linker.rs @@ -90,6 +90,7 @@ fn link_twice_bad() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn function_interposition() -> Result<()> { let mut store = Store::<()>::default(); let mut linker = Linker::new(store.engine()); @@ -124,6 +125,7 @@ fn function_interposition() -> Result<()> { // Same as `function_interposition`, but the linker's name for the function // differs from the module's name. #[test] +#[cfg_attr(miri, ignore)] fn function_interposition_renamed() -> Result<()> { let mut store = Store::<()>::default(); let mut linker = Linker::new(store.engine()); @@ -154,6 +156,7 @@ fn function_interposition_renamed() -> Result<()> { // Similar to `function_interposition`, but use `Linker::instance` instead of // `Linker::define`. #[test] +#[cfg_attr(miri, ignore)] fn module_interposition() -> Result<()> { let mut store = Store::<()>::default(); let mut linker = Linker::new(store.engine()); @@ -185,6 +188,7 @@ fn module_interposition() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn allow_unknown_exports() -> Result<()> { let mut store = Store::<()>::default(); let mut linker = Linker::new(store.engine()); @@ -203,6 +207,7 @@ fn allow_unknown_exports() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn no_leak() -> Result<()> { struct DropMe(Rc>); @@ -231,6 +236,7 @@ fn no_leak() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn no_leak_with_imports() -> Result<()> { struct DropMe(Arc); @@ -354,6 +360,7 @@ fn instance_pre() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_trapping_unknown_import() -> Result<()> { const WAT: &str = r#" (module @@ -392,6 +399,7 @@ fn test_trapping_unknown_import() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_default_value_unknown_import() -> Result<()> { const WAT: &str = r#" (module diff --git a/tests/all/main.rs b/tests/all/main.rs index 754492b0cd3d..e9941cc73710 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(miri, allow(dead_code, unused_imports))] + mod async_functions; mod call_hook; mod cli_tests; diff --git a/tests/all/memory.rs b/tests/all/memory.rs index a2eaa0e54acb..ecd1a0ab5881 100644 --- a/tests/all/memory.rs +++ b/tests/all/memory.rs @@ -92,6 +92,7 @@ fn test_traps(store: &mut Store<()>, funcs: &[TestFunc], addr: u32, mem: &Memory } #[test] +#[cfg_attr(miri, ignore)] fn offsets_static_dynamic_oh_my() -> Result<()> { const GB: u64 = 1 << 30; @@ -137,6 +138,7 @@ fn offsets_static_dynamic_oh_my() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn guards_present() -> Result<()> { const GUARD_SIZE: u64 = 65536; @@ -185,6 +187,7 @@ fn guards_present() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn guards_present_pooling() -> Result<()> { const GUARD_SIZE: u64 = 65536; @@ -322,6 +325,7 @@ fn massive_64_bit_still_limited() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn tiny_static_heap() -> Result<()> { // The size of the memory in the module below is the exact same size as // the static memory size limit in the configuration. This is intended to @@ -533,6 +537,7 @@ fn shared_memory_basics() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn shared_memory_wait_notify() -> Result<()> { const THREADS: usize = 8; const COUNT: usize = 100_000; diff --git a/tests/all/memory_creator.rs b/tests/all/memory_creator.rs index 26950ca6169b..3984b2e00c42 100644 --- a/tests/all/memory_creator.rs +++ b/tests/all/memory_creator.rs @@ -1,4 +1,4 @@ -#[cfg(not(target_os = "windows"))] +#[cfg(all(not(target_os = "windows"), not(miri)))] mod not_for_windows { use wasmtime::*; use wasmtime_environ::{WASM32_MAX_PAGES, WASM_PAGE_SIZE}; diff --git a/tests/all/module.rs b/tests/all/module.rs index b1eea2f6516d..9b3b83ab1bb6 100644 --- a/tests/all/module.rs +++ b/tests/all/module.rs @@ -51,6 +51,7 @@ fn caches_across_engines() { } #[test] +#[cfg_attr(miri, ignore)] fn aot_compiles() -> Result<()> { let engine = Engine::default(); let bytes = engine.precompile_module( @@ -69,6 +70,7 @@ fn aot_compiles() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn serialize_deterministic() { let engine = Engine::default(); @@ -177,7 +179,7 @@ fn serialize_not_overly_massive() -> Result<()> { // This test then also tests that loading modules through various means, e.g. // through precompiled artifacts, all works. #[test] -#[cfg_attr(not(target_arch = "x86_64"), ignore)] +#[cfg_attr(any(not(target_arch = "x86_64"), miri), ignore)] fn missing_sse_and_floats_still_works() -> Result<()> { let mut config = Config::new(); config.wasm_simd(false); diff --git a/tests/all/module_serialize.rs b/tests/all/module_serialize.rs index 614803019ef6..023018528f60 100644 --- a/tests/all/module_serialize.rs +++ b/tests/all/module_serialize.rs @@ -43,6 +43,7 @@ fn test_version_mismatch() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_module_serialize_simple() -> Result<()> { let buffer = serialize( &Engine::default(), @@ -59,6 +60,7 @@ fn test_module_serialize_simple() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_module_serialize_fail() -> Result<()> { let buffer = serialize( &Engine::default(), @@ -76,6 +78,7 @@ fn test_module_serialize_fail() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_deserialize_from_file() -> Result<()> { serialize_and_call("(module (func (export \"run\") (result i32) i32.const 42))")?; serialize_and_call( @@ -105,6 +108,7 @@ fn test_deserialize_from_file() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn deserialize_from_serialized() -> Result<()> { let engine = Engine::default(); let buffer1 = serialize( diff --git a/tests/all/name.rs b/tests/all/name.rs index ec6095b23557..5e64e1935632 100644 --- a/tests/all/name.rs +++ b/tests/all/name.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use wasmtime::*; #[test] diff --git a/tests/all/pooling_allocator.rs b/tests/all/pooling_allocator.rs index 8eaafbf63a64..e015ee02680f 100644 --- a/tests/all/pooling_allocator.rs +++ b/tests/all/pooling_allocator.rs @@ -25,6 +25,7 @@ fn successful_instantiation() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn memory_limit() -> Result<()> { let mut pool = PoolingAllocationConfig::default(); pool.instance_count(1) @@ -112,7 +113,13 @@ fn memory_init() -> Result<()> { let module = Module::new( &engine, - r#"(module (memory (export "m") 2) (data (i32.const 65530) "this data spans multiple pages") (data (i32.const 10) "hello world"))"#, + r#" + (module + (memory (export "m") 2) + (data (i32.const 65530) "this data spans multiple pages") + (data (i32.const 10) "hello world") + ) + "#, )?; let mut store = Store::new(&engine, ()); @@ -129,6 +136,7 @@ fn memory_init() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn memory_guard_page_trap() -> Result<()> { let mut pool = PoolingAllocationConfig::default(); pool.instance_count(1) @@ -141,7 +149,12 @@ fn memory_guard_page_trap() -> Result<()> { let module = Module::new( &engine, - r#"(module (memory (export "m") 0) (func (export "f") (param i32) local.get 0 i32.load drop))"#, + r#" + (module + (memory (export "m") 0) + (func (export "f") (param i32) local.get 0 i32.load drop) + ) + "#, )?; // Instantiate the module and check for out of bounds trap @@ -231,6 +244,7 @@ fn memory_zeroed() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn table_limit() -> Result<()> { const TABLE_ELEMENTS: u32 = 10; let mut pool = PoolingAllocationConfig::default(); @@ -315,6 +329,7 @@ fn table_limit() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn table_init() -> Result<()> { let mut pool = PoolingAllocationConfig::default(); pool.instance_count(1) @@ -327,7 +342,18 @@ fn table_init() -> Result<()> { let module = Module::new( &engine, - r#"(module (table (export "t") 6 funcref) (elem (i32.const 1) 1 2 3 4) (elem (i32.const 0) 0) (func) (func (param i32)) (func (param i32 i32)) (func (param i32 i32 i32)) (func (param i32 i32 i32 i32)))"#, + r#" + (module + (table (export "t") 6 funcref) + (elem (i32.const 1) 1 2 3 4) + (elem (i32.const 0) 0) + (func) + (func (param i32)) + (func (param i32 i32)) + (func (param i32 i32 i32)) + (func (param i32 i32 i32 i32)) + ) + "#, )?; let mut store = Store::new(&engine, ()); @@ -473,15 +499,17 @@ fn preserve_data_segments() -> Result<()> { // Spray some stuff on the heap. If wasm data lived on the heap this should // paper over things and help us catch use-after-free here if it would // otherwise happen. - let mut strings = Vec::new(); - for _ in 0..1000 { - let mut string = String::new(); + if !cfg!(miri) { + let mut strings = Vec::new(); for _ in 0..1000 { - string.push('g'); + let mut string = String::new(); + for _ in 0..1000 { + string.push('g'); + } + strings.push(string); } - strings.push(string); + drop(strings); } - drop(strings); let mem = i.get_memory(&mut store, "mem").unwrap(); @@ -580,6 +608,7 @@ fn drop_externref_global_during_module_init() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn switch_image_and_non_image() -> Result<()> { let mut pool = PoolingAllocationConfig::default(); pool.instance_count(1); @@ -638,6 +667,7 @@ fn switch_image_and_non_image() -> Result<()> { #[test] #[cfg(target_pointer_width = "64")] +#[cfg_attr(miri, ignore)] fn instance_too_large() -> Result<()> { let mut pool = PoolingAllocationConfig::default(); pool.instance_size(16).instance_count(1); @@ -679,6 +709,7 @@ configured maximum of 16 bytes; breakdown of allocation requirement: } #[test] +#[cfg_attr(miri, ignore)] fn dynamic_memory_pooling_allocator() -> Result<()> { for guard_size in [0, 1 << 16] { let max_size = 128 << 20; @@ -787,6 +818,7 @@ fn dynamic_memory_pooling_allocator() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn zero_memory_pages_disallows_oob() -> Result<()> { let mut pool = PoolingAllocationConfig::default(); pool.instance_count(1).instance_memory_pages(0); diff --git a/tests/all/relocs.rs b/tests/all/relocs.rs index a27ff6a001ef..db2feee5dbc3 100644 --- a/tests/all/relocs.rs +++ b/tests/all/relocs.rs @@ -8,6 +8,8 @@ //! 32-bits, and right now object files aren't supported larger than 4gb anyway //! so we would need a lot of other support necessary to exercise that. +#![cfg(not(miri))] + use anyhow::Result; use wasmtime::*; diff --git a/tests/all/stack_overflow.rs b/tests/all/stack_overflow.rs index f2e2417d46c7..ec534b7af594 100644 --- a/tests/all/stack_overflow.rs +++ b/tests/all/stack_overflow.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::Result; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use wasmtime::*; diff --git a/tests/all/table.rs b/tests/all/table.rs index 8bc62f4f1a14..2b22c2ee7631 100644 --- a/tests/all/table.rs +++ b/tests/all/table.rs @@ -53,6 +53,7 @@ fn copy_wrong() { } #[test] +#[cfg_attr(miri, ignore)] fn null_elem_segment_works_with_imported_table() -> Result<()> { let mut store = Store::<()>::default(); let ty = TableType::new(ValType::FuncRef, 1, None); diff --git a/tests/all/threads.rs b/tests/all/threads.rs index 30ca86bdd3ae..b08daf279163 100644 --- a/tests/all/threads.rs +++ b/tests/all/threads.rs @@ -52,6 +52,7 @@ fn test_export_shared_memory() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_sharing_of_shared_memory() -> Result<()> { let wat = r#"(module (import "env" "memory" (memory 1 5 shared)) @@ -95,6 +96,7 @@ fn test_sharing_of_shared_memory() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_probe_shared_memory_size() -> Result<()> { let wat = r#"(module (memory (export "memory") 1 2 shared) @@ -157,6 +159,7 @@ fn test_multi_memory() -> Result<()> { } #[test] +#[cfg_attr(miri, ignore)] fn test_grow_memory_in_multiple_threads() -> Result<()> { const NUM_THREADS: usize = 4; const NUM_GROW_OPS: usize = 1000; @@ -226,6 +229,7 @@ fn is_sorted(data: &[u32]) -> bool { } #[test] +#[cfg_attr(miri, ignore)] fn test_memory_size_accessibility() -> Result<()> { const NUM_GROW_OPS: usize = 1000; let wat = r#"(module diff --git a/tests/all/traps.rs b/tests/all/traps.rs index a5f7463cadf9..183ce2d408f9 100644 --- a/tests/all/traps.rs +++ b/tests/all/traps.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::{bail, Error, Result}; use std::panic::{self, AssertUnwindSafe}; use std::process::Command; diff --git a/tests/all/wait_notify.rs b/tests/all/wait_notify.rs index 930b49744a49..fb95e5d6baa9 100644 --- a/tests/all/wait_notify.rs +++ b/tests/all/wait_notify.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use anyhow::Result; use std::time::Instant; use wasmtime::*; diff --git a/tests/all/wasi_testsuite.rs b/tests/all/wasi_testsuite.rs index 81d2bf434a43..680715eb7b43 100644 --- a/tests/all/wasi_testsuite.rs +++ b/tests/all/wasi_testsuite.rs @@ -3,6 +3,8 @@ //! //! [wasi-testsuite]: https://github.com/WebAssembly/wasi-testsuite +#![cfg(not(miri))] + use crate::cli_tests::run_wasmtime_for_output; use anyhow::Result; use serde::Deserialize; diff --git a/tests/host_segfault.rs b/tests/host_segfault.rs index 404fb4947028..8c6112df3597 100644 --- a/tests/host_segfault.rs +++ b/tests/host_segfault.rs @@ -80,6 +80,9 @@ fn dummy_waker() -> Waker { } fn main() { + if cfg!(miri) { + return; + } // Skip this tests if it looks like we're in a cross-compiled situation and // we're emulating this test for a different platform. In that scenario // emulators (like QEMU) tend to not report signals the same way and such. diff --git a/tests/rlimited-memory.rs b/tests/rlimited-memory.rs index 810ea07d5d2c..bd57fdd0c95c 100644 --- a/tests/rlimited-memory.rs +++ b/tests/rlimited-memory.rs @@ -37,6 +37,7 @@ impl ResourceLimiter for MemoryGrowFailureDetector { } #[test] +#[cfg_attr(miri, ignore)] fn custom_limiter_detect_os_oom_failure() -> Result<()> { if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() { return Ok(());