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