OLD | NEW |
1 # Copyright 2016 the V8 project authors. All rights reserved. | 1 # Copyright 2016 the V8 project authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """ | 5 """ |
6 Suppressions for V8 correctness fuzzer failures. | 6 Suppressions for V8 correctness fuzzer failures. |
7 | 7 |
8 We support three types of suppressions: | 8 We support three types of suppressions: |
9 1. Ignore test case by pattern. | 9 1. Ignore test case by pattern. |
10 Map a regular expression to a bug entry. A new failure will be reported | 10 Map a regular expression to a bug entry. A new failure will be reported |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 ] | 141 ] |
142 | 142 |
143 | 143 |
144 ############################################################################### | 144 ############################################################################### |
145 # Implementation - you should not need to change anything below this point. | 145 # Implementation - you should not need to change anything below this point. |
146 | 146 |
147 # Compile regular expressions. | 147 # Compile regular expressions. |
148 ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS] | 148 ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS] |
149 IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES] | 149 IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES] |
150 | 150 |
| 151 ORIGINAL_SOURCE_PREFIX = 'v8-foozzie source: ' |
151 | 152 |
152 def line_pairs(lines): | 153 def line_pairs(lines): |
153 return itertools.izip_longest( | 154 return itertools.izip_longest( |
154 lines, itertools.islice(lines, 1, None), fillvalue=None) | 155 lines, itertools.islice(lines, 1, None), fillvalue=None) |
155 | 156 |
156 | 157 |
157 def caret_match(line1, line2): | 158 def caret_match(line1, line2): |
158 if (not line1 or | 159 if (not line1 or |
159 not line2 or | 160 not line2 or |
160 len(line1) > MAX_LINE_LENGTH or | 161 len(line1) > MAX_LINE_LENGTH or |
(...skipping 17 matching lines...) Expand all Loading... |
178 match2 = exp.match(line2) | 179 match2 = exp.match(line2) |
179 if match1 and match2: | 180 if match1 and match2: |
180 # If there are groups in the regexp, ensure the groups matched the same | 181 # If there are groups in the regexp, ensure the groups matched the same |
181 # things. | 182 # things. |
182 if match1.groups() == match2.groups(): # tuple comparison | 183 if match1.groups() == match2.groups(): # tuple comparison |
183 return True | 184 return True |
184 return False | 185 return False |
185 | 186 |
186 | 187 |
187 def diff_output(output1, output2, allowed, ignore1, ignore2): | 188 def diff_output(output1, output2, allowed, ignore1, ignore2): |
| 189 """Returns a tuple (difference, source). |
| 190 |
| 191 The difference is None if there's no difference, otherwise a string |
| 192 with a readable diff. |
| 193 |
| 194 The source is a string with the last source output within the test case. |
| 195 It is the string 'none' if no such output existed. |
| 196 """ |
188 def useful_line(ignore): | 197 def useful_line(ignore): |
189 def fun(line): | 198 def fun(line): |
190 return all(not e.match(line) for e in ignore) | 199 return all(not e.match(line) for e in ignore) |
191 return fun | 200 return fun |
192 | 201 |
193 lines1 = filter(useful_line(ignore1), output1) | 202 lines1 = filter(useful_line(ignore1), output1) |
194 lines2 = filter(useful_line(ignore2), output2) | 203 lines2 = filter(useful_line(ignore2), output2) |
195 | 204 |
| 205 # This keeps track where we are in the original source file of the fuzz |
| 206 # test case. |
| 207 source = 'none' |
| 208 |
196 for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest( | 209 for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest( |
197 line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)): | 210 line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)): |
198 | 211 |
199 # Only one of the two iterators should run out. | 212 # Only one of the two iterators should run out. |
200 assert not (line1 is None and line2 is None) | 213 assert not (line1 is None and line2 is None) |
201 | 214 |
202 # One iterator ends earlier. | 215 # One iterator ends earlier. |
203 if line1 is None: | 216 if line1 is None: |
204 return '+ %s' % short_line_output(line2) | 217 return '+ %s' % short_line_output(line2), source |
205 if line2 is None: | 218 if line2 is None: |
206 return '- %s' % short_line_output(line1) | 219 return '- %s' % short_line_output(line1), source |
207 | 220 |
208 # If lines are equal, no further checks are necessary. | 221 # If lines are equal, no further checks are necessary. |
209 if line1 == line2: | 222 if line1 == line2: |
| 223 # Instrumented original-source-file output must be equal in both |
| 224 # versions. It only makes sense to update it here when both lines |
| 225 # are equal. |
| 226 if line1.startswith(ORIGINAL_SOURCE_PREFIX): |
| 227 source = line1[len(ORIGINAL_SOURCE_PREFIX):] |
210 continue | 228 continue |
211 | 229 |
212 # Look ahead. If next line is a caret, ignore this line. | 230 # Look ahead. If next line is a caret, ignore this line. |
213 if caret_match(lookahead1, lookahead2): | 231 if caret_match(lookahead1, lookahead2): |
214 continue | 232 continue |
215 | 233 |
216 # Check if a regexp allows these lines to be different. | 234 # Check if a regexp allows these lines to be different. |
217 if ignore_by_regexp(line1, line2, allowed): | 235 if ignore_by_regexp(line1, line2, allowed): |
218 continue | 236 continue |
219 | 237 |
220 # Lines are different. | 238 # Lines are different. |
221 return '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2)) | 239 return ( |
| 240 '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2)), |
| 241 source, |
| 242 ) |
222 | 243 |
223 # No difference found. | 244 # No difference found. |
224 return None | 245 return None, source |
225 | 246 |
226 | 247 |
227 def get_suppression(arch1, config1, arch2, config2): | 248 def get_suppression(arch1, config1, arch2, config2): |
228 return V8Suppression(arch1, config1, arch2, config2) | 249 return V8Suppression(arch1, config1, arch2, config2) |
229 | 250 |
230 | 251 |
231 class Suppression(object): | 252 class Suppression(object): |
232 def diff(self, output1, output2): | 253 def diff(self, output1, output2): |
233 return None | 254 return None |
234 | 255 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 bug = check(IGNORE_OUTPUT.get(arch, {})) | 312 bug = check(IGNORE_OUTPUT.get(arch, {})) |
292 if bug: | 313 if bug: |
293 return bug | 314 return bug |
294 bug = check(IGNORE_OUTPUT.get(config, {})) | 315 bug = check(IGNORE_OUTPUT.get(config, {})) |
295 if bug: | 316 if bug: |
296 return bug | 317 return bug |
297 bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {})) | 318 bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {})) |
298 if bug: | 319 if bug: |
299 return bug | 320 return bug |
300 return None | 321 return None |
OLD | NEW |