wasmi/engine/limits/
stack.rs

1use core::{
2    error::Error,
3    fmt::{self, Display},
4};
5
6/// Default value for maximum recursion depth.
7const DEFAULT_MAX_RECURSION_DEPTH: usize = 1000;
8
9/// Default value for minimum value stack height in bytes.
10const DEFAULT_MIN_STACK_HEIGHT: usize = 1_000;
11
12/// Default value for maximum value stack height in bytes.
13const DEFAULT_MAX_STACK_HEIGHT: usize = 1_000_000;
14
15/// The default maximum number of cached stacks for reuse.
16const DEFAULT_MAX_CACHED_STACKS: usize = 2;
17
18/// An error returned by some [`StackConfig`] methods.
19#[derive(Debug)]
20pub enum StackConfigError {
21    /// The given minimum stack height exceeds the maximum stack height.
22    MinStackHeightExceedsMax,
23}
24
25impl Error for StackConfigError {}
26
27impl Display for StackConfigError {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        match self {
30            StackConfigError::MinStackHeightExceedsMax => {
31                write!(f, "minimum value stack height exceeds maximum stack height")
32            }
33        }
34    }
35}
36
37/// The Wasmi [`Engine`]'s stack configuration.
38///
39/// [`Engine`]: crate::Engine
40#[derive(Debug, Copy, Clone)]
41pub struct StackConfig {
42    /// The maximum recursion depth.
43    max_recursion_depth: usize,
44    /// The minimum (or initial) value stack height.
45    min_stack_height: usize,
46    /// The maximum value stack height.
47    max_stack_height: usize,
48    /// The maximum number of cached stacks kept for reuse.
49    max_cached_stacks: usize,
50}
51
52impl Default for StackConfig {
53    fn default() -> Self {
54        Self {
55            max_recursion_depth: DEFAULT_MAX_RECURSION_DEPTH,
56            min_stack_height: DEFAULT_MIN_STACK_HEIGHT,
57            max_stack_height: DEFAULT_MAX_STACK_HEIGHT,
58            max_cached_stacks: DEFAULT_MAX_CACHED_STACKS,
59        }
60    }
61}
62
63impl StackConfig {
64    /// Sets the new maximum recursion depth.
65    pub fn set_max_recursion_depth(&mut self, value: usize) {
66        self.max_recursion_depth = value;
67    }
68
69    /// Sets the new minimum (or initial) value stack height.
70    ///
71    /// # Errors
72    ///
73    /// If `value` is greater than the current maximum value stack heihgt.
74    pub fn set_min_stack_height(&mut self, value: usize) -> Result<(), StackConfigError> {
75        if value > self.max_stack_height {
76            return Err(StackConfigError::MinStackHeightExceedsMax);
77        }
78        self.min_stack_height = value;
79        Ok(())
80    }
81
82    /// Sets the new maximum value stack height.
83    ///
84    /// # Errors
85    ///
86    /// If `value` is less than the current minimum (or initial) value stack heihgt.
87    pub fn set_max_stack_height(&mut self, value: usize) -> Result<(), StackConfigError> {
88        if value < self.max_stack_height {
89            return Err(StackConfigError::MinStackHeightExceedsMax);
90        }
91        self.max_stack_height = value;
92        Ok(())
93    }
94
95    /// Sets the maximum number of stacks that the [`Engine`] keeps for reuse.
96    ///
97    /// [`Engine`]: crate::Engine
98    pub fn set_max_cached_stacks(&mut self, value: usize) {
99        self.max_recursion_depth = value;
100    }
101
102    /// Returns the maximum recursion depth.
103    pub fn max_recursion_depth(&self) -> usize {
104        self.max_recursion_depth
105    }
106
107    /// Returns the minimum (or initial) value stack height.
108    pub fn min_stack_height(&self) -> usize {
109        self.min_stack_height
110    }
111
112    /// Returns the maximum value stack height.
113    pub fn max_stack_height(&self) -> usize {
114        self.max_stack_height
115    }
116
117    /// Returns the maximum number of stacks that the [`Engine`] keeps for reuse.
118    ///
119    /// [`Engine`]: crate::Engine
120    pub fn max_cached_stacks(&mut self) -> usize {
121        self.max_cached_stacks
122    }
123}
124
125/// The configured limits of the Wasm stack.
126#[deprecated(
127    since = "0.51.0",
128    note = "\
129        use `Config::set_{min,max}_stack_height`, \
130        `Config::max_recursion_depth` and \
131        `Config::set_max_cached_stacks` instead"
132)]
133#[derive(Debug, Copy, Clone)]
134pub struct StackLimits {
135    /// The initial value stack height that the Wasm stack prepares.
136    pub initial_value_stack_height: usize,
137    /// The maximum value stack height in use that the Wasm stack allows.
138    pub maximum_value_stack_height: usize,
139    /// The maximum number of nested calls that the Wasm stack allows.
140    pub maximum_recursion_depth: usize,
141}
142
143#[expect(deprecated)]
144impl StackLimits {
145    /// Creates a new [`StackLimits`] configuration.
146    ///
147    /// # Errors
148    ///
149    /// If the `initial_value_stack_height` exceeds `maximum_value_stack_height`.
150    pub fn new(
151        initial_value_stack_height: usize,
152        maximum_value_stack_height: usize,
153        maximum_recursion_depth: usize,
154    ) -> Result<Self, StackConfigError> {
155        if initial_value_stack_height > maximum_value_stack_height {
156            return Err(StackConfigError::MinStackHeightExceedsMax);
157        }
158        Ok(Self {
159            initial_value_stack_height,
160            maximum_value_stack_height,
161            maximum_recursion_depth,
162        })
163    }
164}
165
166#[expect(deprecated)]
167impl Default for StackLimits {
168    fn default() -> Self {
169        let register_len = size_of::<u64>();
170        let initial_value_stack_height = DEFAULT_MIN_STACK_HEIGHT / register_len;
171        let maximum_value_stack_height = DEFAULT_MAX_STACK_HEIGHT / register_len;
172        Self {
173            initial_value_stack_height,
174            maximum_value_stack_height,
175            maximum_recursion_depth: DEFAULT_MAX_RECURSION_DEPTH,
176        }
177    }
178}