aether/runtime/
limits.rs

1//! 执行限制配置和错误类型
2//!
3//! 提供执行资源限制,防止恶意或错误代码耗尽系统资源。
4
5use std::fmt;
6
7/// 执行限制配置
8///
9/// 用于控制脚本执行的资源消耗,包括步数、递归深度、执行时长和内存使用。
10#[derive(Debug, Clone, PartialEq)]
11pub struct ExecutionLimits {
12    /// 最大执行步数(指令计数)
13    /// None 表示无限制
14    pub max_steps: Option<usize>,
15
16    /// 最大递归深度(调用栈深度)
17    /// None 表示无限制
18    pub max_recursion_depth: Option<usize>,
19
20    /// 最大执行时长(毫秒)
21    /// None 表示无限制
22    pub max_duration_ms: Option<u64>,
23
24    /// 最大内存分配(字节)
25    /// None 表示无限制(暂未实现,预留)
26    pub max_memory_bytes: Option<usize>,
27}
28
29impl Default for ExecutionLimits {
30    fn default() -> Self {
31        Self {
32            max_steps: Some(1_000_000),      // 默认100万步
33            max_recursion_depth: Some(1000), // 默认1000层
34            max_duration_ms: Some(30_000),   // 默认30秒
35            max_memory_bytes: None,
36        }
37    }
38}
39
40impl ExecutionLimits {
41    /// 创建无限制的配置
42    pub fn unrestricted() -> Self {
43        Self {
44            max_steps: None,
45            max_recursion_depth: None,
46            max_duration_ms: None,
47            max_memory_bytes: None,
48        }
49    }
50
51    /// 创建严格限制的配置(用于 DSL 安全模式)
52    pub fn strict() -> Self {
53        Self {
54            max_steps: Some(100_000),       // 10万步
55            max_recursion_depth: Some(100), // 100层
56            max_duration_ms: Some(5_000),   // 5秒
57            max_memory_bytes: None,
58        }
59    }
60
61    /// 创建宽松限制的配置(用于 CLI 模式)
62    pub fn lenient() -> Self {
63        Self {
64            max_steps: Some(10_000_000),     // 1000万步
65            max_recursion_depth: Some(5000), // 5000层
66            max_duration_ms: Some(300_000),  // 5分钟
67            max_memory_bytes: None,
68        }
69    }
70}
71
72/// 执行限制错误
73///
74/// 当脚本超出配置的资源限制时返回此错误。
75#[derive(Debug, Clone, PartialEq)]
76pub enum ExecutionLimitError {
77    /// 步数限制超出
78    StepLimitExceeded { steps: usize, limit: usize },
79
80    /// 递归深度限制超出
81    RecursionDepthExceeded { depth: usize, limit: usize },
82
83    /// 执行时长超出
84    DurationExceeded { duration_ms: u64, limit: u64 },
85
86    /// 内存限制超出(暂未实现)
87    MemoryLimitExceeded { bytes: usize, limit: usize },
88}
89
90impl fmt::Display for ExecutionLimitError {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        match self {
93            ExecutionLimitError::StepLimitExceeded { steps, limit } => write!(
94                f,
95                "Execution step limit exceeded: {} steps (limit: {})",
96                steps, limit
97            ),
98            ExecutionLimitError::RecursionDepthExceeded { depth, limit } => write!(
99                f,
100                "Recursion depth limit exceeded: {} levels (limit: {})",
101                depth, limit
102            ),
103            ExecutionLimitError::DurationExceeded { duration_ms, limit } => write!(
104                f,
105                "Execution duration limit exceeded: {} ms (limit: {} ms)",
106                duration_ms, limit
107            ),
108            ExecutionLimitError::MemoryLimitExceeded { bytes, limit } => write!(
109                f,
110                "Memory limit exceeded: {} bytes (limit: {} bytes)",
111                bytes, limit
112            ),
113        }
114    }
115}
116
117impl std::error::Error for ExecutionLimitError {}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_default_limits() {
125        let limits = ExecutionLimits::default();
126        assert_eq!(limits.max_steps, Some(1_000_000));
127        assert_eq!(limits.max_recursion_depth, Some(1000));
128        assert_eq!(limits.max_duration_ms, Some(30_000));
129        assert_eq!(limits.max_memory_bytes, None);
130    }
131
132    #[test]
133    fn test_unrestricted_limits() {
134        let limits = ExecutionLimits::unrestricted();
135        assert_eq!(limits.max_steps, None);
136        assert_eq!(limits.max_recursion_depth, None);
137        assert_eq!(limits.max_duration_ms, None);
138        assert_eq!(limits.max_memory_bytes, None);
139    }
140
141    #[test]
142    fn test_strict_limits() {
143        let limits = ExecutionLimits::strict();
144        assert_eq!(limits.max_steps, Some(100_000));
145        assert_eq!(limits.max_recursion_depth, Some(100));
146        assert_eq!(limits.max_duration_ms, Some(5_000));
147        assert_eq!(limits.max_memory_bytes, None);
148    }
149
150    #[test]
151    fn test_lenient_limits() {
152        let limits = ExecutionLimits::lenient();
153        assert_eq!(limits.max_steps, Some(10_000_000));
154        assert_eq!(limits.max_recursion_depth, Some(5000));
155        assert_eq!(limits.max_duration_ms, Some(300_000));
156        assert_eq!(limits.max_memory_bytes, None);
157    }
158
159    #[test]
160    fn test_error_display() {
161        let err = ExecutionLimitError::StepLimitExceeded {
162            steps: 1000,
163            limit: 100,
164        };
165        assert!(err.to_string().contains("1000"));
166        assert!(err.to_string().contains("100"));
167
168        let err = ExecutionLimitError::RecursionDepthExceeded {
169            depth: 500,
170            limit: 100,
171        };
172        assert!(err.to_string().contains("500"));
173        assert!(err.to_string().contains("100"));
174
175        let err = ExecutionLimitError::DurationExceeded {
176            duration_ms: 5000,
177            limit: 1000,
178        };
179        assert!(err.to_string().contains("5000"));
180        assert!(err.to_string().contains("1000"));
181    }
182}