Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an instance limit to Config #2593

Merged
merged 2 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions crates/c-api/include/wasmtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ WASMTIME_CONFIG_PROP(void, static_memory_guard_size, uint64_t)
*/
WASMTIME_CONFIG_PROP(void, dynamic_memory_guard_size, uint64_t)

/**
* \brief Configures the maximum number of instances that cana be created.
alexcrichton marked this conversation as resolved.
Show resolved Hide resolved
*
* For more information see the Rust documentation at
* https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.max_instances.
*/
WASMTIME_CONFIG_PROP(void, max_instances, size_t)

/**
* \brief Enables Wasmtime's cache and loads configuration from the specified
* path.
Expand Down
5 changes: 5 additions & 0 deletions crates/c-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,8 @@ pub extern "C" fn wasmtime_config_static_memory_guard_size_set(c: &mut wasm_conf
pub extern "C" fn wasmtime_config_dynamic_memory_guard_size_set(c: &mut wasm_config_t, size: u64) {
c.config.dynamic_memory_guard_size(size);
}

#[no_mangle]
pub extern "C" fn wasmtime_config_max_instances(c: &mut wasm_config_t, limit: usize) {
c.config.max_instances(limit);
}
11 changes: 11 additions & 0 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct Config {
pub(crate) max_wasm_stack: usize,
pub(crate) features: WasmFeatures,
pub(crate) wasm_backtrace_details_env_used: bool,
pub(crate) max_instances: usize,
}

impl Config {
Expand Down Expand Up @@ -79,6 +80,7 @@ impl Config {
multi_value: true,
..WasmFeatures::default()
},
max_instances: 10_000,
};
ret.wasm_backtrace_details(WasmBacktraceDetails::Environment);
return ret;
Expand Down Expand Up @@ -635,6 +637,15 @@ impl Config {
self
}

/// Configures the maximum number of instances which can be created within
/// this `Store`.
///
/// Instantiation will fail with an error if this limit is exceeded.
pub fn max_instances(&mut self, instances: usize) -> &mut Self {
self.max_instances = instances;
self
}

pub(crate) fn target_isa(&self) -> Box<dyn TargetIsa> {
self.isa_flags
.clone()
Expand Down
2 changes: 2 additions & 0 deletions crates/wasmtime/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ fn instantiate(
&mut ImportsBuilder<'_>,
) -> Result<()>,
) -> Result<RuntimeInstance, Error> {
store.bump_instance_count()?;

let compiled_module = module.compiled_module();
let env_module = compiled_module.module();

Expand Down
14 changes: 13 additions & 1 deletion crates/wasmtime/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::trampoline::StoreInstanceHandle;
use crate::{Engine, Module};
use anyhow::{bail, Result};
use std::any::Any;
use std::cell::RefCell;
use std::cell::{Cell, RefCell};
use std::collections::HashSet;
use std::fmt;
use std::hash::{Hash, Hasher};
Expand Down Expand Up @@ -67,6 +67,8 @@ pub(crate) struct StoreInner {
/// Set of all compiled modules that we're holding a strong reference to
/// the module's code for. This includes JIT functions, trampolines, etc.
modules: RefCell<HashSet<ArcModuleCode>>,
/// The number of instantiated instances in this store.
instance_count: Cell<usize>,
}

struct HostInfoKey(VMExternRef);
Expand Down Expand Up @@ -109,6 +111,7 @@ impl Store {
stack_map_registry: StackMapRegistry::default(),
frame_info: Default::default(),
modules: Default::default(),
instance_count: Default::default(),
}),
}
}
Expand Down Expand Up @@ -213,6 +216,15 @@ impl Store {
}
}

pub(crate) fn bump_instance_count(&self) -> Result<()> {
let n = self.inner.instance_count.get();
self.inner.instance_count.set(n + 1);
if n >= self.engine().config().max_instances {
bail!("instance limit of {} exceeded", n);
}
Ok(())
}

pub(crate) unsafe fn add_instance(&self, handle: InstanceHandle) -> StoreInstanceHandle {
self.inner.instances.borrow_mut().push(handle.clone());
StoreInstanceHandle {
Expand Down
36 changes: 36 additions & 0 deletions tests/all/module_linking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,39 @@ fn imports_exports() -> Result<()> {
}
Ok(())
}

#[test]
fn limit_instances() -> Result<()> {
let mut config = Config::new();
config.wasm_module_linking(true);
config.max_instances(10);
let engine = Engine::new(&config);
let module = Module::new(
&engine,
r#"
(module $PARENT
(module $m0)
(module $m1
(instance (instantiate (module outer $PARENT $m0)))
(instance (instantiate (module outer $PARENT $m0))))
(module $m2
(instance (instantiate (module outer $PARENT $m1)))
(instance (instantiate (module outer $PARENT $m1))))
(module $m3
(instance (instantiate (module outer $PARENT $m2)))
(instance (instantiate (module outer $PARENT $m2))))
(module $m4
(instance (instantiate (module outer $PARENT $m3)))
(instance (instantiate (module outer $PARENT $m3))))
(module $m5
(instance (instantiate (module outer $PARENT $m4)))
(instance (instantiate (module outer $PARENT $m4))))
(instance (instantiate $m5))
)
"#,
)?;
let store = Store::new(&engine);
let err = Instance::new(&store, &module, &[]).err().unwrap();
assert!(err.to_string().contains("instance limit of 10 exceeded"));
Ok(())
}