| 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 |