From 0f48f939b9870036562ca02ff21253547a9f1a5c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Jun 2024 18:08:43 -0500 Subject: [PATCH] Disable memory protection keys by default at compile time (#8813) * Disable memory protection keys by default at compile time This commit gates memory protection keys behind a new Cargo feature which is disabled by default. Memory protection keys are already disabled by default on all platforms and are only configured to possibly work with Linux x64. When enabled, however, it unconditionally adds a small amount of overhead to WebAssembly entries/exits even if the feature is disabled at runtime for the same reason that the `call-hook` feature adds overhead. With `call-hook` being disabled by default in #8808 it seemed reasonable to additionally gate memory protection keys to avoid needing to disable features in Wasmtime to get the best performance wasm<->host calls. * Enable Wasmtime feature for fuzzing --- Cargo.toml | 3 ++- crates/cli-flags/Cargo.toml | 3 ++- crates/cli-flags/src/lib.rs | 12 ++++++++---- crates/fuzzing/Cargo.toml | 2 +- crates/wasmtime/Cargo.toml | 4 ++++ crates/wasmtime/src/config.rs | 7 ++++--- crates/wasmtime/src/lib.rs | 7 +++++++ crates/wasmtime/src/runtime/vm/mpk/mod.rs | 3 +-- 8 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3f3115cd3874..b2b8fcf8dbc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,7 @@ rustix = { workspace = true, features = ["mm", "param", "process"] } [dev-dependencies] # depend again on wasmtime to activate its default features for tests -wasmtime = { workspace = true, features = ['default', 'winch', 'all-arch', 'call-hook'] } +wasmtime = { workspace = true, features = ['default', 'winch', 'all-arch', 'call-hook', 'memory-protection-keys'] } env_logger = { workspace = true } log = { workspace = true } filecheck = { workspace = true } @@ -376,6 +376,7 @@ default = [ all-arch = ["wasmtime/all-arch"] winch = ["wasmtime/winch"] wmemcheck = ["wasmtime/wmemcheck"] +memory-protection-keys = ["wasmtime-cli-flags/memory-protection-keys"] # This feature, when enabled, will statically compile out all logging statements # throughout Wasmtime and its dependencies. diff --git a/crates/cli-flags/Cargo.toml b/crates/cli-flags/Cargo.toml index 4ed645c7c2f2..12ef9fb053e8 100644 --- a/crates/cli-flags/Cargo.toml +++ b/crates/cli-flags/Cargo.toml @@ -21,7 +21,7 @@ wasmtime = { workspace = true, features = ["gc"] } humantime = { workspace = true } [features] -pooling-allocator = [] +pooling-allocator = ["wasmtime/pooling-allocator"] component-model = ["wasmtime/component-model"] cache = ["wasmtime/cache"] parallel-compilation = ["wasmtime/parallel-compilation", "dep:rayon"] @@ -30,3 +30,4 @@ cranelift = ["wasmtime/cranelift"] coredump = ["wasmtime/coredump"] gc = ["wasmtime/gc"] threads = ["wasmtime/threads"] +memory-protection-keys = ["wasmtime/memory-protection-keys"] diff --git a/crates/cli-flags/src/lib.rs b/crates/cli-flags/src/lib.rs index 743f31c1fd1c..89f1472ba4a2 100644 --- a/crates/cli-flags/src/lib.rs +++ b/crates/cli-flags/src/lib.rs @@ -612,10 +612,14 @@ impl CommonOptions { if let Some(limit) = self.opts.pooling_max_memory_size { cfg.max_memory_size(limit); } - if let Some(enable) = self.opts.memory_protection_keys { - if enable { - cfg.memory_protection_keys(wasmtime::MpkEnabled::Enable); - } + match_feature! { + ["memory-protection-keys" : self.opts.memory_protection_keys] + enable => cfg.memory_protection_keys(if enable { + wasmtime::MpkEnabled::Enable + } else { + wasmtime::MpkEnabled::Disable + }), + _ => err, } config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling(cfg)); } diff --git a/crates/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml index ddaa4ad5737c..d4757a7db8bc 100644 --- a/crates/fuzzing/Cargo.toml +++ b/crates/fuzzing/Cargo.toml @@ -22,7 +22,7 @@ target-lexicon = { workspace = true } tempfile = "3.3.0" wasmparser = { workspace = true } wasmprinter = { workspace = true } -wasmtime = { workspace = true, features = ['default', 'winch', 'gc'] } +wasmtime = { workspace = true, features = ['default', 'winch', 'gc', 'memory-protection-keys'] } wasmtime-wast = { workspace = true } wasm-encoder = { workspace = true } wasm-smith = { workspace = true } diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 7a8aa7766439..c76b3f90d8b6 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -264,3 +264,7 @@ std = [ # logic around all entries/exits from WebAssembly. This has a slight performance # cost for all host functions. call-hook = [] + +# Enables support for "memory protection keys" which can be used in conjunction +# with the pooling allocator on x64 to compact linear memory allocations. +memory-protection-keys = ["pooling-allocator"] diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 707e6b386d6d..9f40bc70b329 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -28,8 +28,6 @@ use crate::stack::{StackCreator, StackCreatorProxy}; #[cfg(feature = "async")] use wasmtime_fiber::RuntimeFiberStackCreator; -#[cfg(feature = "pooling-allocator")] -use crate::runtime::vm::mpk; #[cfg(feature = "pooling-allocator")] pub use crate::runtime::vm::MpkEnabled; #[cfg(all(feature = "incremental-cache", feature = "cranelift"))] @@ -2821,6 +2819,7 @@ impl PoolingAllocationConfig { /// your own risk! MPK uses kernel and CPU features to protect memory /// regions; you may observe segmentation faults if anything is /// misconfigured. + #[cfg(feature = "memory-protection-keys")] pub fn memory_protection_keys(&mut self, enable: MpkEnabled) -> &mut Self { self.config.memory_protection_keys = enable; self @@ -2838,6 +2837,7 @@ impl PoolingAllocationConfig { /// engines will share the same set of allocated keys; this setting will /// limit how many keys are allocated initially and thus available to all /// other engines. + #[cfg(feature = "memory-protection-keys")] pub fn max_memory_protection_keys(&mut self, max: usize) -> &mut Self { self.config.max_memory_protection_keys = max; self @@ -2849,8 +2849,9 @@ impl PoolingAllocationConfig { /// same method that [`MpkEnabled::Auto`] does. See /// [`PoolingAllocationConfig::memory_protection_keys`] for more /// information. + #[cfg(feature = "memory-protection-keys")] pub fn are_memory_protection_keys_available() -> bool { - mpk::is_supported() + crate::runtime::vm::mpk::is_supported() } /// The maximum number of concurrent GC heaps supported (default is `1000`). diff --git a/crates/wasmtime/src/lib.rs b/crates/wasmtime/src/lib.rs index baed60ec0d04..bedba1e4e846 100644 --- a/crates/wasmtime/src/lib.rs +++ b/crates/wasmtime/src/lib.rs @@ -259,6 +259,13 @@ //! entries/exits from WebAssembly and may want to be disabled by some //! embedders. //! +//! * `memory-protection-keys` - Disabled by default, this enables support for +//! the [`PoolingAllocationConfig::memory_protection_keys`] API. This feature +//! currently only works on x64 Linux and can enable compacting the virtual +//! memory allocation for linear memories in the pooling allocator. This comes +//! with the same overhead as the `call-hook` feature where entries/exits into +//! WebAssembly will have more overhead than before. +//! //! More crate features can be found in the [manifest] of Wasmtime itself for //! seeing what can be enabled and disabled. //! diff --git a/crates/wasmtime/src/runtime/vm/mpk/mod.rs b/crates/wasmtime/src/runtime/vm/mpk/mod.rs index 12ac3370201a..844c35b4378e 100644 --- a/crates/wasmtime/src/runtime/vm/mpk/mod.rs +++ b/crates/wasmtime/src/runtime/vm/mpk/mod.rs @@ -33,8 +33,7 @@ cfg_if::cfg_if! { if #[cfg(all( target_arch = "x86_64", target_os = "linux", - feature = "pooling-allocator", - feature = "std", + feature = "memory-protection-keys", not(miri), ))] { mod enabled;