wasmtime/
limits.rs

1/// Value returned by [`ResourceLimiter::instances`] default method
2pub const DEFAULT_INSTANCE_LIMIT: usize = 10000;
3/// Value returned by [`ResourceLimiter::tables`] default method
4pub const DEFAULT_TABLE_LIMIT: usize = 10000;
5/// Value returned by [`ResourceLimiter::memories`] default method
6pub const DEFAULT_MEMORY_LIMIT: usize = 10000;
7
8/// Used by hosts to limit resource consumption of instances.
9///
10/// This trait is used in conjunction with the
11/// [`Store::limiter`](crate::Store::limiter) to synchronously limit the
12/// allocation of resources within a store. As a store-level limit this means
13/// that all creation of instances, memories, and tables are limited within the
14/// store. Resources limited via this trait are primarily related to memory and
15/// limiting CPU resources needs to be done with something such as
16/// [`Config::consume_fuel`](crate::Config::consume_fuel) or
17/// [`Config::epoch_interruption`](crate::Config::epoch_interruption).
18///
19/// Note that this trait does not limit 100% of memory allocated via a
20/// [`Store`](crate::Store). Wasmtime will still allocate memory to track data
21/// structures and additionally embedder-specific memory allocations are not
22/// tracked via this trait. This trait only limits resources allocated by a
23/// WebAssembly instance itself.
24///
25/// This trait is intended for synchronously limiting the resources of a module.
26/// If your use case requires blocking to answer whether a request is permitted
27/// or not and you're otherwise working in an asynchronous context the
28/// [`ResourceLimiterAsync`] trait is also provided to avoid blocking an OS
29/// thread while a limit is determined.
30pub trait ResourceLimiter {
31    /// Notifies the resource limiter that an instance's linear memory has been
32    /// requested to grow.
33    ///
34    /// * `current` is the current size of the linear memory in bytes.
35    /// * `desired` is the desired size of the linear memory in bytes.
36    /// * `maximum` is either the linear memory's maximum or a maximum from an
37    ///   instance allocator, also in bytes. A value of `None`
38    ///   indicates that the linear memory is unbounded.
39    ///
40    /// The `current` and `desired` amounts are guaranteed to always be
41    /// multiples of the WebAssembly page size, 64KiB.
42    ///
43    /// This function should return `true` to indicate that the growing
44    /// operation is permitted or `false` if not permitted. Returning `true`
45    /// when a maximum has been exceeded will have no effect as the linear
46    /// memory will not grow.
47    ///
48    /// This function is not guaranteed to be invoked for all requests to
49    /// `memory.grow`. Requests where the allocation requested size doesn't fit
50    /// in `usize` or exceeds the memory's listed maximum size may not invoke
51    /// this method.
52    ///
53    /// Returning `false` from this method will cause the `memory.grow`
54    /// instruction in a module to return -1 (failure), or in the case of an
55    /// embedder API calling [`Memory::new`](crate::Memory::new) or
56    /// [`Memory::grow`](crate::Memory::grow) an error will be returned from
57    /// those methods.
58    fn memory_growing(&mut self, current: usize, desired: usize, maximum: Option<usize>) -> bool;
59
60    /// Notifies the resource limiter that growing a linear memory, permitted by
61    /// the `memory_growing` method, has failed.
62    ///
63    /// Reasons for failure include: the growth exceeds the `maximum` passed to
64    /// `memory_growing`, or the operating system failed to allocate additional
65    /// memory. In that case, `error` might be downcastable to a `std::io::Error`.
66    fn memory_grow_failed(&mut self, _error: &anyhow::Error) {}
67
68    /// Notifies the resource limiter that an instance's table has been
69    /// requested to grow.
70    ///
71    /// * `current` is the current number of elements in the table.
72    /// * `desired` is the desired number of elements in the table.
73    /// * `maximum` is either the table's maximum or a maximum from an instance
74    ///   allocator.  A value of `None` indicates that the table is unbounded.
75    ///
76    /// This function should return `true` to indicate that the growing
77    /// operation is permitted or `false` if not permitted. Returning `true`
78    /// when a maximum has been exceeded will have no effect as the table will
79    /// not grow.
80    ///
81    /// Currently in Wasmtime each table element requires a pointer's worth of
82    /// space (e.g. `mem::size_of::<usize>()`).
83    ///
84    /// Like `memory_growing` returning `false` from this function will cause
85    /// `table.grow` to return -1 or embedder APIs will return an error.
86    fn table_growing(&mut self, current: u32, desired: u32, maximum: Option<u32>) -> bool;
87
88    /// Notifies the resource limiter that growing a linear memory, permitted by
89    /// the `table_growing` method, has failed.
90    ///
91    /// Reasons for failure include: the growth exceeds the `maximum` passed to
92    /// `table_growing`. This could expand in the future.
93    fn table_grow_failed(&mut self, _error: &anyhow::Error) {}
94
95    /// The maximum number of instances that can be created for a `Store`.
96    ///
97    /// Module instantiation will fail if this limit is exceeded.
98    ///
99    /// This value defaults to 10,000.
100    fn instances(&self) -> usize {
101        DEFAULT_INSTANCE_LIMIT
102    }
103
104    /// The maximum number of tables that can be created for a `Store`.
105    ///
106    /// Creation of tables will fail if this limit is exceeded.
107    ///
108    /// This value defaults to 10,000.
109    fn tables(&self) -> usize {
110        DEFAULT_TABLE_LIMIT
111    }
112
113    /// The maximum number of linear memories that can be created for a `Store`
114    ///
115    /// Creation of memories will fail with an error if this limit is exceeded.
116    ///
117    /// This value defaults to 10,000.
118    fn memories(&self) -> usize {
119        DEFAULT_MEMORY_LIMIT
120    }
121}
122
123/// Used by hosts to limit resource consumption of instances, blocking
124/// asynchronously if necessary.
125///
126/// This trait is identical to [`ResourceLimiter`], except that the
127/// `memory_growing` and `table_growing` functions are `async`. Must be used
128/// with an async [`Store`](`crate::Store`) configured via
129/// [`Config::async_support`](crate::Config::async_support).
130///
131/// This trait is used with
132/// [`Store::limiter_async`](`crate::Store::limiter_async`)`: see those docs
133/// for restrictions on using other Wasmtime interfaces with an async resource
134/// limiter. Additionally see [`ResourceLimiter`] for more information about
135/// limiting resources from WebAssembly.
136///
137/// The `async` here enables embedders that are already using asynchronous
138/// execution of WebAssembly to block the WebAssembly, but no the OS thread, to
139/// answer the question whether growing a memory or table is allowed.
140#[cfg(feature = "async")]
141#[async_trait::async_trait]
142pub trait ResourceLimiterAsync {
143    /// Async version of [`ResourceLimiter::memory_growing`]
144    async fn memory_growing(
145        &mut self,
146        current: usize,
147        desired: usize,
148        maximum: Option<usize>,
149    ) -> bool;
150
151    /// Identical to [`ResourceLimiter::memory_grow_failed`]
152    fn memory_grow_failed(&mut self, _error: &anyhow::Error) {}
153
154    /// Asynchronous version of [`ResourceLimiter::table_growing`]
155    async fn table_growing(&mut self, current: u32, desired: u32, maximum: Option<u32>) -> bool;
156
157    /// Identical to [`ResourceLimiter::table_grow_failed`]
158    fn table_grow_failed(&mut self, _error: &anyhow::Error) {}
159
160    /// Identical to [`ResourceLimiter::instances`]`
161    fn instances(&self) -> usize {
162        DEFAULT_INSTANCE_LIMIT
163    }
164
165    /// Identical to [`ResourceLimiter::tables`]`
166    fn tables(&self) -> usize {
167        DEFAULT_TABLE_LIMIT
168    }
169
170    /// Identical to [`ResourceLimiter::memories`]`
171    fn memories(&self) -> usize {
172        DEFAULT_MEMORY_LIMIT
173    }
174}
175
176/// Used to build [`StoreLimits`].
177pub struct StoreLimitsBuilder(StoreLimits);
178
179impl StoreLimitsBuilder {
180    /// Creates a new [`StoreLimitsBuilder`].
181    ///
182    /// See the documentation on each builder method for the default for each
183    /// value.
184    pub fn new() -> Self {
185        Self(StoreLimits::default())
186    }
187
188    /// The maximum number of bytes a linear memory can grow to.
189    ///
190    /// Growing a linear memory beyond this limit will fail.
191    ///
192    /// By default, linear memory will not be limited.
193    pub fn memory_size(mut self, limit: usize) -> Self {
194        self.0.memory_size = Some(limit);
195        self
196    }
197
198    /// The maximum number of elements in a table.
199    ///
200    /// Growing a table beyond this limit will fail.
201    ///
202    /// By default, table elements will not be limited.
203    pub fn table_elements(mut self, limit: u32) -> Self {
204        self.0.table_elements = Some(limit);
205        self
206    }
207
208    /// The maximum number of instances that can be created for a [`Store`](crate::Store).
209    ///
210    /// Module instantiation will fail if this limit is exceeded.
211    ///
212    /// This value defaults to 10,000.
213    pub fn instances(mut self, limit: usize) -> Self {
214        self.0.instances = limit;
215        self
216    }
217
218    /// The maximum number of tables that can be created for a [`Store`](crate::Store).
219    ///
220    /// Module instantiation will fail if this limit is exceeded.
221    ///
222    /// This value defaults to 10,000.
223    pub fn tables(mut self, tables: usize) -> Self {
224        self.0.tables = tables;
225        self
226    }
227
228    /// The maximum number of linear memories that can be created for a [`Store`](crate::Store).
229    ///
230    /// Instantiation will fail with an error if this limit is exceeded.
231    ///
232    /// This value defaults to 10,000.
233    pub fn memories(mut self, memories: usize) -> Self {
234        self.0.memories = memories;
235        self
236    }
237
238    /// Consumes this builder and returns the [`StoreLimits`].
239    pub fn build(self) -> StoreLimits {
240        self.0
241    }
242}
243
244/// Provides limits for a [`Store`](crate::Store).
245///
246/// This type is created with a [`StoreLimitsBuilder`] and is typically used in
247/// conjunction with [`Store::limiter`](crate::Store::limiter).
248///
249/// This is a convenience type included to avoid needing to implement the
250/// [`ResourceLimiter`] trait if your use case fits in the static configuration
251/// that this [`StoreLimits`] provides.
252pub struct StoreLimits {
253    memory_size: Option<usize>,
254    table_elements: Option<u32>,
255    instances: usize,
256    tables: usize,
257    memories: usize,
258}
259
260impl Default for StoreLimits {
261    fn default() -> Self {
262        Self {
263            memory_size: None,
264            table_elements: None,
265            instances: DEFAULT_INSTANCE_LIMIT,
266            tables: DEFAULT_TABLE_LIMIT,
267            memories: DEFAULT_MEMORY_LIMIT,
268        }
269    }
270}
271
272impl ResourceLimiter for StoreLimits {
273    fn memory_growing(&mut self, _current: usize, desired: usize, _maximum: Option<usize>) -> bool {
274        match self.memory_size {
275            Some(limit) if desired > limit => false,
276            _ => true,
277        }
278    }
279
280    fn table_growing(&mut self, _current: u32, desired: u32, _maximum: Option<u32>) -> bool {
281        match self.table_elements {
282            Some(limit) if desired > limit => false,
283            _ => true,
284        }
285    }
286
287    fn instances(&self) -> usize {
288        self.instances
289    }
290
291    fn tables(&self) -> usize {
292        self.tables
293    }
294
295    fn memories(&self) -> usize {
296        self.memories
297    }
298}