soroban_wasmi/engine/limits/
stack.rs

1use crate::core::UntypedVal;
2use core::{
3    fmt::{self, Display},
4    mem::size_of,
5};
6
7/// Default value for initial value stack height in bytes.
8const DEFAULT_MIN_VALUE_STACK_HEIGHT: usize = 1024;
9
10/// Default value for maximum value stack height in bytes.
11const DEFAULT_MAX_VALUE_STACK_HEIGHT: usize = 1024 * DEFAULT_MIN_VALUE_STACK_HEIGHT;
12
13/// Default value for maximum recursion depth.
14const DEFAULT_MAX_RECURSION_DEPTH: usize = 1024;
15
16/// The configured limits of the Wasm stack.
17#[derive(Debug, Copy, Clone)]
18pub struct StackLimits {
19    /// The initial value stack height that the Wasm stack prepares.
20    pub initial_value_stack_height: usize,
21    /// The maximum value stack height in use that the Wasm stack allows.
22    pub maximum_value_stack_height: usize,
23    /// The maximum number of nested calls that the Wasm stack allows.
24    pub maximum_recursion_depth: usize,
25}
26
27/// An error that may occur when configuring [`StackLimits`].
28#[derive(Debug)]
29pub enum LimitsError {
30    /// The initial value stack height exceeds the maximum value stack height.
31    InitialValueStackExceedsMaximum,
32}
33
34#[cfg(feature = "std")]
35impl std::error::Error for LimitsError {}
36
37impl Display for LimitsError {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match self {
40            LimitsError::InitialValueStackExceedsMaximum => {
41                write!(f, "initial value stack height exceeds maximum stack height")
42            }
43        }
44    }
45}
46
47impl StackLimits {
48    /// Creates a new [`StackLimits`] configuration.
49    ///
50    /// # Errors
51    ///
52    /// If the `initial_value_stack_height` exceeds `maximum_value_stack_height`.
53    pub fn new(
54        initial_value_stack_height: usize,
55        maximum_value_stack_height: usize,
56        maximum_recursion_depth: usize,
57    ) -> Result<Self, LimitsError> {
58        if initial_value_stack_height > maximum_value_stack_height {
59            return Err(LimitsError::InitialValueStackExceedsMaximum);
60        }
61        Ok(Self {
62            initial_value_stack_height,
63            maximum_value_stack_height,
64            maximum_recursion_depth,
65        })
66    }
67}
68
69impl Default for StackLimits {
70    fn default() -> Self {
71        let register_len = size_of::<UntypedVal>();
72        let initial_value_stack_height = DEFAULT_MIN_VALUE_STACK_HEIGHT / register_len;
73        let maximum_value_stack_height = DEFAULT_MAX_VALUE_STACK_HEIGHT / register_len;
74        Self {
75            initial_value_stack_height,
76            maximum_value_stack_height,
77            maximum_recursion_depth: DEFAULT_MAX_RECURSION_DEPTH,
78        }
79    }
80}