From 406135cd7e80ab07111e9570bf6aabacaf6e3948 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Jun 2026 09:34:59 -0700 Subject: [PATCH 1/6] Disable signals-based-traps in s390x in CI The many-failures-per-week is becoming quite onerous. I'm getting more desperate to try anything to at least work around this issue. This is an attempt based on LLM-analysis saying that the signal handler has funny things going on. No idea if this will fix anything, and we'll have to monitor this over time. Otherwise this is intended to be as lightweight and unobtrusive as possible to make it easy to excise if needed. --- crates/wasmtime/build.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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() } From e33da53763f1c26a3fb91e2e8fb1aca9f4d2f4e5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Jun 2026 11:31:09 -0700 Subject: [PATCH 2/6] Try to fix warnings --- crates/wasmtime/src/runtime/vm/traphandlers.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/wasmtime/src/runtime/vm/traphandlers.rs b/crates/wasmtime/src/runtime/vm/traphandlers.rs index e67fac2b83fb..a2cecf05d15f 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")] From 6986a2b6370ac41203c5ec5c11f154bb1b25af48 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Jun 2026 12:24:39 -0700 Subject: [PATCH 3/6] Try another cfg combo prtest:full --- crates/wasmtime/src/runtime/vm/interpreter.rs | 2 +- crates/wasmtime/src/runtime/vm/traphandlers.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) 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 a2cecf05d15f..457754539e32 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers.rs @@ -56,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), From 6294643b647e75a4b79a5ac59ad11d4a02bdbda1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Jun 2026 13:54:44 -0700 Subject: [PATCH 4/6] Adjust some tests --- crates/wasmtime/src/engine/serialization.rs | 1 + tests/all/pooling_allocator.rs | 8 +++++++- tests/all/traps.rs | 22 ++++++++++++--------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index 24001e15181e..03b4345c2e2d 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -611,6 +611,7 @@ mod test { #[test] #[cfg_attr(miri, ignore)] + #[cfg_attr(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/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..ad61012c03e2 100644 --- a/tests/all/traps.rs +++ b/tests/all/traps.rs @@ -1303,7 +1303,14 @@ 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); + // 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. + let Ok(engine) = Engine::new(&config) else { + return Ok(()); + }; let mut store = Store::new(&engine, ()); let module = Module::new( &engine, @@ -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(()) } From e91294583a07bc341a67d9ebfb55eba19ebcc569 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Jun 2026 14:02:37 -0700 Subject: [PATCH 5/6] Adjust attributes --- crates/wasmtime/src/engine/serialization.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index 03b4345c2e2d..3eeb11c7e2f1 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -610,8 +610,7 @@ mod test { } #[test] - #[cfg_attr(miri, ignore)] - #[cfg_attr(not(has_native_signals), 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(); From 3877d54c9fdb676bfeb596009e26eb4bbf6fbc1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Jun 2026 14:51:51 -0700 Subject: [PATCH 6/6] Adjust test --- tests/all/traps.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/all/traps.rs b/tests/all/traps.rs index ad61012c03e2..b80bfa705952 100644 --- a/tests/all/traps.rs +++ b/tests/all/traps.rs @@ -1305,14 +1305,9 @@ fn div_plus_load_reported_right() -> Result<()> { fn wasm_fault_address_reported_by_default() -> Result<()> { let mut config = Config::new(); config.signals_based_traps(true); - // 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. - let Ok(engine) = Engine::new(&config) else { - return Ok(()); - }; + let engine = Engine::new(&config)?; let mut store = Store::new(&engine, ()); - let module = Module::new( + let Ok(module) = Module::new( &engine, r#" (module @@ -1324,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