Skip to main content

optirs_bench/security_auditor/
memory_safety.rs

1// Memory safety analyzer for detecting memory-related vulnerabilities
2//
3// This module provides memory safety testing capabilities including
4// buffer overflow detection, memory leak monitoring, and allocation pattern analysis.
5
6use crate::error::Result;
7use std::collections::{HashMap, VecDeque};
8use std::time::{Duration, Instant};
9
10use super::types::*;
11
12/// Memory usage tracker
13#[derive(Debug)]
14pub struct MemoryUsageTracker {
15    /// Current memory usage in bytes
16    current_usage: usize,
17    /// Peak memory usage in bytes
18    peak_usage: usize,
19    /// Memory usage history
20    usage_history: VecDeque<MemorySnapshot>,
21    /// Allocation tracking
22    allocations: HashMap<String, AllocationInfo>,
23}
24
25/// Memory snapshot at a point in time
26#[derive(Debug, Clone)]
27pub struct MemorySnapshot {
28    /// Timestamp of snapshot
29    pub timestamp: Instant,
30    /// Memory usage in bytes
31    pub usage_bytes: usize,
32    /// Number of active allocations
33    pub allocation_count: usize,
34}
35
36/// Allocation information
37#[derive(Debug, Clone)]
38pub struct AllocationInfo {
39    /// Size of allocation
40    pub size: usize,
41    /// Timestamp of allocation
42    pub timestamp: Instant,
43    /// Stack trace (if available)
44    pub stack_trace: Option<String>,
45}
46
47/// Memory safety analyzer
48#[derive(Debug)]
49pub struct MemorySafetyAnalyzer {
50    /// Memory safety tests
51    test_cases: Vec<MemorySafetyTest>,
52    /// Detected memory issues
53    memory_issues: Vec<MemoryIssue>,
54    /// Memory usage tracking
55    memory_tracking: MemoryUsageTracker,
56}
57
58impl MemorySafetyAnalyzer {
59    /// Create a new memory safety analyzer
60    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    /// Create analyzer with built-in memory tests
74    pub fn with_builtin_tests() -> Self {
75        let mut analyzer = Self::new();
76        analyzer.register_memory_tests();
77        analyzer
78    }
79
80    /// Register standard memory safety tests
81    pub fn register_memory_tests(&mut self) {
82        self.test_cases.clear();
83
84        // Large array allocation test
85        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        // Rapid allocation test
92        self.test_cases.push(MemorySafetyTest {
93            name: "Rapid Allocation Test".to_string(),
94            vulnerability_type: MemoryVulnerabilityType::MemoryLeak,
95            scenario: MemoryTestScenario::RapidAllocation,
96        });
97
98        // Deep recursion test
99        self.test_cases.push(MemorySafetyTest {
100            name: "Deep Recursion Test".to_string(),
101            vulnerability_type: MemoryVulnerabilityType::StackOverflow,
102            scenario: MemoryTestScenario::DeepRecursion,
103        });
104
105        // Buffer overflow test
106        self.test_cases.push(MemorySafetyTest {
107            name: "Buffer Overflow Test".to_string(),
108            vulnerability_type: MemoryVulnerabilityType::BufferOverflow,
109            scenario: MemoryTestScenario::LargeArrayAllocation,
110        });
111
112        // Circular references test
113        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    /// Run all memory safety tests
121    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    /// Execute memory safety test
135    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        // Check for memory issues related to this test
156        let test_issues: Vec<_> = self
157            .memory_issues
158            .iter()
159            .rev()
160            .take(1) // Take the most recent issue
161            .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    /// Test large array allocation
188    fn test_large_array_allocation(&mut self, test: &MemorySafetyTest) -> Result<()> {
189        // Simulate large memory allocation
190        let large_size = 1024 * 1024 * 100; // 100MB
191
192        // Record before allocation
193        let before_usage = self.memory_tracking.current_usage;
194
195        // Simulate allocation
196        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        // Check if this indicates a potential issue (simplified logic)
202        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    /// Test rapid allocation
224    fn test_rapid_allocation(&mut self, _test: &MemorySafetyTest) -> Result<()> {
225        // Simulate rapid allocations
226        for i in 0..1000 {
227            let alloc_size = 1024; // 1KB
228            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        // Check for fragmentation
241        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    /// Test deep recursion
256    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    /// Test circular references
276    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    /// Simple randomized memory issue detection
292    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    /// Generate memory-specific recommendations
298    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    /// Get memory issues
350    pub fn get_issues(&self) -> &[MemoryIssue] {
351        &self.memory_issues
352    }
353
354    /// Get memory tracking info
355    pub fn get_memory_tracking(&self) -> &MemoryUsageTracker {
356        &self.memory_tracking
357    }
358
359    /// Get current memory usage
360    pub fn current_memory_usage(&self) -> usize {
361        self.memory_tracking.current_usage
362    }
363
364    /// Get peak memory usage
365    pub fn peak_memory_usage(&self) -> usize {
366        self.memory_tracking.peak_usage
367    }
368}
369
370/// Memory test result
371#[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}