Update memfd support with a runtime toggle (#3778)
This commit updates the `memfd` support in Wasmtime to have a runtime toggle as to whether it's used or not. The compile-time feature gating `memfd` support is now also re-enabled by default, but the new runtime switch is still disabled-by-default. Additionally this commit updates our fuzz oracle to turn on/off the memfd flag to re-enable fuzzing with memfd on oss-fuzz.
This commit is contained in:
@@ -61,6 +61,7 @@ pub struct WasmtimeConfig {
|
||||
pub(crate) consume_fuel: bool,
|
||||
memory_config: MemoryConfig,
|
||||
force_jump_veneers: bool,
|
||||
memfd: bool,
|
||||
}
|
||||
|
||||
#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
|
||||
@@ -99,7 +100,8 @@ impl Config {
|
||||
.cranelift_nan_canonicalization(self.wasmtime.canonicalize_nans)
|
||||
.cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime())
|
||||
.interruptable(self.wasmtime.interruptable)
|
||||
.consume_fuel(self.wasmtime.consume_fuel);
|
||||
.consume_fuel(self.wasmtime.consume_fuel)
|
||||
.memfd(self.wasmtime.memfd);
|
||||
|
||||
// If the wasm-smith-generated module use nan canonicalization then we
|
||||
// don't need to enable it, but if it doesn't enable it already then we
|
||||
|
||||
@@ -51,7 +51,16 @@ wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync" }
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[features]
|
||||
default = ['async', 'cache', 'wat', 'jitdump', 'parallel-compilation', 'cranelift', 'pooling-allocator']
|
||||
default = [
|
||||
'async',
|
||||
'cache',
|
||||
'wat',
|
||||
'jitdump',
|
||||
'parallel-compilation',
|
||||
'cranelift',
|
||||
'pooling-allocator',
|
||||
'memfd',
|
||||
]
|
||||
|
||||
# An on-by-default feature enabling runtime compilation of WebAssembly modules
|
||||
# with the Cranelift compiler. Cranelift is the default compilation backend of
|
||||
|
||||
@@ -104,6 +104,7 @@ pub struct Config {
|
||||
pub(crate) module_version: ModuleVersionStrategy,
|
||||
pub(crate) parallel_compilation: bool,
|
||||
pub(crate) paged_memory_initialization: bool,
|
||||
pub(crate) memfd: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -129,6 +130,7 @@ impl Config {
|
||||
parallel_compilation: true,
|
||||
// Default to paged memory initialization when using uffd on linux
|
||||
paged_memory_initialization: cfg!(all(target_os = "linux", feature = "uffd")),
|
||||
memfd: false,
|
||||
};
|
||||
#[cfg(compiler)]
|
||||
{
|
||||
@@ -1170,6 +1172,33 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures whether `memfd`, if supported, will be used to initialize
|
||||
/// applicable module memories.
|
||||
///
|
||||
/// This is a Linux-specific feature since `memfd` is only supported on
|
||||
/// Linux. Support for this is also enabled by default at compile time but
|
||||
/// is otherwise disabled at runtime by default. This feature needs to be
|
||||
/// enabled to `true` for support to be used.
|
||||
///
|
||||
/// Also note that even if this feature is enabled it may not be applicable
|
||||
/// to all memories in all wasm modules. At this time memories must meet
|
||||
/// specific criteria to be memfd-initialized:
|
||||
///
|
||||
/// * Only memories defined in the module can be initialized this way.
|
||||
/// * Data segments for memory must use statically known offsets.
|
||||
/// * Data segments for memory must all be in-bounds.
|
||||
///
|
||||
/// If all of the above applies, this setting is enabled, and the current
|
||||
/// platform is Linux the `memfd` will be used to efficiently initialize
|
||||
/// linear memories with `mmap` to avoid copying data from initializers into
|
||||
/// linear memory.
|
||||
#[cfg(feature = "memfd")]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "memfd")))]
|
||||
pub fn memfd(&mut self, memfd: bool) -> &mut Self {
|
||||
self.memfd = memfd;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build_allocator(&self) -> Result<Box<dyn InstanceAllocator>> {
|
||||
#[cfg(feature = "async")]
|
||||
let stack_size = self.async_stack_size;
|
||||
@@ -1239,6 +1268,7 @@ impl Clone for Config {
|
||||
module_version: self.module_version.clone(),
|
||||
parallel_compilation: self.parallel_compilation,
|
||||
paged_memory_initialization: self.paged_memory_initialization,
|
||||
memfd: self.memfd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,6 +275,21 @@
|
||||
//! all architectures for both the JIT compiler and the `wasmtime compile` CLI
|
||||
//! command.
|
||||
//!
|
||||
//! * `pooling-allocator` - Enabled by default, this feature adds support for
|
||||
//! the pooling allocation strategy enabled via
|
||||
//! [`Config::allocation_strategy`]. The pooling allocator can enable more
|
||||
//! efficient reuse of resources for high-concurrency and
|
||||
//! high-instantiation-count scenarios.
|
||||
//!
|
||||
//! * `memfd` - Enabled by default, this feature builds in support for a
|
||||
//! Linux-specific feature of creating a `memfd` where applicable for a
|
||||
//! [`Module`]'s initial memory. This makes instantiation much faster by
|
||||
//! `mmap`-ing the initial memory image into place instead of copying memory
|
||||
//! into place, allowing sharing pages that end up only getting read and
|
||||
//! otherwise using copy-on-write for efficient initialization of memory. Note
|
||||
//! that this is simply compile-time support and this must also be enabled at
|
||||
//! run-time via [`Config::memfd`].
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! In addition to the examples below be sure to check out the [online embedding
|
||||
|
||||
@@ -724,6 +724,9 @@ impl Module {
|
||||
}
|
||||
|
||||
pub(crate) fn memfds(&self) -> Result<Option<&Arc<ModuleMemFds>>> {
|
||||
if !self.engine().config().memfd {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(self
|
||||
.inner
|
||||
.memfds
|
||||
|
||||
Reference in New Issue
Block a user