1use regex::Regex;
2#[derive(Debug, Clone)]
3pub struct MutationOperator {
4 pub pattern: Regex,
5 pub replacement: String,
6}
7
8impl MutationOperator {
9 pub fn new(pattern: &str, replacement: &str) -> Result<Self, regex::Error> {
10 Ok(MutationOperator {
11 pattern: Regex::new(pattern)?,
12 replacement: replacement.to_string(),
13 })
14 }
15}
16
17pub fn get_regex_operators() -> Result<Vec<MutationOperator>, regex::Error> {
18 let operators = vec![
19 (r"--(\b\w+\b)", r"++$1"),
20 (r"(\b\w+\b)--", r"$1++"),
21 ("continue", "break"),
24 ("break", "continue"),
25 ("std::all_of", "std::any_of"),
26 ("std::any_of", "std::all_of"),
27 ("std::min", "std::max"),
28 ("std::max", "std::min"),
29 ("std::begin", "std::end"),
30 ("std::end", "std::begin"),
31 ("true", "false"),
32 ("false", "true"),
33 (r" / ", " * "),
34 (r" > ", " < "),
35 (r" > ", " >= "),
36 (r" > ", " <= "),
37 (r" < ", " > "),
38 (r" < ", " <= "),
39 (r" < ", " >= "),
40 (r" >= ", " <= "),
41 (r" >= ", " > "),
42 (r"&&", "||"),
43 (r"\|\|", "&&"),
44 (r" == ", " != "),
45 (r" != ", " == "),
46 (" - ", " + "),
47 (r" \+ ", " - "),
48 (r" \+ ", " * "),
49 (r" \+ ", " / "),
50 (r"\((-?\d+)\)", r"($1 - 1)"),
51 (r"\((-?\d+)\)", r"($1 + 1)"),
52 (r"\b(if|else\s+if|while|for)\s*\(([^()]*)\)", r"$1 (1==1)"),
53 (r"\b(if|else\s+if|while|for)\s*\(([^()]*)\)", r"$1 (1==0)"),
54 (r".*\berase\(.+", ""),
55 (r"^.*if\s*\(.*\)\s*continue;.*$", ""),
56 (r"^.*if\s*\(.*\)\s*return;.*$", ""),
57 (r"^.*if\s*\(.*\)\s*return.*;.*$", ""),
58 (r"^(.*for\s*\(.*;.*;.*\)\s*\{.*)$", r"$1break;"),
59 (r"^(.*while\s*\(.*\)\s*\{.*)$", r"$1break;"),
60 ];
80
81 operators
82 .into_iter()
83 .map(|(pattern, replacement)| MutationOperator::new(pattern, replacement))
84 .collect()
85}
86
87pub fn get_security_operators() -> Result<Vec<MutationOperator>, regex::Error> {
88 let operators = vec![
89 ("==", "="),
90 (r" - ", " + "),
91 (r"\s\+\s", "-"),
92 (
93 r"std::array<\s*([\w:]+)\s*,\s*(\d+)\s*>",
94 r"std::array<$1, $2 - 2>",
95 ),
96 (
97 r"\b((?:int16_t|uint16_t|int32_t|uint32_t|int64_t|uint64_t|int)\s*[\(\{])([^\)\}]*)[\)\}]",
98 "$2",
99 ),
100 (r"ignore\((\s*(\d+)\s*)\)", r"ignore($2 + 100)"),
101 (r"(\w+)\[(\w+)\]", r"$1[$2 + 5]"),
102 (
103 r"^\s*(?:\(void\)\s*)?[a-zA-Z_][\w:]*\s*\([\w\s,]*\)\s*;\s*$",
104 "",
105 ),
106 (r"if\s*\(\s*(.*?)\s*\|\|\s*(.*?)\s*\)", r"if($2||$1)"),
107 (
108 r"GetSelectionAmount\(\)",
109 r"GetSelectionAmount() + std::numeric_limits<CAmount>::max() - 1",
110 ),
111 (r"resetBlock\(\);", ""),
112 (
113 r"\w+(\.|->)GetMedianTimePast\(\)",
114 "std::numeric_limits<int64_t>::max()",
115 ),
116 ("break", ""),
117 ];
118
119 operators
120 .into_iter()
121 .map(|(pattern, replacement)| MutationOperator::new(pattern, replacement))
122 .collect()
123}
124
125pub fn get_test_operators() -> Result<Vec<MutationOperator>, regex::Error> {
126 let operators = vec![
129 (r"^\s*(?:\w+(?:\.|->|::))*(\w+)\s*\([^)]*\)\s*;?\s*$", ""), ];
131
132 operators
133 .into_iter()
134 .map(|(pattern, replacement)| MutationOperator::new(pattern, replacement))
135 .collect()
136}
137
138pub fn get_do_not_mutate_patterns() -> Vec<&'static str> {
139 vec![
140 "//",
141 "#",
142 "*",
143 "assert",
144 "self.log",
145 "Assume",
146 "CHECK_NONFATAL",
147 "/*",
148 "LogPrintf",
149 "LogPrint",
150 "strprintf",
151 "G_FUZZING",
152 ]
153}
154
155pub fn get_do_not_mutate_py_patterns() -> Vec<&'static str> {
156 vec![
157 "wait_for",
158 "wait_until",
159 "check_",
160 "for",
161 "expected_error",
162 "def",
163 "send_and_ping",
164 "test_",
165 "rehash",
166 "start_",
167 "solve()",
168 "restart_",
169 "stop_",
170 "connect_",
171 "sync_",
172 "class",
173 "return",
174 "generate(",
175 "continue",
176 "sleep",
177 "break",
178 "getcontext().prec",
179 "if",
180 "else",
181 "assert",
182 ]
183}
184
185pub fn get_do_not_mutate_unit_patterns() -> Vec<&'static str> {
186 vec![
187 "while",
188 "for",
189 "if",
190 "test_",
191 "_test",
192 "reset",
193 "class",
194 "return",
195 "continue",
196 "break",
197 "else",
198 "reserve",
199 "resize",
200 "static",
201 "void",
202 "BOOST_",
203 "LOCK(",
204 "LOCK2(",
205 "Test",
206 "Assert",
207 "EXCLUSIVE_LOCKS_REQUIRED",
208 "catch",
209 ]
210}
211
212pub fn get_skip_if_contain_patterns() -> Vec<&'static str> {
213 vec!["EnableFuzzDeterminism", "nLostUnk", "RPCArg::Type::"]
214}
215
216pub fn should_mutate_test_line(line: &str) -> bool {
219 let line_trimmed = line.trim();
220
221 let skip_patterns = vec![
223 "assert",
224 "BOOST_",
225 "EXPECT_",
226 "ASSERT_",
227 "CHECK_",
228 "REQUIRE_",
229 "wait_for",
230 "wait_until",
231 "send_and_ping",
232 ];
233
234 for pattern in skip_patterns {
235 if line_trimmed.starts_with(pattern) {
236 return false;
237 }
238 }
239
240 let function_call_pattern =
242 Regex::new(r"^\s*(?:\w+(?:\.|->|::))*(\w+)\s*\([^)]*\)\s*;?\s*$").unwrap();
243 function_call_pattern.is_match(line)
244}