diff --git a/cranelift/codegen/src/result.rs b/cranelift/codegen/src/result.rs index 9cbef79795..9d73bd0f62 100644 --- a/cranelift/codegen/src/result.rs +++ b/cranelift/codegen/src/result.rs @@ -77,6 +77,9 @@ impl std::fmt::Display for CodegenError { #[cfg(feature = "unwind")] CodegenError::RegisterMappingError(_0) => write!(f, "Register mapping error"), CodegenError::Regalloc(errors) => write!(f, "Regalloc validation errors: {:?}", errors), + + // NOTE: if this is changed, please update the `is_pcc_error` function defined in + // `wasmtime/crates/fuzzing/src/oracles.rs` CodegenError::Pcc(e) => write!(f, "Proof-carrying-code validation error: {:?}", e), } } diff --git a/crates/fuzzing/src/generators/config.rs b/crates/fuzzing/src/generators/config.rs index 7c47300c4f..c974af2d7f 100644 --- a/crates/fuzzing/src/generators/config.rs +++ b/crates/fuzzing/src/generators/config.rs @@ -1,7 +1,8 @@ //! Generate a configuration for both Wasmtime and the Wasm module to execute. use super::{ - CodegenSettings, InstanceAllocationStrategy, MemoryConfig, ModuleConfig, UnalignedMemoryCreator, + CodegenSettings, InstanceAllocationStrategy, MemoryConfig, ModuleConfig, NormalMemoryConfig, + UnalignedMemoryCreator, }; use crate::oracles::{StoreLimits, Timeout}; use anyhow::Result; @@ -215,6 +216,8 @@ impl Config { ); } } + + cfg.cranelift_pcc(self.wasmtime.pcc); } // Vary the memory configuration, but only if threads are not enabled. @@ -228,7 +231,20 @@ impl Config { // `CustomUnaligned` variant isn't actually safe to use with a shared // memory. if !self.module_config.config.threads_enabled { - match &self.wasmtime.memory_config { + // If PCC is enabled, force other options to be compatible: PCC is currently only + // supported when bounds checks are elided. + let memory_config = if self.wasmtime.pcc { + MemoryConfig::Normal(NormalMemoryConfig { + static_memory_maximum_size: Some(4 << 30), // 4 GiB + static_memory_guard_size: Some(2 << 30), // 2 GiB + dynamic_memory_guard_size: Some(0), + guard_before_linear_memory: false, + }) + } else { + self.wasmtime.memory_config.clone() + }; + + match &memory_config { MemoryConfig::Normal(memory_config) => { cfg.static_memory_maximum_size( memory_config.static_memory_maximum_size.unwrap_or(0), @@ -429,6 +445,9 @@ pub struct WasmtimeConfig { native_unwind_info: bool, /// Configuration for the compiler to use. pub compiler_strategy: CompilerStrategy, + + /// Whether or not fuzzing should enable PCC. + pcc: bool, } impl WasmtimeConfig { diff --git a/crates/fuzzing/src/oracles.rs b/crates/fuzzing/src/oracles.rs index bb3bc14504..66a17e5923 100644 --- a/crates/fuzzing/src/oracles.rs +++ b/crates/fuzzing/src/oracles.rs @@ -256,8 +256,18 @@ fn compile_module( config: &generators::Config, ) -> Option { log_wasm(bytes); + + fn is_pcc_error(e: &anyhow::Error) -> bool { + // NOTE: please keep this predicate in sync with the display format of CodegenError, + // defined in `wasmtime/cranelift/codegen/src/result.rs` + e.to_string().to_lowercase().contains("proof-carrying-code") + } + match config.compile(engine, bytes) { Ok(module) => Some(module), + Err(e) if is_pcc_error(&e) => { + panic!("pcc error in input: {e:#?}"); + } Err(_) if known_valid == KnownValid::No => None, Err(e) => { if let generators::InstanceAllocationStrategy::Pooling(c) = &config.wasmtime.strategy { diff --git a/tests/pcc_memory.rs b/tests/pcc_memory.rs index dddff2a5ba..dd54cf02b3 100644 --- a/tests/pcc_memory.rs +++ b/tests/pcc_memory.rs @@ -8,132 +8,44 @@ mod pcc_memory_tests { const TESTS: &'static [&'static str] = &[ r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i32.load8_u - drop)) + drop "#, r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i32.load8_u offset=0x10000 - drop)) + drop "#, r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i32.load16_u - drop)) + drop "#, r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i32.load16_u offset=0x10000 - drop)) + drop "#, r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i32.load - drop)) + drop "#, r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i32.load offset=0x10000 - drop)) + drop "#, r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i64.load - drop)) + drop "#, r#" -(module - (memory 1 1) - (func (param i32) local.get 0 i64.load offset=0x10000 - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i32.load8_u - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i32.load8_u offset=0x10000 - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i32.load16_u - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i32.load16_u offset=0x10000 - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i32.load - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i32.load offset=0x10000 - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i64.load - drop)) - "#, - r#" -(module - (memory 10 20) - (func (param i32) - local.get 0 - i64.load offset=0x10000 - drop)) + drop "#, ]; @@ -145,9 +57,26 @@ mod pcc_memory_tests { const MIB: u64 = 1024 * KIB; const GIB: u64 = 1024 * MIB; - for &test in TESTS { - for static_memory_maximum_size in [0, 64 * KIB, 1 * MIB, 4 * GIB, 6 * GIB] { - for guard_size in [0, 64 * KIB, 2 * GIB] { + let mut bodies = vec![]; + for (mem_min, mem_max) in [(1, 1), (10, 20)] { + for &snippet in TESTS { + bodies.push(format!( + "(module (memory {mem_min} {mem_max}) (func (param i32) {snippet}))" + )); + } + let all_snippets = TESTS + .iter() + .map(|s| s.to_owned()) + .collect::>() + .join("\n"); + bodies.push(format!( + "(module (memory {mem_min} {mem_max}) (func (param i32) {all_snippets}))" + )); + } + + for test in &bodies { + for static_memory_maximum_size in [4 * GIB] { + for guard_size in [2 * GIB] { for enable_spectre in [true /* not yet supported by PCC: false */] { for _memory_bits in [32 /* not yet supported by PCC: 64 */] { log::trace!("test:\n{}\n", test);