memscope_rs/analyzer/
safety.rs1use crate::analyzer::report::{IssueSeverity, SafetyIssue, SafetyReport};
4use crate::view::MemoryView;
5
6pub struct SafetyAnalysis {
10 view: MemoryView,
11}
12
13impl SafetyAnalysis {
14 pub fn from_view(view: &MemoryView) -> Self {
16 Self { view: view.clone() }
17 }
18
19 pub fn analyze(&self) -> SafetyReport {
26 let allocations = self.view.allocations();
27 let mut issues: Vec<SafetyIssue> = Vec::new();
28
29 let large_threshold = 1024 * 1024; for alloc in &allocations {
32 if alloc.size > large_threshold {
33 issues.push(SafetyIssue {
34 severity: IssueSeverity::High,
35 description: format!(
36 "Large allocation: {} bytes ({}), potential memory exhaustion",
37 alloc.size,
38 alloc.type_name.as_deref().unwrap_or("unknown")
39 ),
40 ptr: alloc.ptr,
41 });
42 }
43 }
44
45 let small_threshold = 64;
47 let small_allocs: Vec<_> = allocations
48 .iter()
49 .filter(|a| a.size < small_threshold)
50 .collect();
51 if small_allocs.len() > 100 {
52 issues.push(SafetyIssue {
53 severity: IssueSeverity::Medium,
54 description: format!(
55 "Many small allocations detected: {} allocations < {} bytes, potential fragmentation",
56 small_allocs.len(),
57 small_threshold
58 ),
59 ptr: None,
60 });
61 }
62
63 let score = calculate_safety_score(&issues);
65
66 SafetyReport {
67 score,
68 issue_count: issues.len(),
69 issues,
70 }
71 }
72
73 pub fn summary(&self) -> SafetySummary {
75 let report = self.analyze();
76 let critical = report
77 .issues
78 .iter()
79 .filter(|i| i.severity == IssueSeverity::Critical)
80 .count();
81 let high = report
82 .issues
83 .iter()
84 .filter(|i| i.severity == IssueSeverity::High)
85 .count();
86 let medium = report
87 .issues
88 .iter()
89 .filter(|i| i.severity == IssueSeverity::Medium)
90 .count();
91 let low = report
92 .issues
93 .iter()
94 .filter(|i| i.severity == IssueSeverity::Low)
95 .count();
96
97 SafetySummary {
98 score: report.score,
99 critical_count: critical,
100 high_count: high,
101 medium_count: medium,
102 low_count: low,
103 }
104 }
105}
106
107#[derive(Debug, Clone)]
109pub struct SafetySummary {
110 pub score: f64,
112 pub critical_count: usize,
114 pub high_count: usize,
116 pub medium_count: usize,
118 pub low_count: usize,
120}
121
122fn calculate_safety_score(issues: &[SafetyIssue]) -> f64 {
124 let mut score: f64 = 100.0;
125
126 for issue in issues {
127 let penalty: f64 = match issue.severity {
128 IssueSeverity::Critical => 25.0,
129 IssueSeverity::High => 10.0,
130 IssueSeverity::Medium => 5.0,
131 IssueSeverity::Low => 1.0,
132 };
133 score = (score - penalty).max(0.0);
134 }
135
136 score
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use crate::event_store::MemoryEvent;
143
144 #[test]
145 fn test_safety_analysis() {
146 let events = vec![MemoryEvent::allocate(0x1000, 64, 1)];
147 let view = MemoryView::from_events(events);
148 let analysis = SafetyAnalysis::from_view(&view);
149 let report = analysis.analyze();
150 assert!(report.score > 0.0);
151 }
152
153 #[test]
154 fn test_large_allocation_detection() {
155 let events = vec![MemoryEvent::allocate(0x1000, 2 * 1024 * 1024, 1)]; let view = MemoryView::from_events(events);
157 let analysis = SafetyAnalysis::from_view(&view);
158 let report = analysis.analyze();
159 assert!(report
160 .issues
161 .iter()
162 .any(|i| i.description.contains("Large allocation")));
163 }
164}