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 generation_id: 0,
104 }
105 }
106
107 pub fn new() -> Self {
112 let event_store = Arc::new(EventStore::new());
114
115 let capture = Arc::new(CaptureEngine::new(
117 CaptureBackendType::Unified,
118 event_store.clone(),
119 ));
120
121 let metadata = Arc::new(MetadataEngine::new());
123
124 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
126
127 let query = Arc::new(QueryEngine::new(snapshot.clone()));
129
130 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
132
133 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
135
136 let render = Arc::new(RenderEngine::new(snapshot.clone()));
138
139 Self {
140 event_store,
141 capture,
142 metadata,
143 snapshot,
144 query,
145 analysis,
146 timeline,
147 render,
148 }
149 }
150
151 pub fn with_backend(backend_type: CaptureBackendType) -> Self {
156 let event_store = Arc::new(EventStore::new());
158
159 let capture = Arc::new(CaptureEngine::new(backend_type, event_store.clone()));
161
162 let metadata = Arc::new(MetadataEngine::new());
164
165 let snapshot = Arc::new(SnapshotEngine::new(event_store.clone()));
167
168 let query = Arc::new(QueryEngine::new(snapshot.clone()));
170
171 let analysis = Arc::new(Mutex::new(AnalysisEngine::new(snapshot.clone())));
173
174 let timeline = Arc::new(TimelineEngine::new(event_store.clone()));
176
177 let render = Arc::new(RenderEngine::new(snapshot.clone()));
179
180 Self {
181 event_store,
182 capture,
183 metadata,
184 snapshot,
185 query,
186 analysis,
187 timeline,
188 render,
189 }
190 }
191
192 pub fn register_analyzer(&self, analyzer: Box<dyn Analyzer>) {
197 if let Ok(mut analysis) = self.analysis.lock() {
198 analysis.register_analyzer(analyzer);
199 tracing::info!("Analyzer registered successfully");
200 } else {
201 tracing::error!("Failed to acquire analysis engine lock for registration");
202 }
203 }
204
205 pub fn summary(&self) -> crate::query::QueryResult {
207 self.query.summary()
208 }
209
210 pub fn top_allocations(&self, limit: usize) -> crate::query::QueryResult {
215 self.query.top_allocations(limit)
216 }
217
218 pub fn render_json(&self, verbose: bool) -> Result<crate::render_engine::RenderResult, String> {
223 let snapshot = self.snapshot.build_snapshot();
224 self.render.render_json(&snapshot, verbose)
225 }
226
227 pub fn clear(&self) {
229 self.event_store.clear();
230 }
231
232 pub fn event_count(&self) -> usize {
234 self.event_store.len()
235 }
236
237 pub fn register_detector<D>(&self, detector: D)
247 where
248 D: crate::analysis::detectors::Detector + Send + Sync + 'static,
249 {
250 use crate::analysis_engine::DetectorToAnalyzer;
251 let adapter = Box::new(DetectorToAnalyzer::new(detector));
252 self.register_analyzer(adapter);
253 }
254
255 pub fn run_detectors(&self) -> Vec<crate::analysis_engine::analyzer::AnalysisResult> {
260 if let Ok(analysis) = self.analysis.lock() {
261 analysis.analyze()
262 } else {
263 tracing::error!("Failed to acquire analysis engine lock");
264 vec![]
265 }
266 }
267
268 pub fn run_leak_detector(&self) -> crate::analysis::detectors::DetectionResult {
273 use crate::analysis::detectors::{LeakDetector, LeakDetectorConfig};
274 let detector = LeakDetector::new(LeakDetectorConfig::default());
275 let snapshot = self.snapshot.build_snapshot();
276 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
277 .active_allocations
278 .values()
279 .map(Self::to_allocation_info)
280 .collect();
281 detector.detect(&allocations)
282 }
283
284 pub fn run_uaf_detector(&self) -> crate::analysis::detectors::DetectionResult {
289 use crate::analysis::detectors::{UafDetector, UafDetectorConfig};
290 let detector = UafDetector::new(UafDetectorConfig::default());
291 let snapshot = self.snapshot.build_snapshot();
292 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
293 .active_allocations
294 .values()
295 .map(Self::to_allocation_info)
296 .collect();
297 detector.detect(&allocations)
298 }
299
300 pub fn run_overflow_detector(&self) -> crate::analysis::detectors::DetectionResult {
305 use crate::analysis::detectors::{OverflowDetector, OverflowDetectorConfig};
306 let detector = OverflowDetector::new(OverflowDetectorConfig::default());
307 let snapshot = self.snapshot.build_snapshot();
308 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
309 .active_allocations
310 .values()
311 .map(Self::to_allocation_info)
312 .collect();
313 detector.detect(&allocations)
314 }
315
316 pub fn run_safety_detector(&self) -> crate::analysis::detectors::DetectionResult {
321 use crate::analysis::detectors::{SafetyDetector, SafetyDetectorConfig};
322 let detector = SafetyDetector::new(SafetyDetectorConfig::default());
323 let snapshot = self.snapshot.build_snapshot();
324 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
325 .active_allocations
326 .values()
327 .map(Self::to_allocation_info)
328 .collect();
329 detector.detect(&allocations)
330 }
331
332 pub fn run_lifecycle_detector(&self) -> crate::analysis::detectors::DetectionResult {
337 use crate::analysis::detectors::{LifecycleDetector, LifecycleDetectorConfig};
338 let detector = LifecycleDetector::new(LifecycleDetectorConfig::default());
339 let snapshot = self.snapshot.build_snapshot();
340 let allocations: Vec<crate::capture::types::AllocationInfo> = snapshot
341 .active_allocations
342 .values()
343 .map(Self::to_allocation_info)
344 .collect();
345 detector.detect(&allocations)
346 }
347
348 pub fn export_html_with_template<P: AsRef<std::path::Path>>(
359 &self,
360 path: P,
361 template: crate::render_engine::export::DashboardTemplate,
362 ) -> Result<(), String> {
363 use crate::render_engine::export::export_dashboard_html_with_template;
364 use crate::tracker::Tracker;
365 use std::sync::Arc;
366
367 let tracker = Tracker::new();
369 let passport_tracker =
370 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
371
372 export_dashboard_html_with_template(path, &tracker, &passport_tracker, template, None)
373 .map_err(|e| format!("Failed to export HTML: {}", e))
374 }
375
376 pub fn export_html<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
389 use crate::render_engine::export::DashboardTemplate;
390
391 let _snapshot = self.snapshot.build_snapshot();
392 self.export_html_with_template(path, DashboardTemplate::Unified)
393 }
394
395 pub fn export_json<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), String> {
414 use crate::render_engine::export::export_all_json;
415 use crate::tracker::Tracker;
416 use std::sync::Arc;
417
418 let tracker = Tracker::new();
419 let passport_tracker =
420 Arc::new(crate::analysis::memory_passport_tracker::get_global_passport_tracker());
421 let async_tracker = Arc::new(crate::capture::backends::async_tracker::AsyncTracker::new());
422
423 export_all_json(path, &tracker, &passport_tracker, &async_tracker)
424 .map_err(|e| format!("Failed to export JSON files: {}", e))
425 }
426}
427
428impl Default for MemScope {
429 fn default() -> Self {
430 Self::new()
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437
438 #[test]
439 fn test_memscope_creation() {
440 let memscope = MemScope::new();
441 assert_eq!(memscope.event_count(), 0);
442 }
443
444 #[test]
445 fn test_memscope_default() {
446 let memscope = MemScope::default();
447 assert_eq!(memscope.event_count(), 0);
448 }
449
450 #[test]
451 fn test_memscope_with_backend() {
452 let memscope = MemScope::with_backend(CaptureBackendType::Core);
453 assert_eq!(memscope.event_count(), 0);
454 }
455
456 #[test]
457 fn test_summary() {
458 let memscope = MemScope::new();
459 let result = memscope.summary();
460 match result {
461 crate::query::QueryResult::Summary(_) => (),
462 _ => panic!("Expected summary result"),
463 }
464 }
465
466 #[test]
467 fn test_top_allocations() {
468 let memscope = MemScope::new();
469 let result = memscope.top_allocations(10);
470 match result {
471 crate::query::QueryResult::Allocations(_) => (),
472 _ => panic!("Expected allocations result"),
473 }
474 }
475
476 #[test]
477 fn test_render_json() {
478 let memscope = MemScope::new();
479 let result = memscope.render_json(false);
480 assert!(result.is_ok());
481 }
482
483 #[test]
484 fn test_clear() {
485 let memscope = MemScope::new();
486 memscope.capture.capture_alloc(0x1000, 1024, 1);
488 assert_eq!(memscope.event_count(), 1);
489
490 memscope.clear();
491 assert_eq!(memscope.event_count(), 0);
492 }
493}