Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion crates/wasmtime/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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()
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/engine/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/runtime/vm/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions crates/wasmtime/src/runtime/vm/traphandlers.rs
Original file line number Diff line number Diff line change
@@ -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")]
Expand Down Expand Up @@ -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),
Expand Down
8 changes: 7 additions & 1 deletion tests/all/pooling_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
26 changes: 15 additions & 11 deletions tests/all/traps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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(())
}

Expand Down
Loading