diff --git a/crates/wasmtime/build.rs b/crates/wasmtime/build.rs index 33f9c78b91ca..ade2dbc5156b 100644 --- a/crates/wasmtime/build.rs +++ b/crates/wasmtime/build.rs @@ -24,7 +24,8 @@ fn main() { let has_native_signals = !miri && (supported_os || cfg!(feature = "custom-native-signals")) - && has_host_compiler_backend; + && has_host_compiler_backend + && !is_buggy_s390x_qemu_emulation(); let has_virtual_memory = supported_os || cfg!(feature = "custom-virtual-memory"); let has_custom_sync = !cfg!(feature = "std") && cfg!(feature = "custom-sync-primitives") @@ -59,6 +60,21 @@ fn main() { } } +// Attempts to detect if we're running in Wasmtime's CI, testing s390x, and +// testing s390x under QEMU. In this situation we're experiencing flaky +// failures, more info in #10000, and current LLM-based analysis seems to point +// to the signal handler state being corrupted in emulation. We're seeing +// many spurious failures per week so this is a bit of a last-ditch attempt to +// work around the issue. In this situation we pretend that native signals are +// not available for s390x which forces disabling signals-based-traps which in +// theory means we don't rely on signal handlers... +fn is_buggy_s390x_qemu_emulation() -> bool { + std::env::var("CI").is_ok() + && std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() + && std::env::var("QEMU_BUILD_VERSION").is_ok() + && std::env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "s390x" +} + fn cfg(key: &str) -> bool { std::env::var(&format!("CARGO_CFG_{}", key.to_uppercase())).is_ok() } diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index 24001e15181e..3eeb11c7e2f1 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -610,7 +610,7 @@ mod test { } #[test] - #[cfg_attr(miri, ignore)] + #[cfg_attr(any(miri, not(has_native_signals)), ignore)] #[cfg(target_pointer_width = "64")] // different defaults on 32-bit platforms fn test_tunables_int_mismatch() -> Result<()> { let engine = Engine::default(); diff --git a/crates/wasmtime/src/runtime/vm/interpreter.rs b/crates/wasmtime/src/runtime/vm/interpreter.rs index 849108786de1..a32c26bb1c4d 100644 --- a/crates/wasmtime/src/runtime/vm/interpreter.rs +++ b/crates/wasmtime/src/runtime/vm/interpreter.rs @@ -483,7 +483,7 @@ impl InterpreterRef<'_> { } // Not possible with our closure above returning `false`. - #[cfg(has_host_compiler_backend)] + #[cfg(has_native_signals)] TrapTest::HandledByEmbedder => unreachable!(), // Trap was handled, yay! Configure interpreter state diff --git a/crates/wasmtime/src/runtime/vm/traphandlers.rs b/crates/wasmtime/src/runtime/vm/traphandlers.rs index e67fac2b83fb..457754539e32 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers.rs @@ -1,6 +1,11 @@ //! WebAssembly trap handling, which is built on top of the lower-level //! signalhandling mechanisms. +#![cfg_attr( + all(not(has_native_signals), not(feature = "pulley")), + expect(unused, reason = "easier to not #[cfg] methods and all related types") +)] + mod backtrace; #[cfg(feature = "coredump")] @@ -51,8 +56,7 @@ pub(crate) enum TrapTest { /// Not a wasm trap, need to delegate to whatever process handler is next. NotWasm, /// This trap was handled by the embedder via custom embedding APIs. - #[cfg(has_host_compiler_backend)] - #[cfg_attr(miri, expect(dead_code, reason = "using #[cfg] too unergonomic"))] + #[cfg(all(has_native_signals, not(miri)))] HandledByEmbedder, /// This is a wasm trap, it needs to be handled. Trap(Handler), diff --git a/tests/all/pooling_allocator.rs b/tests/all/pooling_allocator.rs index ffb7482003ca..fc19983934ca 100644 --- a/tests/all/pooling_allocator.rs +++ b/tests/all/pooling_allocator.rs @@ -713,7 +713,13 @@ fn dynamic_memory_pooling_allocator() -> Result<()> { ) else { // Ignore invalid configurations on 32-bit which can't run with // signals-based-traps. - assert!(cfg!(target_pointer_width = "32") && signals_based_traps); + // + // Note that s390x in CI also skip this because it's not using + // signals-based-traps. + assert!( + cfg!(target_arch = "s390x") + || (cfg!(target_pointer_width = "32") && signals_based_traps) + ); continue; }; diff --git a/tests/all/traps.rs b/tests/all/traps.rs index c9a1ad3447be..b80bfa705952 100644 --- a/tests/all/traps.rs +++ b/tests/all/traps.rs @@ -1303,9 +1303,11 @@ fn div_plus_load_reported_right() -> Result<()> { #[test] fn wasm_fault_address_reported_by_default() -> Result<()> { - let engine = Engine::default(); + let mut config = Config::new(); + config.signals_based_traps(true); + let engine = Engine::new(&config)?; let mut store = Store::new(&engine, ()); - let module = Module::new( + let Ok(module) = Module::new( &engine, r#" (module @@ -1317,7 +1319,12 @@ fn wasm_fault_address_reported_by_default() -> Result<()> { (start $start) ) "#, - )?; + ) else { + // This test requires a host that supports signals-based-traps to report + // the faulting address. If that configuration isn't supported by this + // host then skip the test. + return Ok(()); + }; let err = Instance::new(&mut store, &module, &[]).unwrap_err(); // NB: at this time there's no programmatic access to the fault address @@ -1329,15 +1336,12 @@ fn wasm_fault_address_reported_by_default() -> Result<()> { // It looks like the exact reported fault address may not be deterministic, // so assert that we have the right error message, but not the exact // address. - // - // Skip 32-bit platforms here which currently all use Pulley and don't use - // virtual memory for catching traps. This means that the trap error isn't - // available. let err = format!("{err:?}"); - let contains_address = err.contains("memory fault at wasm address ") - && err.contains(" in linear memory of size 0x10000"); - let address_expected = cfg!(target_pointer_width = "64"); - assert_eq!(contains_address, address_expected, "bad error: {err}"); + assert!( + err.contains("memory fault at wasm address ") + && err.contains(" in linear memory of size 0x10000"), + "bad error: {err}" + ); Ok(()) }