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)\s*\(([^()]*)\)", r"$1 (1==1)"),
53 (r"\b(if|else\s+if|while)\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 "*",
144 "assert",
145 "self.log",
146 "Assume",
147 "CHECK_NONFATAL",
148 "/*",
149 "LogPrintf",
150 "LogPrint",
151 "strprintf",
152 "G_FUZZING",
153 ]
154}
155
156pub fn get_do_not_mutate_py_patterns() -> Vec<&'static str> {
157 vec![
158 "wait_for",
159 "wait_until",
160 "check_",
161 "for",
162 "expected_error",
163 "def",
164 "send_and_ping",
165 "test_",
166 "rehash",
167 "start_",
168 "solve()",
169 "restart_",
170 "stop_",
171 "connect_",
172 "sync_",
173 "class",
174 "return",
175 "generate(",
176 "continue",
177 "sleep",
178 "break",
179 "getcontext().prec",
180 "if",
181 "else",
182 "assert",
183 ]
184}
185
186pub fn get_do_not_mutate_unit_patterns() -> Vec<&'static str> {
187 vec![
188 "while",
189 "for",
190 "if",
191 "test_",
192 "_test",
193 "reset",
194 "class",
195 "return",
196 "continue",
197 "break",
198 "else",
199 "reserve",
200 "resize",
201 "static",
202 "void",
203 "BOOST_",
204 "LOCK(",
205 "LOCK2(",
206 "Test",
207 "Assert",
208 "EXCLUSIVE_LOCKS_REQUIRED",
209 "catch",
210 ]
211}
212
213pub fn get_skip_if_contain_patterns() -> Vec<&'static str> {
214 vec!["EnableFuzzDeterminism", "nLostUnk", "RPCArg::Type::"]
215}
216
217pub fn should_mutate_test_line(line: &str) -> bool {
220 let line_trimmed = line.trim();
221
222 let skip_patterns = vec![
224 "assert",
225 "BOOST_",
226 "EXPECT_",
227 "ASSERT_",
228 "CHECK_",
229 "REQUIRE_",
230 "wait_for",
231 "wait_until",
232 "send_and_ping",
233 ];
234
235 for pattern in skip_patterns {
236 if line_trimmed.starts_with(pattern) {
237 return false;
238 }
239 }
240
241 let function_call_pattern =
243 Regex::new(r"^\s*(?:\w+(?:\.|->|::))*(\w+)\s*\([^)]*\)\s*;?\s*$").unwrap();
244 function_call_pattern.is_match(line)
245}