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}