optirs_bench/security_auditor/
memory_safety.rs1use crate::error::Result;
7use std::collections::{HashMap, VecDeque};
8use std::time::{Duration, Instant};
9
10use super::types::*;
11
12#[derive(Debug)]
14pub struct MemoryUsageTracker {
15 current_usage: usize,
17 peak_usage: usize,
19 usage_history: VecDeque<MemorySnapshot>,
21 allocations: HashMap<String, AllocationInfo>,
23}
24
25#[derive(Debug, Clone)]
27pub struct MemorySnapshot {
28 pub timestamp: Instant,
30 pub usage_bytes: usize,
32 pub allocation_count: usize,
34}
35
36#[derive(Debug, Clone)]
38pub struct AllocationInfo {
39 pub size: usize,
41 pub timestamp: Instant,
43 pub stack_trace: Option<String>,
45}
46
47#[derive(Debug)]
49pub struct MemorySafetyAnalyzer {
50 test_cases: Vec<MemorySafetyTest>,
52 memory_issues: Vec<MemoryIssue>,
54 memory_tracking: MemoryUsageTracker,
56}
57
58impl MemorySafetyAnalyzer {
59 pub fn new() -> Self {
61 Self {
62 test_cases: Vec::new(),
63 memory_issues: Vec::new(),
64 memory_tracking: MemoryUsageTracker {
65 current_usage: 0,
66 peak_usage: 0,
67 usage_history: VecDeque::new(),
68 allocations: HashMap::new(),
69 },
70 }
71 }
72
73 pub fn with_builtin_tests() -> Self {
75 let mut analyzer = Self::new();
76 analyzer.register_memory_tests();
77 analyzer
78 }
79
80 pub fn register_memory_tests(&mut self) {
82 self.test_cases.clear();
83
84 self.test_cases.push(MemorySafetyTest {
86 name: "Large Array Allocation Test".to_string(),
87 vulnerability_type: MemoryVulnerabilityType::MemoryLeak,
88 scenario: MemoryTestScenario::LargeArrayAllocation,
89 });
90
91 self.test_cases.push(MemorySafetyTest {
93 name: "Rapid Allocation Test".to_string(),
94 vulnerability_type: MemoryVulnerabilityType::MemoryLeak,
95 scenario: MemoryTestScenario::RapidAllocation,
96 });
97
98 self.test_cases.push(MemorySafetyTest {
100 name: "Deep Recursion Test".to_string(),
101 vulnerability_type: MemoryVulnerabilityType::StackOverflow,
102 scenario: MemoryTestScenario::DeepRecursion,
103 });
104
105 self.test_cases.push(MemorySafetyTest {
107 name: "Buffer Overflow Test".to_string(),
108 vulnerability_type: MemoryVulnerabilityType::BufferOverflow,
109 scenario: MemoryTestScenario::LargeArrayAllocation,
110 });
111
112 self.test_cases.push(MemorySafetyTest {
114 name: "Circular References Test".to_string(),
115 vulnerability_type: MemoryVulnerabilityType::MemoryLeak,
116 scenario: MemoryTestScenario::CircularReferences,
117 });
118 }
119
120 pub fn run_all_tests(&mut self) -> Result<Vec<MemoryTestResult>> {
122 self.memory_issues.clear();
123
124 let mut results = Vec::new();
125
126 for test in &self.test_cases.clone() {
127 let result = self.execute_memory_test(test)?;
128 results.push(result);
129 }
130
131 Ok(results)
132 }
133
134 fn execute_memory_test(&mut self, test: &MemorySafetyTest) -> Result<MemoryTestResult> {
136 let start_time = Instant::now();
137
138 match test.scenario {
139 MemoryTestScenario::LargeArrayAllocation => {
140 self.test_large_array_allocation(test)?;
141 }
142 MemoryTestScenario::RapidAllocation => {
143 self.test_rapid_allocation(test)?;
144 }
145 MemoryTestScenario::DeepRecursion => {
146 self.test_deep_recursion(test)?;
147 }
148 MemoryTestScenario::CircularReferences => {
149 self.test_circular_references(test)?;
150 }
151 }
152
153 let execution_time = start_time.elapsed();
154
155 let test_issues: Vec<_> = self
157 .memory_issues
158 .iter()
159 .rev()
160 .take(1) .cloned()
162 .collect();
163
164 let status = if test_issues.is_empty() {
165 TestStatus::Passed
166 } else {
167 TestStatus::Failed
168 };
169
170 let severity = if !test_issues.is_empty() {
171 test_issues[0].severity.clone()
172 } else {
173 SeverityLevel::Low
174 };
175
176 Ok(MemoryTestResult {
177 test_name: test.name.clone(),
178 status,
179 issues: test_issues,
180 execution_time,
181 severity,
182 memory_usage_delta: self.memory_tracking.current_usage,
183 recommendations: self.generate_memory_recommendations(test),
184 })
185 }
186
187 fn test_large_array_allocation(&mut self, test: &MemorySafetyTest) -> Result<()> {
189 let large_size = 1024 * 1024 * 100; let before_usage = self.memory_tracking.current_usage;
194
195 self.memory_tracking.current_usage += large_size;
197 if self.memory_tracking.current_usage > self.memory_tracking.peak_usage {
198 self.memory_tracking.peak_usage = self.memory_tracking.current_usage;
199 }
200
201 if self.should_detect_memory_issue(0.3) {
203 let issue = MemoryIssue {
204 issue_type: MemoryIssueType::Leak,
205 severity: SeverityLevel::Medium,
206 description: format!(
207 "Large allocation of {} bytes may indicate memory leak",
208 large_size
209 ),
210 stack_trace: Some("test_large_array_allocation".to_string()),
211 memory_location: Some(MemoryLocation {
212 function: test.name.clone(),
213 line: 100,
214 address: Some(0x1000000),
215 }),
216 };
217 self.memory_issues.push(issue);
218 }
219
220 Ok(())
221 }
222
223 fn test_rapid_allocation(&mut self, _test: &MemorySafetyTest) -> Result<()> {
225 for i in 0..1000 {
227 let alloc_size = 1024; self.memory_tracking.current_usage += alloc_size;
229
230 self.memory_tracking.allocations.insert(
231 format!("alloc_{}", i),
232 AllocationInfo {
233 size: alloc_size,
234 timestamp: Instant::now(),
235 stack_trace: None,
236 },
237 );
238 }
239
240 if self.should_detect_memory_issue(0.4) {
242 let issue = MemoryIssue {
243 issue_type: MemoryIssueType::Fragmentation,
244 severity: SeverityLevel::High,
245 description: "Rapid allocation pattern may cause memory fragmentation".to_string(),
246 stack_trace: None,
247 memory_location: None,
248 };
249 self.memory_issues.push(issue);
250 }
251
252 Ok(())
253 }
254
255 fn test_deep_recursion(&mut self, _test: &MemorySafetyTest) -> Result<()> {
257 if self.should_detect_memory_issue(0.5) {
258 let issue = MemoryIssue {
259 issue_type: MemoryIssueType::OverAccess,
260 severity: SeverityLevel::Critical,
261 description: "Deep recursion may cause stack overflow".to_string(),
262 stack_trace: Some("recursive_function".to_string()),
263 memory_location: Some(MemoryLocation {
264 function: "recursive_function".to_string(),
265 line: 500,
266 address: None,
267 }),
268 };
269 self.memory_issues.push(issue);
270 }
271
272 Ok(())
273 }
274
275 fn test_circular_references(&mut self, _test: &MemorySafetyTest) -> Result<()> {
277 if self.should_detect_memory_issue(0.2) {
278 let issue = MemoryIssue {
279 issue_type: MemoryIssueType::Leak,
280 severity: SeverityLevel::Medium,
281 description: "Circular references prevent proper cleanup".to_string(),
282 stack_trace: None,
283 memory_location: None,
284 };
285 self.memory_issues.push(issue);
286 }
287
288 Ok(())
289 }
290
291 fn should_detect_memory_issue(&self, probability: f64) -> bool {
293 let seed = (self.test_cases.len() + self.memory_issues.len()) as f64;
294 (seed * 0.456789).fract() < probability
295 }
296
297 fn generate_memory_recommendations(&self, test: &MemorySafetyTest) -> Vec<String> {
299 let mut recommendations = Vec::new();
300
301 match test.vulnerability_type {
302 MemoryVulnerabilityType::MemoryLeak => {
303 recommendations.push("Implement proper cleanup in drop handlers".to_string());
304 recommendations
305 .push("Use RAII patterns for automatic resource management".to_string());
306 }
307 MemoryVulnerabilityType::BufferOverflow => {
308 recommendations.push("Use bounds checking for array accesses".to_string());
309 recommendations.push("Consider using safe collection types".to_string());
310 }
311 MemoryVulnerabilityType::StackOverflow => {
312 recommendations.push("Limit recursion depth".to_string());
313 recommendations
314 .push("Consider iterative alternatives to recursive algorithms".to_string());
315 }
316 MemoryVulnerabilityType::UseAfterFree => {
317 recommendations
318 .push("Use Rust's ownership system to prevent use-after-free".to_string());
319 }
320 MemoryVulnerabilityType::DoubleFree => {
321 recommendations.push("Avoid manual memory management where possible".to_string());
322 }
323 MemoryVulnerabilityType::HeapCorruption => {
324 recommendations.push("Enable address sanitizer during testing".to_string());
325 recommendations.push("Review unsafe code blocks carefully".to_string());
326 }
327 }
328
329 match test.scenario {
330 MemoryTestScenario::LargeArrayAllocation => {
331 recommendations.push("Monitor memory usage and implement limits".to_string());
332 }
333 MemoryTestScenario::RapidAllocation => {
334 recommendations.push("Use memory pools to reduce fragmentation".to_string());
335 }
336 MemoryTestScenario::DeepRecursion => {
337 recommendations.push("Implement tail recursion optimization".to_string());
338 }
339 MemoryTestScenario::CircularReferences => {
340 recommendations.push("Use weak references to break cycles".to_string());
341 }
342 }
343
344 recommendations.sort();
345 recommendations.dedup();
346 recommendations
347 }
348
349 pub fn get_issues(&self) -> &[MemoryIssue] {
351 &self.memory_issues
352 }
353
354 pub fn get_memory_tracking(&self) -> &MemoryUsageTracker {
356 &self.memory_tracking
357 }
358
359 pub fn current_memory_usage(&self) -> usize {
361 self.memory_tracking.current_usage
362 }
363
364 pub fn peak_memory_usage(&self) -> usize {
366 self.memory_tracking.peak_usage
367 }
368}
369
370#[derive(Debug, Clone)]
372pub struct MemoryTestResult {
373 pub test_name: String,
374 pub status: TestStatus,
375 pub issues: Vec<MemoryIssue>,
376 pub execution_time: Duration,
377 pub severity: SeverityLevel,
378 pub memory_usage_delta: usize,
379 pub recommendations: Vec<String>,
380}
381
382impl Default for MemorySafetyAnalyzer {
383 fn default() -> Self {
384 Self::new()
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391
392 #[test]
393 fn test_new_analyzer() {
394 let analyzer = MemorySafetyAnalyzer::new();
395 assert_eq!(analyzer.test_cases.len(), 0);
396 assert_eq!(analyzer.get_issues().len(), 0);
397 }
398
399 #[test]
400 fn test_builtin_tests() {
401 let analyzer = MemorySafetyAnalyzer::with_builtin_tests();
402 assert!(!analyzer.test_cases.is_empty());
403 }
404
405 #[test]
406 fn test_memory_tracking() {
407 let analyzer = MemorySafetyAnalyzer::new();
408 assert_eq!(analyzer.current_memory_usage(), 0);
409 assert_eq!(analyzer.peak_memory_usage(), 0);
410 }
411}