Skip to main content

panic_attacker/signatures/
rules.rs

1// SPDX-License-Identifier: PMPL-1.0-or-later
2
3//! Datalog-style rule definitions for bug detection
4//!
5//! This module defines the logical rules used for pattern matching,
6//! inspired by Datalog and Mozart/Oz constraint logic programming.
7
8use crate::types::*;
9
10pub struct RuleSet {
11    rules: Vec<Rule>,
12}
13
14impl RuleSet {
15    pub fn new() -> Self {
16        Self {
17            rules: Self::build_rules(),
18        }
19    }
20
21    /// Build the complete rule set for bug detection
22    fn build_rules() -> Vec<Rule> {
23        vec![
24            // Use-after-free detection
25            Rule {
26                name: "use_after_free".to_string(),
27                head: Predicate::UseAfterFree {
28                    var: "X".to_string(),
29                    use_loc: 0,
30                    free_loc: 0,
31                },
32                body: vec![
33                    Predicate::Fact(Fact::Free {
34                        var: "X".to_string(),
35                        location: 0,
36                    }),
37                    Predicate::Fact(Fact::Use {
38                        var: "X".to_string(),
39                        location: 0,
40                    }),
41                ],
42            },
43            // Double-free detection
44            Rule {
45                name: "double_free".to_string(),
46                head: Predicate::DoubleFree {
47                    var: "X".to_string(),
48                    loc1: 0,
49                    loc2: 0,
50                },
51                body: vec![
52                    Predicate::Fact(Fact::Free {
53                        var: "X".to_string(),
54                        location: 0,
55                    }),
56                    Predicate::Fact(Fact::Free {
57                        var: "X".to_string(),
58                        location: 0,
59                    }),
60                ],
61            },
62            // Deadlock detection (simplified)
63            Rule {
64                name: "deadlock".to_string(),
65                head: Predicate::Deadlock {
66                    m1: "M1".to_string(),
67                    m2: "M2".to_string(),
68                },
69                body: vec![
70                    Predicate::Fact(Fact::Lock {
71                        mutex: "M1".to_string(),
72                        location: 0,
73                    }),
74                    Predicate::Fact(Fact::Lock {
75                        mutex: "M2".to_string(),
76                        location: 0,
77                    }),
78                ],
79            },
80            // Data race detection
81            Rule {
82                name: "data_race".to_string(),
83                head: Predicate::DataRace {
84                    var: "X".to_string(),
85                    loc1: 0,
86                    loc2: 0,
87                },
88                body: vec![
89                    Predicate::Fact(Fact::Write {
90                        var: "X".to_string(),
91                        location: 0,
92                    }),
93                    Predicate::Fact(Fact::Read {
94                        var: "X".to_string(),
95                        location: 0,
96                    }),
97                ],
98            },
99        ]
100    }
101
102    pub fn rules(&self) -> &[Rule] {
103        &self.rules
104    }
105}
106
107impl Default for RuleSet {
108    fn default() -> Self {
109        Self::new()
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_ruleset_creation() {
119        let ruleset = RuleSet::new();
120        assert!(!ruleset.rules().is_empty());
121        assert!(ruleset.rules().len() >= 4);
122    }
123
124    #[test]
125    fn test_rule_names() {
126        let ruleset = RuleSet::new();
127        let names: Vec<_> = ruleset.rules().iter().map(|r| &r.name).collect();
128
129        assert!(names.contains(&&"use_after_free".to_string()));
130        assert!(names.contains(&&"double_free".to_string()));
131        assert!(names.contains(&&"deadlock".to_string()));
132        assert!(names.contains(&&"data_race".to_string()));
133    }
134}