#[derive(Debug, Clone)]
pub struct PluginLimits {
pub max_memory_bytes: usize,
pub max_stack_bytes: usize,
pub max_execution_ms: u64,
pub max_fuel: u64,
}
impl Default for PluginLimits {
fn default() -> Self {
Self {
max_memory_bytes: 16 * 1024 * 1024, max_stack_bytes: 1024 * 1024, max_execution_ms: 100, max_fuel: 100_000_000,
}
}
}
impl PluginLimits {
pub fn with_memory(mut self, bytes: usize) -> Self {
self.max_memory_bytes = bytes;
self
}
pub fn with_stack(mut self, bytes: usize) -> Self {
self.max_stack_bytes = bytes;
self
}
pub fn with_timeout(mut self, ms: u64) -> Self {
self.max_execution_ms = ms;
self.max_fuel = ms * 1_000_000;
self
}
}
#[allow(dead_code)] pub struct PluginResourceLimiter {
limits: PluginLimits,
}
#[allow(dead_code)]
impl PluginResourceLimiter {
pub fn new(limits: PluginLimits) -> Self {
Self { limits }
}
}
impl wasmtime::ResourceLimiter for PluginResourceLimiter {
fn memory_growing(
&mut self,
_current: usize,
desired: usize,
_maximum: Option<usize>,
) -> Result<bool, wasmtime::Error> {
Ok(desired <= self.limits.max_memory_bytes)
}
fn table_growing(
&mut self,
_current: usize,
desired: usize,
_maximum: Option<usize>,
) -> Result<bool, wasmtime::Error> {
Ok(desired <= 10_000)
}
}
#[cfg(test)]
mod tests {
use super::*;
use wasmtime::ResourceLimiter;
#[test]
fn default_limits() {
let limits = PluginLimits::default();
assert_eq!(limits.max_memory_bytes, 16 * 1024 * 1024);
assert_eq!(limits.max_stack_bytes, 1024 * 1024);
assert_eq!(limits.max_execution_ms, 100);
}
#[test]
fn custom_limits() {
let limits = PluginLimits::default()
.with_memory(32 * 1024 * 1024)
.with_stack(2 * 1024 * 1024)
.with_timeout(200);
assert_eq!(limits.max_memory_bytes, 32 * 1024 * 1024);
assert_eq!(limits.max_stack_bytes, 2 * 1024 * 1024);
assert_eq!(limits.max_execution_ms, 200);
}
#[test]
fn resource_limiter_allows_within_limits() {
let limits = PluginLimits::default();
let mut limiter = PluginResourceLimiter::new(limits);
assert!(limiter.memory_growing(0, 1024 * 1024, None).unwrap());
assert!(limiter.memory_growing(0, 16 * 1024 * 1024, None).unwrap());
}
#[test]
fn resource_limiter_denies_over_limit() {
let limits = PluginLimits::default();
let mut limiter = PluginResourceLimiter::new(limits);
assert!(!limiter.memory_growing(0, 17 * 1024 * 1024, None).unwrap());
}
}