1use crate::analysis::detectors::Detector;
7use crate::analysis_engine::{AnalysisEngine, Analyzer};
8use crate::capture::{CaptureBackendType, CaptureEngine};
9use crate::event_store::EventStore;
10use crate::metadata::MetadataEngine;
11use crate::query::QueryEngine;
12use crate::render_engine::RenderEngine;
13use crate::snapshot::SnapshotEngine;
14use crate::timeline::TimelineEngine;
15use std::sync::{Arc, Mutex};
16
17pub struct MemScope {
29 pub event_store: Arc<EventStore>,
31 pub capture: Arc<CaptureEngine>,
33 pub metadata: Arc<MetadataEngine>,
35 pub snapshot: Arc<SnapshotEngine>,
37 pub query: Arc<QueryEngine>,
39 pub analysis: Arc<Mutex<AnalysisEngine>>,
41 pub timeline: Arc<TimelineEngine>,
43 pub render: Arc<RenderEngine>,
45}
46
47impl MemScope {
48 fn to_allocation_info(
50 active: &crate::snapshot::ActiveAllocation,
51 ) -> crate::capture::types::AllocationInfo {
52 let thread_id_u64 = active.thread_id;
53 let thread_id = std::thread::current().id();
58
59 crate::capture::types::AllocationInfo {
60 ptr: active.ptr,
61 size: active.size,
62 var_name: active.var_name.clone(),
63 type_name: active.type_name.clone(),
64 scope_name: None,
65 timestamp_alloc: active.allocated_at,
66 timestamp_dealloc: None,
67 thread_id,
68 thread_id_u64,
69 borrow_count: 0,
70 stack_trace: None,
71 is_leaked: false,
72 lifetime_ms: None,
73 borrow_info: None,
74 clone_info: None,
75 ownership_history_available: false,
76 smart_pointer_info: None,
77 memory_layout: None,
78 generic_info: None,
79 dynamic_type_info: None,
80 runtime_state: None,
81 stack_allocation: None,
82 temporary_object: None,
83 fragmentation_analysis: None,
84 generic_instantiation: None,
85 type_relationships: None,
86 type_usage: None,
87 function_call_tracking: None,
88 lifecycle_tracking: None,
89 access_tracking: None,
90 drop_chain_analysis: None,
91 }
92 }
93
94 pub fn new() -> Self {
99 let event_store = Arc::new(EventStore::new());
101
102 let capture = Arc::new(CaptureEngine::new(
104 CaptureBackendType::Unified,
105 event_store.clone(),
106 ));
107
108 let metadata = Arc::new(MetadataEngine::new());
110
111 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
113
114 let query = Arc::new(QueryEngine::new(snapshot.clone()));
116
117 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
119
120 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
122
123 let render = Arc::new(RenderEngine::new(snapshot.clone()));
125
126 Self {
127 event_store,
128 capture,
129 metadata,
130 snapshot,
131 query,
132 analysis,
133 timeline,
134 render,
135 }
136 }
137
138 pub fn with_backend(backend_type: CaptureBackendType) -> Self {
143 let event_store = Arc::new(EventStore::new());
145
146 let capture = Arc::new(CaptureEngine::new(backend_type, event_store.clone()));
148
149 let metadata = Arc::new(MetadataEngine::new());
151
152 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
154
155 let query = Arc::new(QueryEngine::new(snapshot.clone()));
157
158 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
160
161 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
163
164 let render = Arc::new(RenderEngine::new(snapshot.clone()));
166
167 Self {
168 event_store,
169 capture,
170 metadata,
171 snapshot,
172 query,
173 analysis,
174 timeline,
175 render,
176 }
177 }
178
179 pub fn register_analyzer(&self, analyzer: Box<dyn Analyzer>) {
184 if let Ok(mut analysis) = self.analysis.lock() {
185 analysis.register_analyzer(analyzer);
186 tracing::info!("Analyzer registered successfully");
187 } else {
188 tracing::error!("Failed to acquire analysis engine lock for registration");
189 }
190 }
191
192 pub fn summary(&self) -> crate::query::QueryResult {
194 self.query.summary()
195 }
196
197 pub fn top_allocations(&self, limit: usize) -> crate::query::QueryResult {
202 self.query.top_allocations(limit)
203 }
204
205 pub fn render_json(&self, verbose: bool) -> Result<crate::render_engine::RenderResult, String> {
210 let snapshot = self.snapshot.build_snapshot();
211 self.render.render_json(&snapshot, verbose)
212 }
213
214 pub fn clear(&self) {
216 self.event_store.clear();
217 }
218
219 pub fn event_count(&self) -> usize {
221 self.event_store.len()
222 }
223
224 pub fn register_detector<D>(&self, detector: D)
234 where
235 D: crate::analysis::detectors::Detector + Send + Sync + 'static,
236 {
237 use crate::analysis_engine::DetectorToAnalyzer;
238 let adapter = Box::new(DetectorToAnalyzer::new(detector));
239 self.register_analyzer(adapter);
240 }
241
242 pub fn run_detectors(&self) -> Vec<crate::analysis_engine::analyzer::AnalysisResult> {
247 if let Ok(analysis) = self.analysis.lock() {
248 analysis.analyze()
249 } else {
250 tracing::error!("Failed to acquire analysis engine lock");
251 vec![]
252 }
253 }
254
255 pub fn run_leak_detector(&self) -> crate::analysis::detectors::DetectionResult {
260 use crate::analysis::detectors::{LeakDetector, LeakDetectorConfig};
261 let detector = LeakDetector::new(LeakDetectorConfig::default());
262 let snapshot = self.snapshot.build_snapshot();
263 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
264 .active_allocations
265 .values()
266 .map(Self::to_allocation_info)
267 .collect();
268 detector.detect(&allocations)
269 }
270
271 pub fn run_uaf_detector(&self) -> crate::analysis::detectors::DetectionResult {
276 use crate::analysis::detectors::{UafDetector, UafDetectorConfig};
277 let detector = UafDetector::new(UafDetectorConfig::default());
278 let snapshot = self.snapshot.build_snapshot();
279 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
280 .active_allocations
281 .values()
282 .map(Self::to_allocation_info)
283 .collect();
284 detector.detect(&allocations)
285 }
286
287 pub fn run_overflow_detector(&self) -> crate::analysis::detectors::DetectionResult {
292 use crate::analysis::detectors::{OverflowDetector, OverflowDetectorConfig};
293 let detector = OverflowDetector::new(OverflowDetectorConfig::default());
294 let snapshot = self.snapshot.build_snapshot();
295 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
296 .active_allocations
297 .values()
298 .map(Self::to_allocation_info)
299 .collect();
300 detector.detect(&allocations)
301 }
302
303 pub fn run_safety_detector(&self) -> crate::analysis::detectors::DetectionResult {
308 use crate::analysis::detectors::{SafetyDetector, SafetyDetectorConfig};
309 let detector = SafetyDetector::new(SafetyDetectorConfig::default());
310 let snapshot = self.snapshot.build_snapshot();
311 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
312 .active_allocations
313 .values()
314 .map(Self::to_allocation_info)
315 .collect();
316 detector.detect(&allocations)
317 }
318
319 pub fn run_lifecycle_detector(&self) -> crate::analysis::detectors::DetectionResult {
324 use crate::analysis::detectors::{LifecycleDetector, LifecycleDetectorConfig};
325 let detector = LifecycleDetector::new(LifecycleDetectorConfig::default());
326 let snapshot = self.snapshot.build_snapshot();
327 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
328 .active_allocations
329 .values()
330 .map(Self::to_allocation_info)
331 .collect();
332 detector.detect(&allocations)
333 }
334
335 pub fn export_html_with_template<P: AsRef<std::path::Path>>(
346 &self,
347 path: P,
348 template: crate::render_engine::export::DashboardTemplate,
349 ) -> Result<(), String> {
350 use crate::render_engine::export::export_dashboard_html_with_template;
351 use crate::tracker::Tracker;
352 use std::sync::Arc;
353
354 let tracker = Tracker::new();
356 let passport_tracker =
357 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
358
359 export_dashboard_html_with_template(path, &tracker, &passport_tracker, template, None)
360 .map_err(|e| format!("Failed to export HTML: {}", e))
361 }
362
363 pub fn export_html<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
376 use crate::render_engine::export::DashboardTemplate;
377
378 let _snapshot = self.snapshot.build_snapshot();
379 self.export_html_with_template(path, DashboardTemplate::Unified)
380 }
381
382 pub fn export_json<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
401 use crate::render_engine::export::export_all_json;
402 use crate::tracker::Tracker;
403 use std::sync::Arc;
404
405 let tracker = Tracker::new();
406 let passport_tracker =
407 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
408 let async_tracker = Arc::new(crate::capture::backends::async_tracker::AsyncTracker::new());
409
410 export_all_json(path, &tracker, &passport_tracker, &async_tracker)
411 .map_err(|e| format!("Failed to export JSON files: {}", e))
412 }
413}
414
415impl Default for MemScope {
416 fn default() -> Self {
417 Self::new()
418 }
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424
425 #[test]
426 fn test_memscope_creation() {
427 let memscope = MemScope::new();
428 assert_eq!(memscope.event_count(), 0);
429 }
430
431 #[test]
432 fn test_memscope_default() {
433 let memscope = MemScope::default();
434 assert_eq!(memscope.event_count(), 0);
435 }
436
437 #[test]
438 fn test_memscope_with_backend() {
439 let memscope = MemScope::with_backend(CaptureBackendType::Core);
440 assert_eq!(memscope.event_count(), 0);
441 }
442
443 #[test]
444 fn test_summary() {
445 let memscope = MemScope::new();
446 let result = memscope.summary();
447 match result {
448 crate::query::QueryResult::Summary(_) => (),
449 _ => panic!("Expected summary result"),
450 }
451 }
452
453 #[test]
454 fn test_top_allocations() {
455 let memscope = MemScope::new();
456 let result = memscope.top_allocations(10);
457 match result {
458 crate::query::QueryResult::Allocations(_) => (),
459 _ => panic!("Expected allocations result"),
460 }
461 }
462
463 #[test]
464 fn test_render_json() {
465 let memscope = MemScope::new();
466 let result = memscope.render_json(false);
467 assert!(result.is_ok());
468 }
469
470 #[test]
471 fn test_clear() {
472 let memscope = MemScope::new();
473 memscope.capture.capture_alloc(0x1000, 1024, 1);
475 assert_eq!(memscope.event_count(), 1);
476
477 memscope.clear();
478 assert_eq!(memscope.event_count(), 0);
479 }
480}