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 let ptr = match active.kind {
63 crate::core::types::TrackKind::HeapOwner { ptr, .. } => ptr,
64 crate::core::types::TrackKind::Container | crate::core::types::TrackKind::Value => 0,
65 };
66
67 crate::capture::types::AllocationInfo {
68 ptr,
69 size: active.size,
70 var_name: active.var_name.clone(),
71 type_name: active.type_name.clone(),
72 scope_name: None,
73 timestamp_alloc: active.allocated_at,
74 timestamp_dealloc: None,
75 thread_id,
76 thread_id_u64,
77 borrow_count: 0,
78 stack_trace: None,
79 is_leaked: false,
80 lifetime_ms: None,
81 borrow_info: None,
82 clone_info: None,
83 ownership_history_available: false,
84 smart_pointer_info: None,
85 memory_layout: None,
86 generic_info: None,
87 dynamic_type_info: None,
88 runtime_state: None,
89 stack_allocation: None,
90 temporary_object: None,
91 fragmentation_analysis: None,
92 generic_instantiation: None,
93 type_relationships: None,
94 type_usage: None,
95 function_call_tracking: None,
96 lifecycle_tracking: None,
97 access_tracking: None,
98 drop_chain_analysis: None,
99 }
100 }
101
102 pub fn new() -> Self {
107 let event_store = Arc::new(EventStore::new());
109
110 let capture = Arc::new(CaptureEngine::new(
112 CaptureBackendType::Unified,
113 event_store.clone(),
114 ));
115
116 let metadata = Arc::new(MetadataEngine::new());
118
119 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
121
122 let query = Arc::new(QueryEngine::new(snapshot.clone()));
124
125 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
127
128 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
130
131 let render = Arc::new(RenderEngine::new(snapshot.clone()));
133
134 Self {
135 event_store,
136 capture,
137 metadata,
138 snapshot,
139 query,
140 analysis,
141 timeline,
142 render,
143 }
144 }
145
146 pub fn with_backend(backend_type: CaptureBackendType) -> Self {
151 let event_store = Arc::new(EventStore::new());
153
154 let capture = Arc::new(CaptureEngine::new(backend_type, event_store.clone()));
156
157 let metadata = Arc::new(MetadataEngine::new());
159
160 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
162
163 let query = Arc::new(QueryEngine::new(snapshot.clone()));
165
166 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
168
169 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
171
172 let render = Arc::new(RenderEngine::new(snapshot.clone()));
174
175 Self {
176 event_store,
177 capture,
178 metadata,
179 snapshot,
180 query,
181 analysis,
182 timeline,
183 render,
184 }
185 }
186
187 pub fn register_analyzer(&self, analyzer: Box<dyn Analyzer>) {
192 if let Ok(mut analysis) = self.analysis.lock() {
193 analysis.register_analyzer(analyzer);
194 tracing::info!("Analyzer registered successfully");
195 } else {
196 tracing::error!("Failed to acquire analysis engine lock for registration");
197 }
198 }
199
200 pub fn summary(&self) -> crate::query::QueryResult {
202 self.query.summary()
203 }
204
205 pub fn top_allocations(&self, limit: usize) -> crate::query::QueryResult {
210 self.query.top_allocations(limit)
211 }
212
213 pub fn render_json(&self, verbose: bool) -> Result<crate::render_engine::RenderResult, String> {
218 let snapshot = self.snapshot.build_snapshot();
219 self.render.render_json(&snapshot, verbose)
220 }
221
222 pub fn clear(&self) {
224 self.event_store.clear();
225 }
226
227 pub fn event_count(&self) -> usize {
229 self.event_store.len()
230 }
231
232 pub fn register_detector<D>(&self, detector: D)
242 where
243 D: crate::analysis::detectors::Detector + Send + Sync + 'static,
244 {
245 use crate::analysis_engine::DetectorToAnalyzer;
246 let adapter = Box::new(DetectorToAnalyzer::new(detector));
247 self.register_analyzer(adapter);
248 }
249
250 pub fn run_detectors(&self) -> Vec<crate::analysis_engine::analyzer::AnalysisResult> {
255 if let Ok(analysis) = self.analysis.lock() {
256 analysis.analyze()
257 } else {
258 tracing::error!("Failed to acquire analysis engine lock");
259 vec![]
260 }
261 }
262
263 pub fn run_leak_detector(&self) -> crate::analysis::detectors::DetectionResult {
268 use crate::analysis::detectors::{LeakDetector, LeakDetectorConfig};
269 let detector = LeakDetector::new(LeakDetectorConfig::default());
270 let snapshot = self.snapshot.build_snapshot();
271 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
272 .active_allocations
273 .values()
274 .map(Self::to_allocation_info)
275 .collect();
276 detector.detect(&allocations)
277 }
278
279 pub fn run_uaf_detector(&self) -> crate::analysis::detectors::DetectionResult {
284 use crate::analysis::detectors::{UafDetector, UafDetectorConfig};
285 let detector = UafDetector::new(UafDetectorConfig::default());
286 let snapshot = self.snapshot.build_snapshot();
287 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
288 .active_allocations
289 .values()
290 .map(Self::to_allocation_info)
291 .collect();
292 detector.detect(&allocations)
293 }
294
295 pub fn run_overflow_detector(&self) -> crate::analysis::detectors::DetectionResult {
300 use crate::analysis::detectors::{OverflowDetector, OverflowDetectorConfig};
301 let detector = OverflowDetector::new(OverflowDetectorConfig::default());
302 let snapshot = self.snapshot.build_snapshot();
303 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
304 .active_allocations
305 .values()
306 .map(Self::to_allocation_info)
307 .collect();
308 detector.detect(&allocations)
309 }
310
311 pub fn run_safety_detector(&self) -> crate::analysis::detectors::DetectionResult {
316 use crate::analysis::detectors::{SafetyDetector, SafetyDetectorConfig};
317 let detector = SafetyDetector::new(SafetyDetectorConfig::default());
318 let snapshot = self.snapshot.build_snapshot();
319 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
320 .active_allocations
321 .values()
322 .map(Self::to_allocation_info)
323 .collect();
324 detector.detect(&allocations)
325 }
326
327 pub fn run_lifecycle_detector(&self) -> crate::analysis::detectors::DetectionResult {
332 use crate::analysis::detectors::{LifecycleDetector, LifecycleDetectorConfig};
333 let detector = LifecycleDetector::new(LifecycleDetectorConfig::default());
334 let snapshot = self.snapshot.build_snapshot();
335 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
336 .active_allocations
337 .values()
338 .map(Self::to_allocation_info)
339 .collect();
340 detector.detect(&allocations)
341 }
342
343 pub fn export_html_with_template<P: AsRef<std::path::Path>>(
354 &self,
355 path: P,
356 template: crate::render_engine::export::DashboardTemplate,
357 ) -> Result<(), String> {
358 use crate::render_engine::export::export_dashboard_html_with_template;
359 use crate::tracker::Tracker;
360 use std::sync::Arc;
361
362 let tracker = Tracker::new();
364 let passport_tracker =
365 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
366
367 export_dashboard_html_with_template(path, &tracker, &passport_tracker, template, None)
368 .map_err(|e| format!("Failed to export HTML: {}", e))
369 }
370
371 pub fn export_html<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
384 use crate::render_engine::export::DashboardTemplate;
385
386 let _snapshot = self.snapshot.build_snapshot();
387 self.export_html_with_template(path, DashboardTemplate::Unified)
388 }
389
390 pub fn export_json<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
409 use crate::render_engine::export::export_all_json;
410 use crate::tracker::Tracker;
411 use std::sync::Arc;
412
413 let tracker = Tracker::new();
414 let passport_tracker =
415 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
416 let async_tracker = Arc::new(crate::capture::backends::async_tracker::AsyncTracker::new());
417
418 export_all_json(path, &tracker, &passport_tracker, &async_tracker)
419 .map_err(|e| format!("Failed to export JSON files: {}", e))
420 }
421}
422
423impl Default for MemScope {
424 fn default() -> Self {
425 Self::new()
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[test]
434 fn test_memscope_creation() {
435 let memscope = MemScope::new();
436 assert_eq!(memscope.event_count(), 0);
437 }
438
439 #[test]
440 fn test_memscope_default() {
441 let memscope = MemScope::default();
442 assert_eq!(memscope.event_count(), 0);
443 }
444
445 #[test]
446 fn test_memscope_with_backend() {
447 let memscope = MemScope::with_backend(CaptureBackendType::Core);
448 assert_eq!(memscope.event_count(), 0);
449 }
450
451 #[test]
452 fn test_summary() {
453 let memscope = MemScope::new();
454 let result = memscope.summary();
455 match result {
456 crate::query::QueryResult::Summary(_) => (),
457 _ => panic!("Expected summary result"),
458 }
459 }
460
461 #[test]
462 fn test_top_allocations() {
463 let memscope = MemScope::new();
464 let result = memscope.top_allocations(10);
465 match result {
466 crate::query::QueryResult::Allocations(_) => (),
467 _ => panic!("Expected allocations result"),
468 }
469 }
470
471 #[test]
472 fn test_render_json() {
473 let memscope = MemScope::new();
474 let result = memscope.render_json(false);
475 assert!(result.is_ok());
476 }
477
478 #[test]
479 fn test_clear() {
480 let memscope = MemScope::new();
481 memscope.capture.capture_alloc(0x1000, 1024, 1);
483 assert_eq!(memscope.event_count(), 1);
484
485 memscope.clear();
486 assert_eq!(memscope.event_count(), 0);
487 }
488}