1use crate::core::types::{AllocationInfo, ImplementationDifficulty};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct UnknownMemoryRegionAnalysis {
13 pub total_unknown_bytes: usize,
15 pub unknown_percentage: f64,
17 pub unknown_categories: Vec<UnknownMemoryCategory>,
19 pub potential_causes: Vec<UnknownMemoryCause>,
21 pub reduction_strategies: Vec<UnknownRegionReductionStrategy>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct UnknownMemoryCategory {
28 pub category_type: UnknownRegionType,
30 pub description: String,
32 pub estimated_size: usize,
34 pub confidence_level: f64,
36 pub examples: Vec<UnknownMemoryExample>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub enum UnknownRegionType {
43 MemoryMappedRegions,
45 ThreadLocalStorage,
47 DynamicLibraryRegions,
49 SystemReservedRegions,
51 JitCodeRegions,
53 ExternalLibraryAllocations,
55 GuardPages,
57 VdsoRegions,
59 AnonymousMappings,
61 SharedMemorySegments,
63 PreTrackingAllocations,
65 CorruptedMetadata,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct UnknownMemoryExample {
72 pub address_range: (usize, usize),
74 pub size: usize,
76 pub suspected_origin: String,
78 pub access_pattern: MemoryAccessPattern,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84pub enum UnknownMemoryCause {
85 ForeignFunctionInterface {
87 library_name: String,
89 function_name: Option<String>,
91 },
92 MemoryMapping {
94 mapping_type: MappingType,
96 file_path: Option<String>,
98 },
99 SystemAllocations {
101 allocation_type: SystemAllocationType,
103 },
104 ThreadingMemory {
106 thread_id: Option<u64>,
108 memory_type: ThreadMemoryType,
110 },
111 DynamicLoading {
113 library_path: String,
115 load_time: u64,
117 },
118 InstrumentationGaps {
120 gap_type: InstrumentationGapType,
122 description: String,
124 },
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub enum MappingType {
130 FileMapping,
132 AnonymousMapping,
134 SharedMapping,
136 DeviceMapping,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub enum SystemAllocationType {
143 KernelBuffers,
145 DriverMemory,
147 SystemCaches,
149 HardwareReserved,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub enum ThreadMemoryType {
156 ThreadStack,
158 ThreadLocalStorage,
160 ThreadControlBlock,
162 ThreadSynchronization,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub enum InstrumentationGapType {
169 EarlyBootstrap,
171 SignalHandlers,
173 InterruptHandlers,
175 AtomicOperations,
177 CompilerOptimizations,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct UnknownRegionReductionStrategy {
184 pub strategy_type: ReductionStrategyType,
186 pub description: String,
188 pub implementation_steps: Vec<String>,
190 pub expected_improvement: f64,
192 pub implementation_difficulty: ImplementationDifficulty,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub enum ReductionStrategyType {
199 EnhancedInstrumentation,
201 BetterSymbolResolution,
203 MemoryMappingTracking,
205 FfiCallInterception,
207 SystemCallMonitoring,
209 ThreadAwareTracking,
211}
212
213pub struct UnknownMemoryAnalyzer {
215 known_system_regions: HashMap<(usize, usize), SystemRegionInfo>,
216 library_mappings: HashMap<String, LibraryMappingInfo>,
217 thread_memory_ranges: HashMap<u64, Vec<(usize, usize)>>,
218}
219
220impl Default for UnknownMemoryAnalyzer {
221 fn default() -> Self {
222 Self::new()
223 }
224}
225
226impl UnknownMemoryAnalyzer {
227 pub fn new() -> Self {
229 Self {
230 known_system_regions: HashMap::new(),
231 library_mappings: HashMap::new(),
232 thread_memory_ranges: HashMap::new(),
233 }
234 }
235
236 pub fn analyze_unknown_regions(
238 &mut self,
239 allocations: &[AllocationInfo],
240 ) -> UnknownMemoryRegionAnalysis {
241 let total_memory: usize = allocations.iter().map(|a| a.size).sum();
242 let unknown_allocations = self.identify_unknown_allocations(allocations);
243 let total_unknown: usize = unknown_allocations.iter().map(|a| a.size).sum();
244 let unknown_percentage = (total_unknown as f64 / total_memory as f64) * 100.0;
245
246 let unknown_categories = self.categorize_unknown_regions(&unknown_allocations);
248
249 let potential_causes = self.identify_potential_causes(&unknown_allocations);
251
252 let reduction_strategies = self.generate_reduction_strategies(&unknown_categories);
254
255 UnknownMemoryRegionAnalysis {
256 total_unknown_bytes: total_unknown,
257 unknown_percentage,
258 unknown_categories,
259 potential_causes,
260 reduction_strategies,
261 }
262 }
263
264 fn identify_unknown_allocations<'a>(
266 &self,
267 allocations: &'a [AllocationInfo],
268 ) -> Vec<&'a AllocationInfo> {
269 allocations
270 .iter()
271 .filter(|alloc| self.is_unknown_allocation(alloc))
272 .collect()
273 }
274
275 fn is_unknown_allocation(&self, allocation: &AllocationInfo) -> bool {
277 if self.is_in_stack_region(allocation.ptr) || self.is_in_heap_region(allocation.ptr) {
279 return false;
280 }
281
282 if self.is_known_system_region(allocation.ptr) {
284 return false;
285 }
286
287 true
289 }
290
291 fn categorize_unknown_regions(
293 &self,
294 unknown_allocations: &[&AllocationInfo],
295 ) -> Vec<UnknownMemoryCategory> {
296 let mut categories = Vec::new();
297
298 let mmap_allocations = self.identify_memory_mapped_regions(unknown_allocations);
300 if !mmap_allocations.is_empty() {
301 categories.push(UnknownMemoryCategory {
302 category_type: UnknownRegionType::MemoryMappedRegions,
303 description: "Memory-mapped files, shared memory, and anonymous mappings"
304 .to_string(),
305 estimated_size: mmap_allocations.iter().map(|a| a.size).sum(),
306 confidence_level: 0.8,
307 examples: self.generate_examples(&mmap_allocations, "Memory mapping"),
308 });
309 }
310
311 let tls_allocations = self.identify_thread_local_storage(unknown_allocations);
313 if !tls_allocations.is_empty() {
314 categories.push(UnknownMemoryCategory {
315 category_type: UnknownRegionType::ThreadLocalStorage,
316 description: "Thread-local storage and thread control blocks".to_string(),
317 estimated_size: tls_allocations.iter().map(|a| a.size).sum(),
318 confidence_level: 0.7,
319 examples: self.generate_examples(&tls_allocations, "Thread-local storage"),
320 });
321 }
322
323 let lib_allocations = self.identify_library_regions(unknown_allocations);
325 if !lib_allocations.is_empty() {
326 categories.push(UnknownMemoryCategory {
327 category_type: UnknownRegionType::DynamicLibraryRegions,
328 description: "Code and data sections of dynamically loaded libraries".to_string(),
329 estimated_size: lib_allocations.iter().map(|a| a.size).sum(),
330 confidence_level: 0.9,
331 examples: self.generate_examples(&lib_allocations, "Dynamic library"),
332 });
333 }
334
335 let ffi_allocations = self.identify_ffi_allocations(unknown_allocations);
337 if !ffi_allocations.is_empty() {
338 categories.push(UnknownMemoryCategory {
339 category_type: UnknownRegionType::ExternalLibraryAllocations,
340 description: "Memory allocated by external C/C++ libraries through FFI".to_string(),
341 estimated_size: ffi_allocations.iter().map(|a| a.size).sum(),
342 confidence_level: 0.6,
343 examples: self.generate_examples(&ffi_allocations, "FFI allocation"),
344 });
345 }
346
347 let system_allocations = self.identify_system_regions(unknown_allocations);
349 if !system_allocations.is_empty() {
350 categories.push(UnknownMemoryCategory {
351 category_type: UnknownRegionType::SystemReservedRegions,
352 description: "Kernel buffers, driver memory, and system caches".to_string(),
353 estimated_size: system_allocations.iter().map(|a| a.size).sum(),
354 confidence_level: 0.5,
355 examples: self.generate_examples(&system_allocations, "System region"),
356 });
357 }
358
359 let pre_tracking = self.identify_pre_tracking_allocations(unknown_allocations);
361 if !pre_tracking.is_empty() {
362 categories.push(UnknownMemoryCategory {
363 category_type: UnknownRegionType::PreTrackingAllocations,
364 description: "Memory allocated before tracking was initialized".to_string(),
365 estimated_size: pre_tracking.iter().map(|a| a.size).sum(),
366 confidence_level: 0.9,
367 examples: self.generate_examples(&pre_tracking, "Pre-tracking"),
368 });
369 }
370
371 categories
372 }
373
374 fn identify_potential_causes(
376 &self,
377 unknown_allocations: &[&AllocationInfo],
378 ) -> Vec<UnknownMemoryCause> {
379 let mut causes = Vec::new();
380
381 for allocation in unknown_allocations {
383 if self.is_likely_ffi_allocation(allocation) {
384 causes.push(UnknownMemoryCause::ForeignFunctionInterface {
385 library_name: self
386 .guess_library_name(allocation)
387 .unwrap_or_else(|| "unknown".to_string()),
388 function_name: None,
389 });
390 }
391 }
392
393 if self.has_memory_mapping_pattern(unknown_allocations) {
395 causes.push(UnknownMemoryCause::MemoryMapping {
396 mapping_type: MappingType::AnonymousMapping,
397 file_path: None,
398 });
399 }
400
401 if self.has_threading_pattern(unknown_allocations) {
403 causes.push(UnknownMemoryCause::ThreadingMemory {
404 thread_id: None,
405 memory_type: ThreadMemoryType::ThreadStack,
406 });
407 }
408
409 causes.push(UnknownMemoryCause::InstrumentationGaps {
411 gap_type: InstrumentationGapType::EarlyBootstrap,
412 description: "Memory allocated during early program initialization".to_string(),
413 });
414
415 causes
416 }
417
418 fn generate_reduction_strategies(
420 &self,
421 _categories: &[UnknownMemoryCategory],
422 ) -> Vec<UnknownRegionReductionStrategy> {
423 let strategies = vec![
424 UnknownRegionReductionStrategy {
426 strategy_type: ReductionStrategyType::EnhancedInstrumentation,
427 description: "Implement more comprehensive memory tracking hooks".to_string(),
428 implementation_steps: vec![
429 "Hook into mmap/munmap system calls".to_string(),
430 "Intercept malloc/free in all loaded libraries".to_string(),
431 "Track thread creation and destruction".to_string(),
432 "Monitor dynamic library loading".to_string(),
433 ],
434 expected_improvement: 60.0,
435 implementation_difficulty: ImplementationDifficulty::Hard,
436 },
437 UnknownRegionReductionStrategy {
439 strategy_type: ReductionStrategyType::FfiCallInterception,
440 description: "Intercept and track FFI calls to external libraries".to_string(),
441 implementation_steps: vec![
442 "Wrap all extern function calls".to_string(),
443 "Track memory allocations in C libraries".to_string(),
444 "Monitor shared library symbol resolution".to_string(),
445 ],
446 expected_improvement: 25.0,
447 implementation_difficulty: ImplementationDifficulty::Medium,
448 },
449 UnknownRegionReductionStrategy {
451 strategy_type: ReductionStrategyType::MemoryMappingTracking,
452 description: "Track memory mapping operations comprehensively".to_string(),
453 implementation_steps: vec![
454 "Monitor /proc/self/maps changes".to_string(),
455 "Track mmap/mprotect/munmap calls".to_string(),
456 "Analyze virtual memory layout".to_string(),
457 ],
458 expected_improvement: 20.0,
459 implementation_difficulty: ImplementationDifficulty::Medium,
460 },
461 ];
462
463 strategies
464 }
465
466 fn is_in_stack_region(&self, _ptr: usize) -> bool {
468 false }
472
473 fn is_in_heap_region(&self, _ptr: usize) -> bool {
474 false }
478
479 fn is_known_system_region(&self, ptr: usize) -> bool {
480 self.known_system_regions
481 .iter()
482 .any(|((start, end), _)| ptr >= *start && ptr < *end)
483 }
484
485 fn identify_memory_mapped_regions<'a>(
486 &self,
487 allocations: &[&'a AllocationInfo],
488 ) -> Vec<&'a AllocationInfo> {
489 allocations
490 .iter()
491 .filter(|alloc| self.is_likely_mmap_allocation(alloc))
492 .copied()
493 .collect()
494 }
495
496 fn identify_thread_local_storage<'a>(
497 &self,
498 allocations: &[&'a AllocationInfo],
499 ) -> Vec<&'a AllocationInfo> {
500 allocations
501 .iter()
502 .filter(|alloc| self.is_likely_tls_allocation(alloc))
503 .copied()
504 .collect()
505 }
506
507 fn identify_library_regions<'a>(
508 &self,
509 allocations: &[&'a AllocationInfo],
510 ) -> Vec<&'a AllocationInfo> {
511 allocations
512 .iter()
513 .filter(|alloc| self.is_likely_library_allocation(alloc))
514 .copied()
515 .collect()
516 }
517
518 fn identify_ffi_allocations<'a>(
519 &self,
520 allocations: &[&'a AllocationInfo],
521 ) -> Vec<&'a AllocationInfo> {
522 allocations
523 .iter()
524 .filter(|alloc| self.is_likely_ffi_allocation(alloc))
525 .copied()
526 .collect()
527 }
528
529 fn identify_system_regions<'a>(
530 &self,
531 allocations: &[&'a AllocationInfo],
532 ) -> Vec<&'a AllocationInfo> {
533 allocations
534 .iter()
535 .filter(|alloc| self.is_likely_system_allocation(alloc))
536 .copied()
537 .collect()
538 }
539
540 fn identify_pre_tracking_allocations<'a>(
541 &self,
542 allocations: &[&'a AllocationInfo],
543 ) -> Vec<&'a AllocationInfo> {
544 allocations
545 .iter()
546 .filter(|alloc| self.is_likely_pre_tracking_allocation(alloc))
547 .copied()
548 .collect()
549 }
550
551 fn is_likely_mmap_allocation(&self, allocation: &AllocationInfo) -> bool {
553 allocation.size >= 4096 && allocation.ptr % 4096 == 0
555 }
556
557 fn is_likely_tls_allocation(&self, allocation: &AllocationInfo) -> bool {
558 allocation.size < 1024 && self.is_in_thread_range(allocation.ptr)
560 }
561
562 fn is_likely_library_allocation(&self, allocation: &AllocationInfo) -> bool {
563 self.library_mappings
565 .values()
566 .any(|lib| lib.contains_address(allocation.ptr))
567 }
568
569 fn is_likely_ffi_allocation(&self, allocation: &AllocationInfo) -> bool {
570 allocation.type_name.is_none() && allocation.var_name.is_none()
572 }
573
574 fn is_likely_system_allocation(&self, allocation: &AllocationInfo) -> bool {
575 allocation.ptr < 0x1000 || allocation.ptr > 0x7fff_0000_0000
577 }
578
579 fn is_likely_pre_tracking_allocation(&self, allocation: &AllocationInfo) -> bool {
580 allocation.timestamp_alloc < 1000 }
583
584 fn is_in_thread_range(&self, ptr: usize) -> bool {
585 self.thread_memory_ranges.values().any(|ranges| {
586 ranges
587 .iter()
588 .any(|(start, end)| ptr >= *start && ptr < *end)
589 })
590 }
591
592 fn has_memory_mapping_pattern(&self, allocations: &[&AllocationInfo]) -> bool {
593 allocations
595 .iter()
596 .any(|alloc| self.is_likely_mmap_allocation(alloc))
597 }
598
599 fn has_threading_pattern(&self, allocations: &[&AllocationInfo]) -> bool {
600 allocations
602 .iter()
603 .any(|alloc| self.is_likely_tls_allocation(alloc))
604 }
605
606 fn guess_library_name(&self, allocation: &AllocationInfo) -> Option<String> {
607 for (name, info) in &self.library_mappings {
609 if info.contains_address(allocation.ptr) {
610 return Some(name.to_string());
611 }
612 }
613 None
614 }
615
616 fn generate_examples(
617 &self,
618 allocations: &[&AllocationInfo],
619 origin: &str,
620 ) -> Vec<UnknownMemoryExample> {
621 allocations
622 .iter()
623 .take(3) .map(|alloc| UnknownMemoryExample {
625 address_range: (alloc.ptr, alloc.ptr + alloc.size),
626 size: alloc.size,
627 suspected_origin: origin.to_string(),
628 access_pattern: MemoryAccessPattern::Unknown, })
630 .collect()
631 }
632}
633
634#[derive(Debug, Clone, Serialize, Deserialize)]
636pub struct SystemRegionInfo {
638 pub region_type: String,
640 pub description: String,
642 pub read_only: bool,
644}
645
646#[derive(Debug, Clone, Serialize, Deserialize)]
647pub struct LibraryMappingInfo {
649 pub start_address: usize,
651 pub end_address: usize,
653 pub permissions: String,
655 pub file_path: String,
657}
658
659impl LibraryMappingInfo {
660 pub fn contains_address(&self, addr: usize) -> bool {
662 addr >= self.start_address && addr < self.end_address
663 }
664}
665
666#[derive(Debug, Clone, Serialize, Deserialize)]
667pub enum MemoryAccessPattern {
669 Sequential,
671 Random,
673 Sparse,
675 Unknown,
677}
678
679#[cfg(test)]
680mod tests {
681 use super::*;
682 use crate::core::types::{AllocationInfo, ImplementationDifficulty};
683
684 fn create_test_allocation(
686 ptr: usize,
687 size: usize,
688 timestamp: u64,
689 type_name: Option<String>,
690 var_name: Option<String>,
691 ) -> AllocationInfo {
692 AllocationInfo {
693 ptr,
694 size,
695 timestamp_alloc: timestamp,
696 timestamp_dealloc: None,
697 type_name,
698 var_name,
699 scope_name: Some("test_scope".to_string()),
700 thread_id: "test_thread".to_string(),
701 borrow_count: 0,
702 stack_trace: Some(vec!["test_function".to_string()]),
703 is_leaked: false,
704 lifetime_ms: None,
705 borrow_info: None,
706 clone_info: None,
707 ownership_history_available: false,
708 smart_pointer_info: None,
709 memory_layout: None,
710 generic_info: None,
711 dynamic_type_info: None,
712 runtime_state: None,
713 stack_allocation: None,
714 temporary_object: None,
715 fragmentation_analysis: None,
716 generic_instantiation: None,
717 type_relationships: None,
718 type_usage: None,
719 function_call_tracking: None,
720 lifecycle_tracking: None,
721 access_tracking: None,
722 drop_chain_analysis: None,
723 }
724 }
725
726 fn create_test_allocations() -> Vec<AllocationInfo> {
728 vec![
729 create_test_allocation(0x7f0000000000, 8192, 1000, None, None),
731 create_test_allocation(
733 0x7fff00000100,
734 512,
735 2000,
736 Some("ThreadLocal".to_string()),
737 None,
738 ),
739 create_test_allocation(
741 0x7f8000000000,
742 4096,
743 3000,
744 Some("LibCode".to_string()),
745 Some("lib_var".to_string()),
746 ),
747 create_test_allocation(0x6000_0000_0000, 1024, 4000, None, None),
749 create_test_allocation(0x7fff_ffff_0000, 256, 5000, None, None),
751 create_test_allocation(0x4000_0000_0000, 2048, 100, Some("Early".to_string()), None),
753 create_test_allocation(
755 0x5555_5555_0000,
756 128,
757 6000,
758 Some("HeapData".to_string()),
759 Some("heap_var".to_string()),
760 ),
761 ]
762 }
763
764 #[test]
765 fn test_unknown_memory_analyzer_creation() {
766 let analyzer = UnknownMemoryAnalyzer::new();
767 assert!(analyzer.known_system_regions.is_empty());
768 assert!(analyzer.library_mappings.is_empty());
769 assert!(analyzer.thread_memory_ranges.is_empty());
770 }
771
772 #[test]
773 fn test_unknown_memory_analyzer_default() {
774 let analyzer = UnknownMemoryAnalyzer::default();
775 assert!(analyzer.known_system_regions.is_empty());
776 assert!(analyzer.library_mappings.is_empty());
777 assert!(analyzer.thread_memory_ranges.is_empty());
778 }
779
780 #[test]
781 fn test_analyze_unknown_regions_basic() {
782 let mut analyzer = UnknownMemoryAnalyzer::new();
783 let allocations = create_test_allocations();
784
785 let analysis = analyzer.analyze_unknown_regions(&allocations);
786
787 assert!(analysis.total_unknown_bytes > 0);
789 assert!(analysis.unknown_percentage >= 0.0 && analysis.unknown_percentage <= 100.0);
790 assert!(!analysis.unknown_categories.is_empty());
791 assert!(!analysis.potential_causes.is_empty());
792 assert!(!analysis.reduction_strategies.is_empty());
793 }
794
795 #[test]
796 fn test_identify_unknown_allocations() {
797 let analyzer = UnknownMemoryAnalyzer::new();
798 let allocations = create_test_allocations();
799
800 let unknown = analyzer.identify_unknown_allocations(&allocations);
801
802 assert!(!unknown.is_empty());
805 assert!(unknown.len() <= allocations.len());
806 }
807
808 #[test]
809 fn test_is_unknown_allocation_logic() {
810 let analyzer = UnknownMemoryAnalyzer::new();
811
812 let mmap_alloc = create_test_allocation(0x7f0000000000, 8192, 1000, None, None);
814 let small_alloc =
815 create_test_allocation(0x7fff00000100, 512, 2000, Some("Test".to_string()), None);
816
817 assert!(analyzer.is_unknown_allocation(&mmap_alloc));
819 assert!(analyzer.is_unknown_allocation(&small_alloc));
820 }
821
822 #[test]
823 fn test_categorize_unknown_regions() {
824 let analyzer = UnknownMemoryAnalyzer::new();
825 let allocations = create_test_allocations();
826 let unknown_refs: Vec<&AllocationInfo> = allocations.iter().collect();
827
828 let categories = analyzer.categorize_unknown_regions(&unknown_refs);
829
830 assert!(!categories.is_empty());
832
833 for category in &categories {
835 assert!(category.estimated_size > 0);
836 assert!(category.confidence_level >= 0.0 && category.confidence_level <= 1.0);
837 assert!(!category.description.is_empty());
838 assert!(!category.examples.is_empty());
839 }
840 }
841
842 #[test]
843 fn test_identify_potential_causes() {
844 let analyzer = UnknownMemoryAnalyzer::new();
845 let allocations = create_test_allocations();
846 let unknown_refs: Vec<&AllocationInfo> = allocations.iter().collect();
847
848 let causes = analyzer.identify_potential_causes(&unknown_refs);
849
850 assert!(!causes.is_empty());
852
853 let has_ffi_cause = causes
855 .iter()
856 .any(|cause| matches!(cause, UnknownMemoryCause::ForeignFunctionInterface { .. }));
857 let has_instrumentation_gap = causes
858 .iter()
859 .any(|cause| matches!(cause, UnknownMemoryCause::InstrumentationGaps { .. }));
860
861 assert!(has_ffi_cause || has_instrumentation_gap);
862 }
863
864 #[test]
865 fn test_generate_reduction_strategies() {
866 let analyzer = UnknownMemoryAnalyzer::new();
867 let categories = vec![]; let strategies = analyzer.generate_reduction_strategies(&categories);
870
871 assert!(!strategies.is_empty());
873
874 for strategy in &strategies {
876 assert!(!strategy.description.is_empty());
877 assert!(!strategy.implementation_steps.is_empty());
878 assert!(strategy.expected_improvement >= 0.0);
879 assert!(strategy.expected_improvement <= 100.0);
880 }
881
882 let has_enhanced_instrumentation = strategies.iter().any(|s| {
884 matches!(
885 s.strategy_type,
886 ReductionStrategyType::EnhancedInstrumentation
887 )
888 });
889 let has_ffi_interception = strategies
890 .iter()
891 .any(|s| matches!(s.strategy_type, ReductionStrategyType::FfiCallInterception));
892
893 assert!(has_enhanced_instrumentation);
894 assert!(has_ffi_interception);
895 }
896
897 #[test]
898 fn test_memory_pattern_detection() {
899 let analyzer = UnknownMemoryAnalyzer::new();
900
901 let mmap_alloc = create_test_allocation(0x7f0000000000, 8192, 1000, None, None);
903 assert!(analyzer.is_likely_mmap_allocation(&mmap_alloc));
904
905 let small_alloc =
907 create_test_allocation(0x7fff00000100, 512, 2000, Some("Test".to_string()), None);
908 assert!(!analyzer.is_likely_mmap_allocation(&small_alloc));
909
910 let ffi_alloc = create_test_allocation(0x600000000000, 1024, 4000, None, None);
912 assert!(analyzer.is_likely_ffi_allocation(&ffi_alloc));
913
914 let typed_alloc = create_test_allocation(
916 0x600000000000,
917 1024,
918 4000,
919 Some("Type".to_string()),
920 Some("var".to_string()),
921 );
922 assert!(!analyzer.is_likely_ffi_allocation(&typed_alloc));
923 }
924
925 #[test]
926 fn test_system_allocation_detection() {
927 let analyzer = UnknownMemoryAnalyzer::new();
928
929 let high_addr_alloc = create_test_allocation(0x7fff_ffff_0000, 256, 5000, None, None);
931 assert!(analyzer.is_likely_system_allocation(&high_addr_alloc));
932
933 let low_addr_alloc = create_test_allocation(0x500, 256, 5000, None, None);
935 assert!(analyzer.is_likely_system_allocation(&low_addr_alloc));
936
937 let normal_alloc = create_test_allocation(0x5555_5555_0000, 256, 5000, None, None);
939 assert!(!analyzer.is_likely_system_allocation(&normal_alloc));
940 }
941
942 #[test]
943 fn test_pre_tracking_allocation_detection() {
944 let analyzer = UnknownMemoryAnalyzer::new();
945
946 let early_alloc =
948 create_test_allocation(0x4000_0000_0000, 2048, 100, Some("Early".to_string()), None);
949 assert!(analyzer.is_likely_pre_tracking_allocation(&early_alloc));
950
951 let normal_alloc = create_test_allocation(
953 0x4000_0000_0000,
954 2048,
955 5000,
956 Some("Normal".to_string()),
957 None,
958 );
959 assert!(!analyzer.is_likely_pre_tracking_allocation(&normal_alloc));
960 }
961
962 #[test]
963 fn test_library_mapping_info() {
964 let lib_info = LibraryMappingInfo {
965 start_address: 0x7f80_0000_0000,
966 end_address: 0x7f80_0001_0000,
967 permissions: "r-x".to_string(),
968 file_path: "/lib/x86_64-linux-gnu/libc.so.6".to_string(),
969 };
970
971 assert!(lib_info.contains_address(0x7f80_0000_5000));
973 assert!(!lib_info.contains_address(0x7f80_0001_5000));
974 assert!(!lib_info.contains_address(0x7f70_0000_0000));
975 }
976
977 #[test]
978 fn test_unknown_memory_example_creation() {
979 let analyzer = UnknownMemoryAnalyzer::new();
980 let allocations = vec![
981 create_test_allocation(0x7f00_0000_0000, 8192, 1000, None, None),
982 create_test_allocation(0x7f00_0000_2000, 4096, 1100, None, None),
983 ];
984 let alloc_refs: Vec<&AllocationInfo> = allocations.iter().collect();
985
986 let examples = analyzer.generate_examples(&alloc_refs, "Test origin");
987
988 assert!(!examples.is_empty());
989 assert!(examples.len() <= 3); for example in &examples {
992 assert!(example.size > 0);
993 assert!(example.address_range.1 > example.address_range.0);
994 assert_eq!(example.suspected_origin, "Test origin");
995 }
996 }
997
998 #[test]
999 fn test_unknown_region_types_serialization() {
1000 let region_types = vec![
1002 UnknownRegionType::MemoryMappedRegions,
1003 UnknownRegionType::ThreadLocalStorage,
1004 UnknownRegionType::DynamicLibraryRegions,
1005 UnknownRegionType::SystemReservedRegions,
1006 UnknownRegionType::JitCodeRegions,
1007 UnknownRegionType::ExternalLibraryAllocations,
1008 UnknownRegionType::GuardPages,
1009 UnknownRegionType::VdsoRegions,
1010 UnknownRegionType::AnonymousMappings,
1011 UnknownRegionType::SharedMemorySegments,
1012 UnknownRegionType::PreTrackingAllocations,
1013 UnknownRegionType::CorruptedMetadata,
1014 ];
1015
1016 for region_type in region_types {
1017 let serialized = serde_json::to_string(®ion_type).expect("Failed to serialize");
1018 let _deserialized: UnknownRegionType =
1019 serde_json::from_str(&serialized).expect("Failed to deserialize");
1020 }
1021 }
1022
1023 #[test]
1024 fn test_memory_access_pattern_serialization() {
1025 let patterns = vec![
1026 MemoryAccessPattern::Sequential,
1027 MemoryAccessPattern::Random,
1028 MemoryAccessPattern::Sparse,
1029 MemoryAccessPattern::Unknown,
1030 ];
1031
1032 for pattern in patterns {
1033 let serialized = serde_json::to_string(&pattern).expect("Failed to serialize");
1034 let _deserialized: MemoryAccessPattern =
1035 serde_json::from_str(&serialized).expect("Failed to deserialize");
1036 }
1037 }
1038
1039 #[test]
1040 fn test_reduction_strategy_difficulty_levels() {
1041 let analyzer = UnknownMemoryAnalyzer::new();
1042 let strategies = analyzer.generate_reduction_strategies(&[]);
1043
1044 for strategy in &strategies {
1046 match strategy.strategy_type {
1047 ReductionStrategyType::EnhancedInstrumentation => {
1048 assert_eq!(
1049 strategy.implementation_difficulty,
1050 ImplementationDifficulty::Hard
1051 );
1052 }
1053 ReductionStrategyType::FfiCallInterception
1054 | ReductionStrategyType::MemoryMappingTracking => {
1055 assert_eq!(
1056 strategy.implementation_difficulty,
1057 ImplementationDifficulty::Medium
1058 );
1059 }
1060 _ => {
1061 }
1063 }
1064 }
1065 }
1066
1067 #[test]
1068 fn test_comprehensive_analysis_workflow() {
1069 let mut analyzer = UnknownMemoryAnalyzer::new();
1070 let allocations = create_test_allocations();
1071
1072 let analysis = analyzer.analyze_unknown_regions(&allocations);
1074
1075 assert!(analysis.total_unknown_bytes > 0);
1077 assert!(analysis.unknown_percentage > 0.0);
1078 assert!(!analysis.unknown_categories.is_empty());
1079 assert!(!analysis.potential_causes.is_empty());
1080 assert!(!analysis.reduction_strategies.is_empty());
1081
1082 for category in &analysis.unknown_categories {
1085 assert!(category.estimated_size > 0);
1086 assert!(category.confidence_level >= 0.0);
1087 assert!(category.confidence_level <= 1.0);
1088 assert!(!category.examples.is_empty());
1089 assert!(!category.description.is_empty());
1090 }
1091
1092 for cause in &analysis.potential_causes {
1094 match cause {
1095 UnknownMemoryCause::ForeignFunctionInterface { library_name, .. } => {
1096 assert!(!library_name.is_empty());
1097 }
1098 UnknownMemoryCause::InstrumentationGaps { description, .. } => {
1099 assert!(!description.is_empty());
1100 }
1101 _ => {
1102 }
1104 }
1105 }
1106
1107 for strategy in &analysis.reduction_strategies {
1109 assert!(!strategy.description.is_empty());
1110 assert!(!strategy.implementation_steps.is_empty());
1111 assert!(strategy.expected_improvement >= 0.0);
1112 assert!(strategy.expected_improvement <= 100.0);
1113 }
1114 }
1115}