memscope_rs/analysis/detectors/
mod.rs1pub mod types;
43
44pub mod data_race_detector;
46pub mod double_free_detector;
47pub mod leak_detector;
48pub mod lifecycle_detector;
49pub mod overflow_detector;
50pub mod safety_detector;
51pub mod uaf_detector;
52
53pub use types::{
55 DetectionResult, DetectionStatistics, DetectorConfig, DetectorError, Issue, IssueCategory,
56 IssueSeverity, Location,
57};
58
59pub use data_race_detector::{DataRaceConfig, DataRaceDetector, DataRaceDetectorWithEvents};
61pub use double_free_detector::{
62 DoubleFreeConfig, DoubleFreeDetector, DoubleFreeDetectorWithEvents,
63};
64pub use leak_detector::{LeakDetector, LeakDetectorConfig};
65pub use lifecycle_detector::{LifecycleDetector, LifecycleDetectorConfig};
66pub use overflow_detector::{OverflowDetector, OverflowDetectorConfig};
67pub use safety_detector::{SafetyDetector, SafetyDetectorConfig};
68pub use uaf_detector::{UafDetector, UafDetectorConfig};
69
70use crate::capture::types::AllocationInfo;
71use std::fmt;
72
73pub trait Detector: Send + Sync + std::fmt::Debug {
125 fn name(&self) -> &str;
129
130 fn version(&self) -> &str;
134
135 fn detect(&self, allocations: &[AllocationInfo]) -> DetectionResult;
160
161 fn config(&self) -> &DetectorConfig;
165
166 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError>;
193}
194
195#[derive(Debug, Default)]
199pub struct DetectorRegistry {
200 detectors: Vec<Box<dyn Detector>>,
201}
202
203impl DetectorRegistry {
204 pub fn new() -> Self {
206 Self::default()
207 }
208
209 pub fn register(&mut self, detector: Box<dyn Detector>) {
225 self.detectors.push(detector);
226 }
227
228 pub fn unregister(&mut self, name: &str) -> bool {
238 let initial_len = self.detectors.len();
239 self.detectors.retain(|d| d.name() != name);
240 self.detectors.len() < initial_len
241 }
242
243 pub fn get_detector(&self, name: &str) -> Option<&dyn Detector> {
253 self.detectors
254 .iter()
255 .find(|d| d.name() == name)
256 .map(|d| d.as_ref())
257 }
258
259 pub fn run_all(&self, allocations: &[AllocationInfo]) -> Vec<DetectionResult> {
282 self.detectors
283 .iter()
284 .map(|detector| detector.detect(allocations))
285 .collect()
286 }
287
288 pub fn run_detector(
299 &self,
300 name: &str,
301 allocations: &[AllocationInfo],
302 ) -> Option<DetectionResult> {
303 self.get_detector(name)
304 .map(|detector| detector.detect(allocations))
305 }
306
307 pub fn detector_names(&self) -> Vec<&str> {
313 self.detectors.iter().map(|d| d.name()).collect()
314 }
315
316 pub fn len(&self) -> usize {
322 self.detectors.len()
323 }
324
325 pub fn is_empty(&self) -> bool {
331 self.detectors.is_empty()
332 }
333}
334
335impl fmt::Display for DetectorRegistry {
336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337 write!(
338 f,
339 "DetectorRegistry({} detectors: {})",
340 self.len(),
341 self.detector_names().join(", ")
342 )
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349 use crate::capture::types::AllocationInfo;
350
351 #[test]
352 fn test_detector_registry_new() {
353 let registry = DetectorRegistry::new();
354 assert!(registry.is_empty());
355 assert_eq!(registry.len(), 0);
356 }
357
358 #[test]
359 fn test_detector_registry_register() {
360 let mut registry = DetectorRegistry::new();
361 assert_eq!(registry.len(), 0);
362
363 #[derive(Debug)]
365 struct TestDetector {
366 config: DetectorConfig,
367 }
368
369 impl Detector for TestDetector {
370 fn name(&self) -> &str {
371 "TestDetector"
372 }
373
374 fn version(&self) -> &str {
375 "1.0.0"
376 }
377
378 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
379 DetectionResult {
380 detector_name: self.name().to_string(),
381 issues: vec![],
382 statistics: DetectionStatistics::default(),
383 detection_time_ms: 0,
384 }
385 }
386
387 fn config(&self) -> &DetectorConfig {
388 &self.config
389 }
390
391 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
392 self.config = config;
393 Ok(())
394 }
395 }
396
397 registry.register(Box::new(TestDetector {
398 config: DetectorConfig::default(),
399 }));
400 assert_eq!(registry.len(), 1);
401 }
402
403 #[test]
404 fn test_detector_registry_unregister() {
405 let mut registry = DetectorRegistry::new();
406
407 #[derive(Debug)]
408 struct TestDetector {
409 config: DetectorConfig,
410 }
411
412 impl Detector for TestDetector {
413 fn name(&self) -> &str {
414 "TestDetector"
415 }
416
417 fn version(&self) -> &str {
418 "1.0.0"
419 }
420
421 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
422 DetectionResult {
423 detector_name: self.name().to_string(),
424 issues: vec![],
425 statistics: DetectionStatistics::default(),
426 detection_time_ms: 0,
427 }
428 }
429
430 fn config(&self) -> &DetectorConfig {
431 &self.config
432 }
433
434 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
435 self.config = config;
436 Ok(())
437 }
438 }
439
440 registry.register(Box::new(TestDetector {
441 config: DetectorConfig::default(),
442 }));
443 assert_eq!(registry.len(), 1);
444
445 let removed = registry.unregister("TestDetector");
446 assert!(removed);
447 assert_eq!(registry.len(), 0);
448
449 let not_removed = registry.unregister("NonExistent");
450 assert!(!not_removed);
451 }
452
453 #[test]
454 fn test_detector_registry_get_detector() {
455 let mut registry = DetectorRegistry::new();
456
457 #[derive(Debug)]
458 struct TestDetector {
459 config: DetectorConfig,
460 }
461
462 impl Detector for TestDetector {
463 fn name(&self) -> &str {
464 "TestDetector"
465 }
466
467 fn version(&self) -> &str {
468 "1.0.0"
469 }
470
471 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
472 DetectionResult {
473 detector_name: self.name().to_string(),
474 issues: vec![],
475 statistics: DetectionStatistics::default(),
476 detection_time_ms: 0,
477 }
478 }
479
480 fn config(&self) -> &DetectorConfig {
481 &self.config
482 }
483
484 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
485 self.config = config;
486 Ok(())
487 }
488 }
489
490 registry.register(Box::new(TestDetector {
491 config: DetectorConfig::default(),
492 }));
493
494 let detector = registry.get_detector("TestDetector");
495 assert!(detector.is_some());
496 assert_eq!(detector.unwrap().name(), "TestDetector");
497
498 let not_found = registry.get_detector("NonExistent");
499 assert!(not_found.is_none());
500 }
501
502 #[test]
503 fn test_detector_registry_run_all() {
504 let mut registry = DetectorRegistry::new();
505
506 #[derive(Debug)]
507 struct TestDetector {
508 config: DetectorConfig,
509 }
510
511 impl Detector for TestDetector {
512 fn name(&self) -> &str {
513 "TestDetector"
514 }
515
516 fn version(&self) -> &str {
517 "1.0.0"
518 }
519
520 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
521 DetectionResult {
522 detector_name: self.name().to_string(),
523 issues: vec![],
524 statistics: DetectionStatistics::default(),
525 detection_time_ms: 0,
526 }
527 }
528
529 fn config(&self) -> &DetectorConfig {
530 &self.config
531 }
532
533 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
534 self.config = config;
535 Ok(())
536 }
537 }
538
539 registry.register(Box::new(TestDetector {
540 config: DetectorConfig::default(),
541 }));
542 let allocations = vec![
543 AllocationInfo::new(0x1000, 1024),
544 AllocationInfo::new(0x2000, 2048),
545 ];
546
547 let results = registry.run_all(&allocations);
548 assert_eq!(results.len(), 1);
549 assert_eq!(results[0].detector_name, "TestDetector");
550 }
551
552 #[test]
553 fn test_detector_registry_run_detector() {
554 let mut registry = DetectorRegistry::new();
555
556 #[derive(Debug)]
557 struct TestDetector {
558 config: DetectorConfig,
559 }
560
561 impl Detector for TestDetector {
562 fn name(&self) -> &str {
563 "TestDetector"
564 }
565
566 fn version(&self) -> &str {
567 "1.0.0"
568 }
569
570 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
571 DetectionResult {
572 detector_name: self.name().to_string(),
573 issues: vec![],
574 statistics: DetectionStatistics::default(),
575 detection_time_ms: 0,
576 }
577 }
578
579 fn config(&self) -> &DetectorConfig {
580 &self.config
581 }
582
583 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
584 self.config = config;
585 Ok(())
586 }
587 }
588
589 registry.register(Box::new(TestDetector {
590 config: DetectorConfig::default(),
591 }));
592
593 let allocations = vec![AllocationInfo::new(0x1000, 1024)];
594
595 let result = registry.run_detector("TestDetector", &allocations);
596 assert!(result.is_some());
597 assert_eq!(result.unwrap().detector_name, "TestDetector");
598
599 let not_found = registry.run_detector("NonExistent", &allocations);
600 assert!(not_found.is_none());
601 }
602
603 #[test]
604 fn test_detector_registry_detector_names() {
605 let mut registry = DetectorRegistry::new();
606
607 #[derive(Debug)]
608 struct TestDetector1 {
609 config: DetectorConfig,
610 }
611
612 impl Detector for TestDetector1 {
613 fn name(&self) -> &str {
614 "TestDetector1"
615 }
616
617 fn version(&self) -> &str {
618 "1.0.0"
619 }
620
621 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
622 DetectionResult {
623 detector_name: self.name().to_string(),
624 issues: vec![],
625 statistics: DetectionStatistics::default(),
626 detection_time_ms: 0,
627 }
628 }
629
630 fn config(&self) -> &DetectorConfig {
631 &self.config
632 }
633
634 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
635 self.config = config;
636 Ok(())
637 }
638 }
639
640 #[derive(Debug)]
641 struct TestDetector2 {
642 config: DetectorConfig,
643 }
644
645 impl Detector for TestDetector2 {
646 fn name(&self) -> &str {
647 "TestDetector2"
648 }
649
650 fn version(&self) -> &str {
651 "1.0.0"
652 }
653
654 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
655 DetectionResult {
656 detector_name: self.name().to_string(),
657 issues: vec![],
658 statistics: DetectionStatistics::default(),
659 detection_time_ms: 0,
660 }
661 }
662
663 fn config(&self) -> &DetectorConfig {
664 &self.config
665 }
666
667 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
668 self.config = config;
669 Ok(())
670 }
671 }
672
673 registry.register(Box::new(TestDetector1 {
674 config: DetectorConfig::default(),
675 }));
676 registry.register(Box::new(TestDetector2 {
677 config: DetectorConfig::default(),
678 }));
679
680 let names = registry.detector_names();
681 assert_eq!(names.len(), 2);
682 assert!(names.contains(&"TestDetector1"));
683 assert!(names.contains(&"TestDetector2"));
684 }
685
686 #[test]
687 fn test_detector_registry_display() {
688 let registry = DetectorRegistry::new();
689 let display = format!("{}", registry);
690 assert!(display.contains("DetectorRegistry"));
691 assert!(display.contains("0 detectors"));
692
693 let mut registry = DetectorRegistry::new();
694
695 #[derive(Debug)]
696 struct TestDetector {
697 config: DetectorConfig,
698 }
699
700 impl Detector for TestDetector {
701 fn name(&self) -> &str {
702 "TestDetector"
703 }
704
705 fn version(&self) -> &str {
706 "1.0.0"
707 }
708
709 fn detect(&self, _allocations: &[AllocationInfo]) -> DetectionResult {
710 DetectionResult {
711 detector_name: self.name().to_string(),
712 issues: vec![],
713 statistics: DetectionStatistics::default(),
714 detection_time_ms: 0,
715 }
716 }
717
718 fn config(&self) -> &DetectorConfig {
719 &self.config
720 }
721
722 fn update_config(&mut self, config: DetectorConfig) -> Result<(), DetectorError> {
723 self.config = config;
724 Ok(())
725 }
726 }
727
728 registry.register(Box::new(TestDetector {
729 config: DetectorConfig::default(),
730 }));
731
732 let display = format!("{}", registry);
733 assert!(display.contains("DetectorRegistry"));
734 assert!(display.contains("1 detectors"));
735 assert!(display.contains("TestDetector"));
736 }
737}