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