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::StackOwner { heap_ptr, .. } => heap_ptr,
65 crate::core::types::TrackKind::Container | crate::core::types::TrackKind::Value => 0,
66 };
67
68 crate::capture::types::AllocationInfo {
69 ptr,
70 size: active.size,
71 var_name: active.var_name.clone(),
72 type_name: active.type_name.clone(),
73 scope_name: None,
74 timestamp_alloc: active.allocated_at,
75 timestamp_dealloc: None,
76 thread_id,
77 thread_id_u64,
78 borrow_count: 0,
79 stack_trace: None,
80 is_leaked: false,
81 lifetime_ms: None,
82 module_path: None,
83 borrow_info: None,
84 clone_info: None,
85 ownership_history_available: false,
86 smart_pointer_info: None,
87 memory_layout: None,
88 generic_info: None,
89 dynamic_type_info: None,
90 runtime_state: None,
91 stack_allocation: None,
92 temporary_object: None,
93 fragmentation_analysis: None,
94 generic_instantiation: None,
95 type_relationships: None,
96 type_usage: None,
97 function_call_tracking: None,
98 lifecycle_tracking: None,
99 access_tracking: None,
100 drop_chain_analysis: None,
101 stack_ptr: active.stack_ptr,
102 task_id: None,
103 }
104 }
105
106 pub fn new() -> Self {
111 let event_store = Arc::new(EventStore::new());
113
114 let capture = Arc::new(CaptureEngine::new(
116 CaptureBackendType::Unified,
117 event_store.clone(),
118 ));
119
120 let metadata = Arc::new(MetadataEngine::new());
122
123 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
125
126 let query = Arc::new(QueryEngine::new(snapshot.clone()));
128
129 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
131
132 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
134
135 let render = Arc::new(RenderEngine::new(snapshot.clone()));
137
138 Self {
139 event_store,
140 capture,
141 metadata,
142 snapshot,
143 query,
144 analysis,
145 timeline,
146 render,
147 }
148 }
149
150 pub fn with_backend(backend_type: CaptureBackendType) -> Self {
155 let event_store = Arc::new(EventStore::new());
157
158 let capture = Arc::new(CaptureEngine::new(backend_type, event_store.clone()));
160
161 let metadata = Arc::new(MetadataEngine::new());
163
164 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
166
167 let query = Arc::new(QueryEngine::new(snapshot.clone()));
169
170 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
172
173 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
175
176 let render = Arc::new(RenderEngine::new(snapshot.clone()));
178
179 Self {
180 event_store,
181 capture,
182 metadata,
183 snapshot,
184 query,
185 analysis,
186 timeline,
187 render,
188 }
189 }
190
191 pub fn register_analyzer(&self, analyzer: Box<dyn Analyzer>) {
196 if let Ok(mut analysis) = self.analysis.lock() {
197 analysis.register_analyzer(analyzer);
198 tracing::info!("Analyzer registered successfully");
199 } else {
200 tracing::error!("Failed to acquire analysis engine lock for registration");
201 }
202 }
203
204 pub fn summary(&self) -> crate::query::QueryResult {
206 self.query.summary()
207 }
208
209 pub fn top_allocations(&self, limit: usize) -> crate::query::QueryResult {
214 self.query.top_allocations(limit)
215 }
216
217 pub fn render_json(&self, verbose: bool) -> Result<crate::render_engine::RenderResult, String> {
222 let snapshot = self.snapshot.build_snapshot();
223 self.render.render_json(&snapshot, verbose)
224 }
225
226 pub fn clear(&self) {
228 self.event_store.clear();
229 }
230
231 pub fn event_count(&self) -> usize {
233 self.event_store.len()
234 }
235
236 pub fn register_detector<D>(&self, detector: D)
246 where
247 D: crate::analysis::detectors::Detector + Send + Sync + 'static,
248 {
249 use crate::analysis_engine::DetectorToAnalyzer;
250 let adapter = Box::new(DetectorToAnalyzer::new(detector));
251 self.register_analyzer(adapter);
252 }
253
254 pub fn run_detectors(&self) -> Vec<crate::analysis_engine::analyzer::AnalysisResult> {
259 if let Ok(analysis) = self.analysis.lock() {
260 analysis.analyze()
261 } else {
262 tracing::error!("Failed to acquire analysis engine lock");
263 vec![]
264 }
265 }
266
267 pub fn run_leak_detector(&self) -> crate::analysis::detectors::DetectionResult {
272 use crate::analysis::detectors::{LeakDetector, LeakDetectorConfig};
273 let detector = LeakDetector::new(LeakDetectorConfig::default());
274 let snapshot = self.snapshot.build_snapshot();
275 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
276 .active_allocations
277 .values()
278 .map(Self::to_allocation_info)
279 .collect();
280 detector.detect(&allocations)
281 }
282
283 pub fn run_uaf_detector(&self) -> crate::analysis::detectors::DetectionResult {
288 use crate::analysis::detectors::{UafDetector, UafDetectorConfig};
289 let detector = UafDetector::new(UafDetectorConfig::default());
290 let snapshot = self.snapshot.build_snapshot();
291 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
292 .active_allocations
293 .values()
294 .map(Self::to_allocation_info)
295 .collect();
296 detector.detect(&allocations)
297 }
298
299 pub fn run_overflow_detector(&self) -> crate::analysis::detectors::DetectionResult {
304 use crate::analysis::detectors::{OverflowDetector, OverflowDetectorConfig};
305 let detector = OverflowDetector::new(OverflowDetectorConfig::default());
306 let snapshot = self.snapshot.build_snapshot();
307 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
308 .active_allocations
309 .values()
310 .map(Self::to_allocation_info)
311 .collect();
312 detector.detect(&allocations)
313 }
314
315 pub fn run_safety_detector(&self) -> crate::analysis::detectors::DetectionResult {
320 use crate::analysis::detectors::{SafetyDetector, SafetyDetectorConfig};
321 let detector = SafetyDetector::new(SafetyDetectorConfig::default());
322 let snapshot = self.snapshot.build_snapshot();
323 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
324 .active_allocations
325 .values()
326 .map(Self::to_allocation_info)
327 .collect();
328 detector.detect(&allocations)
329 }
330
331 pub fn run_lifecycle_detector(&self) -> crate::analysis::detectors::DetectionResult {
336 use crate::analysis::detectors::{LifecycleDetector, LifecycleDetectorConfig};
337 let detector = LifecycleDetector::new(LifecycleDetectorConfig::default());
338 let snapshot = self.snapshot.build_snapshot();
339 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
340 .active_allocations
341 .values()
342 .map(Self::to_allocation_info)
343 .collect();
344 detector.detect(&allocations)
345 }
346
347 pub fn export_html_with_template<P: AsRef<std::path::Path>>(
358 &self,
359 path: P,
360 template: crate::render_engine::export::DashboardTemplate,
361 ) -> Result<(), String> {
362 use crate::render_engine::export::export_dashboard_html_with_template;
363 use crate::tracker::Tracker;
364 use std::sync::Arc;
365
366 let tracker = Tracker::new();
368 let passport_tracker =
369 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
370
371 export_dashboard_html_with_template(path, &tracker, &passport_tracker, template, None)
372 .map_err(|e| format!("Failed to export HTML: {}", e))
373 }
374
375 pub fn export_html<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
388 use crate::render_engine::export::DashboardTemplate;
389
390 let _snapshot = self.snapshot.build_snapshot();
391 self.export_html_with_template(path, DashboardTemplate::Unified)
392 }
393
394 pub fn export_json<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
413 use crate::render_engine::export::export_all_json;
414 use crate::tracker::Tracker;
415 use std::sync::Arc;
416
417 let tracker = Tracker::new();
418 let passport_tracker =
419 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
420 let async_tracker = Arc::new(crate::capture::backends::async_tracker::AsyncTracker::new());
421
422 export_all_json(path, &tracker, &passport_tracker, &async_tracker)
423 .map_err(|e| format!("Failed to export JSON files: {}", e))
424 }
425}
426
427impl Default for MemScope {
428 fn default() -> Self {
429 Self::new()
430 }
431}
432
433#[cfg(test)]
434mod tests {
435 use super::*;
436
437 #[test]
438 fn test_memscope_creation() {
439 let memscope = MemScope::new();
440 assert_eq!(memscope.event_count(), 0);
441 }
442
443 #[test]
444 fn test_memscope_default() {
445 let memscope = MemScope::default();
446 assert_eq!(memscope.event_count(), 0);
447 }
448
449 #[test]
450 fn test_memscope_with_backend() {
451 let memscope = MemScope::with_backend(CaptureBackendType::Core);
452 assert_eq!(memscope.event_count(), 0);
453 }
454
455 #[test]
456 fn test_summary() {
457 let memscope = MemScope::new();
458 let result = memscope.summary();
459 match result {
460 crate::query::QueryResult::Summary(_) => (),
461 _ => panic!("Expected summary result"),
462 }
463 }
464
465 #[test]
466 fn test_top_allocations() {
467 let memscope = MemScope::new();
468 let result = memscope.top_allocations(10);
469 match result {
470 crate::query::QueryResult::Allocations(_) => (),
471 _ => panic!("Expected allocations result"),
472 }
473 }
474
475 #[test]
476 fn test_render_json() {
477 let memscope = MemScope::new();
478 let result = memscope.render_json(false);
479 assert!(result.is_ok());
480 }
481
482 #[test]
483 fn test_clear() {
484 let memscope = MemScope::new();
485 memscope.capture.capture_alloc(0x1000, 1024, 1);
487 assert_eq!(memscope.event_count(), 1);
488
489 memscope.clear();
490 assert_eq!(memscope.event_count(), 0);
491 }
492}