Skip to main content

memscope_rs/analysis/
mod.rs

1//! Memory analysis functionality
2//!
3//! This module provides advanced analysis capabilities:
4//! - Enhanced memory analysis
5//! - Circular reference detection
6//! - Unsafe FFI tracking
7//! - Unknown memory region analysis
8//! - Type classification
9//! - Performance metrics
10//! - Quality assurance
11//! - Size estimation
12//! - Dedicated detectors (LeakDetector, UafDetector, etc.)
13
14// Node ID module - unified node identity system
15pub mod node_id;
16
17// Detector modules
18pub mod detectors;
19
20pub mod circular_reference;
21pub mod heap_scanner;
22pub mod relation_inference;
23pub mod unsafe_ffi_tracker;
24pub mod unsafe_inference;
25pub mod variable_relationships;
26
27// Submodules from refactoring
28pub mod closure;
29pub mod generic;
30pub mod safety;
31pub mod security;
32pub mod unknown;
33
34// New analysis modules for ComplexTypeForRust.md features
35pub mod async_analysis;
36pub mod borrow_analysis;
37
38pub mod ffi_function_resolver;
39pub mod lifecycle;
40pub mod lifecycle_analysis;
41pub mod memory_passport_tracker;
42pub mod top_n;
43
44// Integrated analysis submodules
45pub mod classification;
46pub mod estimation;
47pub mod metrics;
48pub mod quality;
49
50// Re-export key analysis functions
51pub use circular_reference::{CircularReference, CircularReferenceAnalysis, CircularReferenceNode};
52pub use unsafe_ffi_tracker::UnsafeFFITracker;
53pub use variable_relationships::{
54    build_variable_relationship_graph, GraphStatistics, RelationshipType as VarRelationshipType,
55    SmartPointerInfo as VarSmartPointerInfo, VariableCategory, VariableCluster, VariableNode,
56    VariableRelationship, VariableRelationshipGraph,
57};
58
59// Re-export NodeID for backward compatibility
60pub use node_id::{is_virtual_pointer, NodeId, VIRTUAL_PTR_BASE};
61pub mod relationship_cycle_detector;
62pub use relationship_cycle_detector::{detect_cycles_in_relationships, CycleDetectionResult};
63
64// Ownership graph analysis
65pub mod ownership_graph;
66pub use ownership_graph::{Edge, EdgeKind, Node, OwnershipGraph, OwnershipOp};
67
68// Ownership analyzer - static analysis for ownership semantics
69pub mod ownership_analyzer;
70
71// Re-export new analysis modules
72pub use detectors::{
73    Detector, LeakDetector, LeakDetectorConfig, LifecycleDetector, LifecycleDetectorConfig,
74    OverflowDetector, OverflowDetectorConfig, SafetyDetector, SafetyDetectorConfig, UafDetector,
75    UafDetectorConfig,
76};
77
78pub use async_analysis::{
79    get_global_async_analyzer, AsyncAnalyzer, AsyncPatternAnalysis, AsyncStatistics,
80};
81pub use borrow_analysis::{get_global_borrow_analyzer, BorrowAnalyzer, BorrowPatternAnalysis};
82pub use closure::{get_global_closure_analyzer, ClosureAnalysisReport, ClosureAnalyzer};
83pub use ffi_function_resolver::{
84    get_global_ffi_resolver, initialize_global_ffi_resolver, FfiFunctionCategory,
85    FfiFunctionResolver, FfiRiskLevel, ResolutionStats, ResolvedFfiFunction, ResolverConfig,
86};
87pub use generic::{get_global_generic_analyzer, GenericAnalyzer, GenericStatistics};
88pub use lifecycle::{
89    lifecycle_summary::{
90        AllocationLifecycleSummary, ExportMetadata, LifecycleEvent, LifecycleEventSummary,
91        LifecycleExportData, LifecyclePattern, LifecycleSummaryGenerator, SummaryConfig,
92        VariableGroup,
93    },
94    ownership_history::{
95        BorrowInfo, CloneInfo, OwnershipEvent, OwnershipEventType, OwnershipHistoryRecorder,
96        OwnershipStatistics, OwnershipSummary, RefCountInfo,
97    },
98};
99pub use lifecycle_analysis::{
100    get_global_lifecycle_analyzer, LifecycleAnalysisReport, LifecycleAnalyzer,
101};
102pub use memory_passport_tracker::{
103    get_global_passport_tracker, initialize_global_passport_tracker, LeakDetail,
104    LeakDetectionResult, MemoryPassport, MemoryPassportTracker, PassportEvent, PassportEventType,
105    PassportStatus, PassportTrackerConfig, PassportTrackerStats,
106};
107pub use safety::{
108    DynamicViolation, RiskAssessment, RiskFactor, RiskFactorType, SafetyAnalysisConfig,
109    SafetyAnalysisStats, SafetyAnalyzer, UnsafeReport, UnsafeSource,
110};
111pub use unsafe_ffi_tracker::ComprehensiveSafetyReport;
112pub use unsafe_inference::{
113    count_valid_pointers, get_valid_regions, is_valid_ptr, is_valid_ptr_static, InferenceMethod,
114    InferenceRecord, MemoryRegion, MemoryView, TypeGuess, TypeKind, UnsafeInferenceEngine,
115    ValidRegions,
116};
117
118// Heap scanner exports
119pub use heap_scanner::{HeapScanner, ScanResult};
120
121// Relation inference exports
122pub use relation_inference::{
123    detect_clones, detect_owner, detect_slice, CloneConfig, GraphBuilderConfig, RangeMap, Relation,
124    RelationEdge, RelationGraph, RelationGraphBuilder,
125};
126
127// Re-export integrated submodules
128pub use classification::{
129    pattern_matcher::PatternMatcher,
130    rule_engine::{Rule as ClassificationRule, RuleEngine},
131    type_classifier::{TypeCategory, TypeClassifier},
132};
133pub use estimation::{
134    size_estimator::SizeEstimator, type_classifier::TypeClassifier as EstimationTypeClassifier,
135};
136pub use metrics::{
137    analyzer::{Benchmark, PerformanceAnalyzer, PerformanceReport},
138    collector::{Metric, MetricType, MetricValue, MetricsCollector},
139    reporter::{AlertThreshold, MetricsReporter, ReportFormat},
140};
141pub use quality::{
142    analyzer::{AnalysisReport, CodeAnalyzer, QualityMetric},
143    checker::{MemoryLeakChecker, PerformanceChecker, SafetyChecker},
144    validator::{QualityValidator, ValidationResult, ValidationRule},
145};
146
147use crate::capture::types::stats::FragmentationAnalysis;
148use crate::capture::types::*;
149use std::sync::Arc;
150
151/// Main analysis interface - consolidates all analysis functionality
152pub struct AnalysisManager {
153    // This will contain the consolidated analysis functionality
154}
155
156impl AnalysisManager {
157    /// Create a new analysis manager instance
158    pub fn new() -> Self {
159        Self {}
160    }
161
162    /// Analyze memory fragmentation
163    pub fn analyze_fragmentation(&self, allocations: &[AllocationInfo]) -> FragmentationAnalysis {
164        if allocations.is_empty() {
165            return FragmentationAnalysis::default();
166        }
167
168        let active_allocations: Vec<_> = allocations
169            .iter()
170            .filter(|a| a.timestamp_dealloc.is_none())
171            .collect();
172
173        if active_allocations.is_empty() {
174            return FragmentationAnalysis::default();
175        }
176
177        let mut sorted_ptrs: Vec<usize> = active_allocations.iter().map(|a| a.ptr).collect();
178        sorted_ptrs.sort();
179
180        let mut gaps: Vec<usize> = Vec::new();
181        for i in 1..sorted_ptrs.len() {
182            let prev = sorted_ptrs[i - 1];
183            let curr = sorted_ptrs[i];
184            if curr > prev {
185                let prev_alloc = active_allocations
186                    .iter()
187                    .find(|a| a.ptr == prev)
188                    .map(|a| a.size)
189                    .unwrap_or(0);
190                let gap = curr.saturating_sub(prev + prev_alloc);
191                if gap > 0 {
192                    gaps.push(gap);
193                }
194            }
195        }
196
197        let total_memory: usize = active_allocations.iter().map(|a| a.size).sum();
198        let total_gap: usize = gaps.iter().sum();
199
200        let fragmentation_ratio = if total_memory > 0 {
201            total_gap as f64 / (total_memory + total_gap) as f64
202        } else {
203            0.0
204        };
205
206        let largest_free_block = gaps.iter().max().copied().unwrap_or(0);
207        let smallest_free_block = gaps.iter().min().copied().unwrap_or(0);
208        let free_block_count = gaps.len();
209        let total_free_memory = total_gap;
210
211        let external_fragmentation = if !gaps.is_empty() {
212            let avg_gap = total_gap as f64 / gaps.len() as f64;
213            let max_gap = largest_free_block as f64;
214            if max_gap > 0.0 {
215                1.0 - (avg_gap / max_gap)
216            } else {
217                0.0
218            }
219        } else {
220            0.0
221        };
222
223        let total_requested: usize = active_allocations.iter().map(|a| a.size).sum();
224        let total_allocated = total_requested + total_gap;
225        let internal_fragmentation = if total_allocated > 0 {
226            (total_gap as f64 / total_allocated as f64) * 100.0
227        } else {
228            0.0
229        };
230
231        FragmentationAnalysis {
232            fragmentation_ratio,
233            largest_free_block,
234            smallest_free_block,
235            free_block_count,
236            total_free_memory,
237            external_fragmentation,
238            internal_fragmentation,
239        }
240    }
241
242    /// Analyze system library usage
243    pub fn analyze_system_libraries(&self, allocations: &[AllocationInfo]) -> SystemLibraryStats {
244        let mut stats = SystemLibraryStats::default();
245
246        for alloc in allocations {
247            let type_name = alloc.type_name.as_deref().unwrap_or("");
248            let stack = alloc.stack_trace.as_deref().unwrap_or(&[]);
249
250            if type_name.contains("Vec<")
251                || type_name.contains("HashMap")
252                || type_name.contains("HashSet")
253                || type_name.contains("BTreeMap")
254                || type_name.contains("BTreeSet")
255            {
256                stats.std_collections.allocation_count += 1;
257                stats.std_collections.total_bytes += alloc.size;
258            }
259
260            if type_name.contains("Future")
261                || type_name.contains("async")
262                || type_name.contains("tokio")
263                || type_name.contains("async_std")
264            {
265                stats.async_runtime.allocation_count += 1;
266                stats.async_runtime.total_bytes += alloc.size;
267            }
268
269            if type_name.contains("TcpStream")
270                || type_name.contains("UdpSocket")
271                || type_name.contains("Http")
272                || stack.iter().any(|s| s.contains("net::"))
273            {
274                stats.network_io.allocation_count += 1;
275                stats.network_io.total_bytes += alloc.size;
276            }
277
278            if type_name.contains("File")
279                || type_name.contains("Path")
280                || stack.iter().any(|s| s.contains("fs::"))
281            {
282                stats.file_system.allocation_count += 1;
283                stats.file_system.total_bytes += alloc.size;
284            }
285
286            if type_name.contains("serde")
287                || type_name.contains("Json")
288                || type_name.contains("Deserialize")
289            {
290                stats.serialization.allocation_count += 1;
291                stats.serialization.total_bytes += alloc.size;
292            }
293
294            if type_name.contains("Regex") || type_name.contains("regex") {
295                stats.regex_engine.allocation_count += 1;
296                stats.regex_engine.total_bytes += alloc.size;
297            }
298
299            if type_name.contains("Crypto")
300                || type_name.contains("Hash")
301                || type_name.contains("Signature")
302            {
303                stats.crypto_security.allocation_count += 1;
304                stats.crypto_security.total_bytes += alloc.size;
305            }
306
307            if type_name.contains("Database")
308                || type_name.contains("Connection")
309                || type_name.contains("Query")
310            {
311                stats.database.allocation_count += 1;
312                stats.database.total_bytes += alloc.size;
313            }
314
315            if type_name.contains("Window")
316                || type_name.contains("Canvas")
317                || type_name.contains("Surface")
318                || type_name.contains("wgpu")
319            {
320                stats.graphics_ui.allocation_count += 1;
321                stats.graphics_ui.total_bytes += alloc.size;
322            }
323
324            if type_name.contains("Request")
325                || type_name.contains("Response")
326                || type_name.contains("hyper")
327                || type_name.contains("reqwest")
328            {
329                stats.http_stack.allocation_count += 1;
330                stats.http_stack.total_bytes += alloc.size;
331            }
332        }
333
334        stats
335    }
336
337    /// Analyze concurrency safety
338    pub fn analyze_concurrency_safety(
339        &self,
340        allocations: &[AllocationInfo],
341    ) -> ConcurrencyAnalysis {
342        let mut analysis = ConcurrencyAnalysis::default();
343
344        // Group by the captured numeric thread id: `AllocationInfo::thread_id`
345        // (`ThreadId`) cannot be rebuilt during reconstruction and would collapse
346        // every allocation into the analyzing thread.
347        let mut thread_alloc_counts: std::collections::HashMap<u64, usize> =
348            std::collections::HashMap::new();
349
350        for alloc in allocations {
351            let type_name = alloc.type_name.as_deref().unwrap_or("");
352
353            if type_name.contains("Arc<")
354                || type_name.contains("Mutex<")
355                || type_name.contains("RwLock<")
356            {
357                analysis.thread_safety_allocations += 1;
358                analysis.shared_memory_bytes += alloc.size;
359            }
360
361            if type_name.contains("Arc<") {
362                analysis.arc_shared += 1;
363            }
364
365            if type_name.contains("mpsc")
366                || type_name.contains("channel")
367                || type_name.contains("Sender")
368                || type_name.contains("Receiver")
369            {
370                analysis.channel_buffers += 1;
371            }
372
373            if type_name.contains("thread_local") || type_name.contains("LocalKey") {
374                analysis.thread_local_storage += 1;
375            }
376
377            if type_name.contains("Atomic") {
378                analysis.atomic_operations += 1;
379            }
380
381            *thread_alloc_counts.entry(alloc.thread_id_u64).or_insert(0) += 1;
382        }
383
384        let max_thread_allocs = thread_alloc_counts.values().max().copied().unwrap_or(0);
385        let min_thread_allocs = thread_alloc_counts.values().min().copied().unwrap_or(0);
386        let thread_count = thread_alloc_counts.len();
387
388        if thread_count <= 1 {
389            analysis.lock_contention_risk = "None".to_string();
390        } else {
391            let imbalance_ratio = if min_thread_allocs > 0 {
392                max_thread_allocs as f64 / min_thread_allocs as f64
393            } else {
394                f64::MAX
395            };
396
397            if imbalance_ratio > 10.0 {
398                analysis.lock_contention_risk = "High".to_string();
399            } else if imbalance_ratio > 3.0 {
400                analysis.lock_contention_risk = "Medium".to_string();
401            } else {
402                analysis.lock_contention_risk = "Low".to_string();
403            }
404        }
405
406        analysis
407    }
408
409    /// Get unsafe/FFI tracker instance
410    pub fn get_unsafe_ffi_tracker(&self) -> Arc<crate::unsafe_ffi_tracker::UnsafeFFITracker> {
411        // Delegate to existing global tracker
412        crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker()
413    }
414
415    /// Get unsafe/FFI statistics
416    pub fn get_unsafe_ffi_stats(&self) -> crate::unsafe_ffi_tracker::UnsafeFFIStats {
417        // Get stats from the global tracker
418        self.get_unsafe_ffi_tracker().get_stats()
419    }
420
421    /// Analyze circular references in smart pointers
422    pub fn analyze_circular_references(
423        &self,
424        allocations: &[AllocationInfo],
425    ) -> crate::circular_reference::CircularReferenceAnalysis {
426        crate::circular_reference::detect_circular_references(allocations)
427    }
428
429    /// Analyze borrow checker integration and lifetime tracking
430    pub fn analyze_borrow_patterns(
431        &self,
432        _allocations: &[AllocationInfo],
433    ) -> BorrowPatternAnalysis {
434        let analyzer = get_global_borrow_analyzer();
435        analyzer.analyze_borrow_patterns()
436    }
437
438    /// Analyze generic type usage and constraints
439    pub fn analyze_generic_types(&self, _allocations: &[AllocationInfo]) -> GenericStatistics {
440        // Create a new analyzer instance to avoid global state pollution in tests
441        let analyzer = GenericAnalyzer::new();
442        analyzer.get_generic_statistics()
443    }
444
445    /// Analyze async types and Future state machines
446    pub fn analyze_async_patterns(&self, _allocations: &[AllocationInfo]) -> AsyncPatternAnalysis {
447        let analyzer = get_global_async_analyzer();
448        analyzer.analyze_async_patterns()
449    }
450
451    /// Analyze closure captures and lifetime relationships
452    pub fn analyze_closure_patterns(
453        &self,
454        allocations: &[AllocationInfo],
455    ) -> ClosureAnalysisReport {
456        let analyzer = get_global_closure_analyzer();
457        analyzer.analyze_closure_patterns(allocations)
458    }
459
460    /// Analyze lifecycle patterns including Drop trait and RAII
461    pub fn analyze_lifecycle_patterns(
462        &self,
463        _allocations: &[AllocationInfo],
464    ) -> LifecycleAnalysisReport {
465        let analyzer = get_global_lifecycle_analyzer();
466        analyzer.get_lifecycle_report()
467    }
468
469    /// Analyze memory leaks
470    pub fn analyze_memory_leaks(
471        &self,
472        allocations: &[AllocationInfo],
473    ) -> crate::analysis::detectors::DetectionResult {
474        let detector = crate::analysis::detectors::LeakDetector::new(
475            crate::analysis::detectors::LeakDetectorConfig::default(),
476        );
477        detector.detect(allocations)
478    }
479
480    /// Analyze use-after-free issues
481    pub fn analyze_use_after_free(
482        &self,
483        allocations: &[AllocationInfo],
484    ) -> crate::analysis::detectors::DetectionResult {
485        let detector = crate::analysis::detectors::UafDetector::new(
486            crate::analysis::detectors::UafDetectorConfig::default(),
487        );
488        detector.detect(allocations)
489    }
490
491    /// Analyze buffer overflow issues
492    pub fn analyze_buffer_overflow(
493        &self,
494        allocations: &[AllocationInfo],
495    ) -> crate::analysis::detectors::DetectionResult {
496        let detector = crate::analysis::detectors::OverflowDetector::new(
497            crate::analysis::detectors::OverflowDetectorConfig::default(),
498        );
499        detector.detect(allocations)
500    }
501
502    /// Analyze safety violations
503    pub fn analyze_safety_violations(
504        &self,
505        allocations: &[AllocationInfo],
506    ) -> crate::analysis::detectors::DetectionResult {
507        let detector = crate::analysis::detectors::SafetyDetector::new(
508            crate::analysis::detectors::SafetyDetectorConfig::default(),
509        );
510        detector.detect(allocations)
511    }
512
513    /// Analyze lifecycle issues
514    pub fn analyze_lifecycle_issues(
515        &self,
516        allocations: &[AllocationInfo],
517    ) -> crate::analysis::detectors::DetectionResult {
518        let detector = crate::analysis::detectors::LifecycleDetector::new(
519            crate::analysis::detectors::LifecycleDetectorConfig::default(),
520        );
521        detector.detect(allocations)
522    }
523
524    /// Perform comprehensive analysis
525    pub fn perform_comprehensive_analysis(
526        &self,
527        allocations: &[AllocationInfo],
528        stats: &MemoryStats,
529    ) -> ComprehensiveAnalysisReport {
530        let fragmentation = self.analyze_fragmentation(allocations);
531        let system_libs = self.analyze_system_libraries(allocations);
532        let concurrency = self.analyze_concurrency_safety(allocations);
533        let unsafe_stats = self.get_unsafe_ffi_stats();
534        let circular_refs = self.analyze_circular_references(allocations);
535
536        // New comprehensive analysis features
537        let borrow_analysis = self.analyze_borrow_patterns(allocations);
538        let generic_analysis = self.analyze_generic_types(allocations);
539        let async_analysis = self.analyze_async_patterns(allocations);
540        let closure_analysis = self.analyze_closure_patterns(allocations);
541        let lifecycle_analysis = self.analyze_lifecycle_patterns(allocations);
542
543        ComprehensiveAnalysisReport {
544            fragmentation_analysis: fragmentation,
545            system_library_stats: system_libs,
546            concurrency_analysis: concurrency,
547            unsafe_ffi_stats: unsafe_stats,
548            circular_reference_analysis: circular_refs,
549            borrow_analysis,
550            generic_analysis,
551            async_analysis,
552            closure_analysis,
553            lifecycle_analysis,
554            memory_stats: stats.clone(),
555            analysis_timestamp: std::time::SystemTime::now()
556                .duration_since(std::time::UNIX_EPOCH)
557                .unwrap_or_default()
558                .as_secs(),
559        }
560    }
561}
562
563impl Default for AnalysisManager {
564    fn default() -> Self {
565        Self::new()
566    }
567}
568
569/// Comprehensive analysis report
570#[derive(Debug, Clone)]
571pub struct ComprehensiveAnalysisReport {
572    /// Memory fragmentation analysis results
573    pub fragmentation_analysis: FragmentationAnalysis,
574    /// System library usage statistics
575    pub system_library_stats: SystemLibraryStats,
576    /// Concurrency safety analysis
577    pub concurrency_analysis: ConcurrencyAnalysis,
578    /// Unsafe and FFI operation statistics
579    pub unsafe_ffi_stats: crate::unsafe_ffi_tracker::UnsafeFFIStats,
580    /// Circular reference analysis for smart pointers
581    pub circular_reference_analysis: crate::circular_reference::CircularReferenceAnalysis,
582    /// Borrow checker integration and lifetime tracking
583    pub borrow_analysis: BorrowPatternAnalysis,
584    /// Generic type usage and constraint analysis
585    pub generic_analysis: GenericStatistics,
586    /// Async type and Future state machine analysis
587    pub async_analysis: AsyncPatternAnalysis,
588    /// Closure capture and lifetime analysis
589    pub closure_analysis: ClosureAnalysisReport,
590    /// Lifecycle patterns including Drop trait and RAII
591    pub lifecycle_analysis: LifecycleAnalysisReport,
592    /// Overall memory statistics
593    pub memory_stats: MemoryStats,
594    /// Timestamp when analysis was performed
595    pub analysis_timestamp: u64,
596}
597
598// Re-export all the existing analysis functions for backward compatibility
599// This ensures that existing code continues to work without changes
600
601/// Analyze memory fragmentation - backward compatibility function
602pub fn analyze_fragmentation(allocations: &[AllocationInfo]) -> FragmentationAnalysis {
603    let manager = AnalysisManager::new();
604    manager.analyze_fragmentation(allocations)
605}
606
607/// Analyze system library usage - backward compatibility function
608pub fn analyze_system_libraries(allocations: &[AllocationInfo]) -> SystemLibraryStats {
609    let manager = AnalysisManager::new();
610    manager.analyze_system_libraries(allocations)
611}
612
613/// Analyze concurrency safety - backward compatibility function
614pub fn analyze_concurrency_safety(allocations: &[AllocationInfo]) -> ConcurrencyAnalysis {
615    let manager = AnalysisManager::new();
616    manager.analyze_concurrency_safety(allocations)
617}
618
619/// Get global unsafe/FFI tracker - backward compatibility function
620pub fn get_global_unsafe_ffi_tracker() -> Arc<crate::unsafe_ffi_tracker::UnsafeFFITracker> {
621    crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker()
622}
623
624/// Get unsafe/FFI statistics - convenience function
625pub fn get_unsafe_ffi_stats() -> crate::unsafe_ffi_tracker::UnsafeFFIStats {
626    let manager = AnalysisManager::new();
627    manager.get_unsafe_ffi_stats()
628}
629
630/// Perform comprehensive analysis - convenience function
631pub fn perform_comprehensive_analysis(
632    allocations: &[AllocationInfo],
633    stats: &MemoryStats,
634) -> ComprehensiveAnalysisReport {
635    let manager = AnalysisManager::new();
636    manager.perform_comprehensive_analysis(allocations, stats)
637}
638
639// Analysis module - consolidating implementations for better organization
640// For now, we're just creating the interface and delegating to the existing implementations
641
642#[cfg(test)]
643mod tests {
644    use super::*;
645    use crate::capture::types::AllocationInfo;
646
647    #[test]
648    fn test_analyze_fragmentation() {
649        let manager = AnalysisManager::new();
650        // Create allocations with known gaps to verify precise calculation.
651        // alloc1 at 0x1000 (size 1024) → ends at 0x1400
652        // alloc2 at 0x2000 (size 512) → ends at 0x2200
653        // Gap between them: 0x2000 - 0x1400 = 3072 bytes
654        let allocations = vec![
655            AllocationInfo::new(0x1000, 1024),
656            AllocationInfo::new(0x2000, 512),
657        ];
658
659        let result = manager.analyze_fragmentation(&allocations);
660
661        // With known layout: total_memory = 1536, total_gap = 3072
662        // fragmentation_ratio = 3072 / (1536 + 3072) = 3072/4608 ≈ 0.667
663        assert!(
664            result.fragmentation_ratio > 0.5,
665            "fragmentation_ratio should be > 0.5, got {}",
666            result.fragmentation_ratio
667        );
668        assert_eq!(result.free_block_count, 1, "should have exactly 1 gap");
669        assert_eq!(
670            result.largest_free_block, 3072,
671            "largest gap should be 3072"
672        );
673        assert_eq!(
674            result.smallest_free_block, 3072,
675            "smallest gap should be 3072"
676        );
677    }
678
679    #[test]
680    fn test_analyze_fragmentation_no_gaps() {
681        let manager = AnalysisManager::new();
682        // Contiguous allocations: no gaps
683        let allocations = vec![
684            AllocationInfo::new(0x1000, 256),
685            AllocationInfo::new(0x1100, 256),
686        ];
687
688        let result = manager.analyze_fragmentation(&allocations);
689        assert_eq!(
690            result.fragmentation_ratio, 0.0,
691            "no gaps means zero fragmentation"
692        );
693        assert_eq!(result.free_block_count, 0);
694    }
695
696    #[test]
697    fn test_analyze_system_libraries() {
698        let manager = AnalysisManager::new();
699
700        // Create allocations with specific type names to trigger detection
701        let mut alloc_vec = AllocationInfo::new(0x1000, 256);
702        alloc_vec.type_name = Some("Vec<String>".to_string());
703
704        let mut alloc_hashmap = AllocationInfo::new(0x2000, 512);
705        alloc_hashmap.type_name = Some("HashMap<K, V>".to_string());
706
707        let mut alloc_file = AllocationInfo::new(0x3000, 128);
708        alloc_file.type_name = Some("File".to_string());
709
710        let mut alloc_regex = AllocationInfo::new(0x4000, 64);
711        alloc_regex.type_name = Some("Regex".to_string());
712
713        let allocations = vec![alloc_vec, alloc_hashmap, alloc_file, alloc_regex];
714
715        let result = manager.analyze_system_libraries(&allocations);
716
717        assert_eq!(
718            result.std_collections.allocation_count, 2,
719            "Vec and HashMap"
720        );
721        assert_eq!(result.std_collections.total_bytes, 256 + 512);
722        assert_eq!(result.file_system.allocation_count, 1, "File");
723        assert_eq!(result.file_system.total_bytes, 128);
724        assert_eq!(result.regex_engine.allocation_count, 1, "Regex");
725        assert_eq!(result.regex_engine.total_bytes, 64);
726        assert_eq!(result.async_runtime.allocation_count, 0, "no async types");
727    }
728
729    #[test]
730    fn test_analyze_concurrency_safety() {
731        let manager = AnalysisManager::new();
732
733        let mut alloc_arc = AllocationInfo::new(0x1000, 64);
734        alloc_arc.type_name = Some("Arc<Mutex<i32>>".to_string());
735
736        let mut alloc_mutex = AllocationInfo::new(0x2000, 128);
737        alloc_mutex.type_name = Some("Mutex<String>".to_string());
738
739        let mut alloc_atomic = AllocationInfo::new(0x3000, 8);
740        alloc_atomic.type_name = Some("AtomicUsize".to_string());
741
742        let allocations = vec![alloc_arc, alloc_mutex, alloc_atomic];
743
744        let result = manager.analyze_concurrency_safety(&allocations);
745
746        assert_eq!(result.thread_safety_allocations, 2, "Arc and Mutex");
747        assert_eq!(result.arc_shared, 1, "Arc");
748        assert_eq!(result.atomic_operations, 1, "AtomicUsize");
749        assert_eq!(result.shared_memory_bytes, 64 + 128);
750        assert_eq!(result.lock_contention_risk, "None", "single thread");
751    }
752
753    #[test]
754    fn test_analyze_concurrency_safety_multi_thread() {
755        let manager = AnalysisManager::new();
756
757        // Note: We can't easily create different ThreadId values,
758        // so this tests the single-thread case which is "None" risk.
759        let mut alloc_arc = AllocationInfo::new(0x1000, 64);
760        alloc_arc.type_name = Some("Arc<i32>".to_string());
761
762        let allocations = vec![alloc_arc];
763
764        let result = manager.analyze_concurrency_safety(&allocations);
765        assert_eq!(result.arc_shared, 1);
766    }
767
768    #[test]
769    fn test_get_unsafe_ffi_tracker() {
770        let manager = AnalysisManager::new();
771
772        let _tracker = manager.get_unsafe_ffi_tracker();
773
774        // Test that tracker is returned successfully
775    }
776
777    #[test]
778    fn test_get_unsafe_ffi_stats() {
779        let manager = AnalysisManager::new();
780
781        let stats = manager.get_unsafe_ffi_stats();
782
783        // Test that stats are returned with valid default values
784        assert_eq!(stats.total_operations, 0);
785        assert_eq!(stats.ffi_calls, 0);
786        assert_eq!(stats.raw_pointer_operations, 0);
787        assert_eq!(stats.memory_violations, 0);
788        assert!(stats.operations.is_empty());
789    }
790
791    #[test]
792    fn test_analyze_circular_references() {
793        let manager = AnalysisManager::new();
794        // Without smart pointer info, no circular references can be detected.
795        // This tests the zero case.
796        let allocations = vec![
797            AllocationInfo::new(0x4000, 128),
798            AllocationInfo::new(0x5000, 256),
799        ];
800
801        let result = manager.analyze_circular_references(&allocations);
802        assert_eq!(result.total_smart_pointers, 0, "no smart pointer info");
803        assert_eq!(result.circular_references.len(), 0);
804        assert_eq!(result.pointers_in_cycles, 0);
805        assert_eq!(result.total_leaked_memory, 0);
806    }
807
808    #[test]
809    fn test_analyze_borrow_patterns() {
810        let manager = AnalysisManager::new();
811        let allocations = vec![AllocationInfo::new(0x7000, 1024)];
812
813        let result = manager.analyze_borrow_patterns(&allocations);
814
815        // Test that borrow pattern analysis returns valid results
816        assert!(result.patterns.is_empty());
817        assert_eq!(result.total_events, 0);
818        assert!(result.analysis_timestamp > 0);
819    }
820
821    #[test]
822    fn test_analyze_generic_types() {
823        let manager = AnalysisManager::new();
824        let allocations = vec![AllocationInfo::new(0x8000, 256)];
825
826        let result = manager.analyze_generic_types(&allocations);
827
828        // Test that generic type analysis returns valid results
829        assert_eq!(result.total_instances, 0);
830        assert_eq!(result.unique_base_types, 0);
831        assert_eq!(result.total_instantiations, 0);
832        assert_eq!(result.constraint_violations, 0);
833        assert!(result.most_used_types.is_empty());
834    }
835
836    #[test]
837    fn test_analyze_async_patterns() {
838        let manager = AnalysisManager::new();
839        let allocations = vec![AllocationInfo::new(0x9000, 2048)];
840
841        let result = manager.analyze_async_patterns(&allocations);
842
843        // Test that async pattern analysis returns valid results
844        assert!(result.patterns.is_empty());
845        assert_eq!(result.total_futures_analyzed, 0);
846        assert!(result.analysis_timestamp > 0);
847    }
848
849    #[test]
850    fn test_analyze_closure_patterns() {
851        let manager = AnalysisManager::new();
852        let allocations = vec![AllocationInfo::new(0xa000, 128)];
853
854        let result = manager.analyze_closure_patterns(&allocations);
855
856        // Test that closure pattern analysis returns valid results
857        assert!(result.detected_closures.is_empty());
858        assert_eq!(result.capture_statistics.total_closures, 0);
859        assert!(result.optimization_suggestions.is_empty());
860        assert!(result.lifetime_analysis.lifetime_patterns.is_empty());
861        assert!(result.analysis_timestamp > 0);
862    }
863
864    #[test]
865    fn test_analyze_lifecycle_patterns() {
866        let manager = AnalysisManager::new();
867        let allocations = vec![AllocationInfo::new(0xb000, 512)];
868
869        let result = manager.analyze_lifecycle_patterns(&allocations);
870
871        // Test that lifecycle pattern analysis returns valid results
872        assert!(result.drop_events.is_empty());
873        assert!(result.raii_patterns.is_empty());
874        assert!(result.borrow_analysis.borrow_patterns.is_empty());
875        assert!(result.closure_captures.is_empty());
876        assert!(result.analysis_timestamp > 0);
877    }
878
879    #[test]
880    fn test_perform_comprehensive_analysis() {
881        let manager = AnalysisManager::new();
882        let allocations = vec![
883            AllocationInfo::new(0x1000, 1024),
884            AllocationInfo::new(0x2000, 512),
885            AllocationInfo::new(0x3000, 256),
886        ];
887        let stats = MemoryStats::new();
888
889        let result = manager.perform_comprehensive_analysis(&allocations, &stats);
890
891        assert!(
892            result.fragmentation_analysis.fragmentation_ratio >= 0.0
893                && result.fragmentation_analysis.fragmentation_ratio <= 1.0
894        );
895        assert_eq!(
896            result.system_library_stats.std_collections.allocation_count,
897            0
898        );
899        assert_eq!(result.concurrency_analysis.thread_safety_allocations, 0);
900        assert_eq!(result.unsafe_ffi_stats.total_operations, 0);
901        assert_eq!(result.circular_reference_analysis.total_smart_pointers, 0);
902        assert!(result.borrow_analysis.patterns.is_empty());
903        assert_eq!(result.generic_analysis.total_instances, 0);
904        assert!(result.async_analysis.patterns.is_empty());
905        assert!(result.closure_analysis.detected_closures.is_empty());
906        assert!(result.lifecycle_analysis.drop_events.is_empty());
907        assert_eq!(result.memory_stats.total_allocations, 0);
908        assert!(result.analysis_timestamp > 0);
909    }
910
911    #[test]
912    fn test_backward_compatibility_functions() {
913        let allocations = vec![AllocationInfo::new(0x1000, 1024)];
914
915        // Test backward compatibility functions
916        let frag_result = analyze_fragmentation(&allocations);
917        assert_eq!(frag_result.fragmentation_ratio, 0.0);
918
919        let lib_result = analyze_system_libraries(&allocations);
920        assert_eq!(lib_result.std_collections.allocation_count, 0);
921
922        let conc_result = analyze_concurrency_safety(&allocations);
923        assert_eq!(conc_result.thread_safety_allocations, 0);
924
925        let _tracker = get_global_unsafe_ffi_tracker();
926
927        let stats = get_unsafe_ffi_stats();
928        assert_eq!(stats.total_operations, 0);
929
930        let memory_stats = MemoryStats::new();
931        let comp_result = perform_comprehensive_analysis(&allocations, &memory_stats);
932        assert!(comp_result.analysis_timestamp > 0);
933    }
934
935    #[test]
936    fn test_empty_allocations_analysis() {
937        let manager = AnalysisManager::new();
938        let empty_allocations: Vec<AllocationInfo> = vec![];
939
940        // Test that analysis works with empty allocation list
941        let frag_result = manager.analyze_fragmentation(&empty_allocations);
942        assert_eq!(frag_result.fragmentation_ratio, 0.0);
943
944        let lib_result = manager.analyze_system_libraries(&empty_allocations);
945        assert_eq!(lib_result.std_collections.allocation_count, 0);
946
947        let conc_result = manager.analyze_concurrency_safety(&empty_allocations);
948        assert_eq!(conc_result.thread_safety_allocations, 0);
949
950        let circ_result = manager.analyze_circular_references(&empty_allocations);
951        assert_eq!(circ_result.total_smart_pointers, 0);
952    }
953
954    #[test]
955    fn test_large_allocation_list_analysis() {
956        let manager = AnalysisManager::new();
957        let mut allocations = Vec::new();
958
959        // Create a larger list of allocations to test performance
960        for i in 0..100 {
961            allocations.push(AllocationInfo::new(0x1000 + i * 0x1000, 1024 + i));
962        }
963
964        let stats = MemoryStats::new();
965        let result = manager.perform_comprehensive_analysis(&allocations, &stats);
966
967        // Test that analysis completes successfully with larger datasets
968        assert!(result.analysis_timestamp > 0);
969        assert_eq!(result.memory_stats.total_allocations, 0); // Default stats
970    }
971}