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 |
11 when the pattern matches a JS test case. | 11 when the pattern matches a JS test case. |
12 Subsequent matches will be recoreded under the first failure. | 12 Subsequent matches will be recoreded under the first failure. |
13 | 13 |
14 2. Ignore test run by output pattern: | 14 2. Ignore test run by output pattern: |
15 Map a regular expression to a bug entry. A new failure will be reported | 15 Map a regular expression to a bug entry. A new failure will be reported |
16 when the pattern matches the output of a particular run. | 16 when the pattern matches the output of a particular run. |
17 Subsequent matches will be recoreded under the first failure. | 17 Subsequent matches will be recoreded under the first failure. |
18 | 18 |
19 3. Relax line-to-line comparisons with expressions of lines to ignore and | 19 3. Relax line-to-line comparisons with expressions of lines to ignore and |
20 lines to be normalized (i.e. ignore only portions of lines). | 20 lines to be normalized (i.e. ignore only portions of lines). |
21 These are not tied to bugs, be careful to not silently switch off this tool! | 21 These are not tied to bugs, be careful to not silently switch off this tool! |
22 | 22 |
23 Alternatively, think about adding a behavior change to v8_suppressions.js | 23 Alternatively, think about adding a behavior change to v8_suppressions.js |
24 to silence a particular class of problems. | 24 to silence a particular class of problems. |
25 """ | 25 """ |
26 | 26 |
27 import hashlib | |
27 import itertools | 28 import itertools |
28 import re | 29 import re |
29 | 30 |
30 # Max line length for regular experessions checking for lines to ignore. | 31 # Max line length for regular experessions checking for lines to ignore. |
31 MAX_LINE_LENGTH = 512 | 32 MAX_LINE_LENGTH = 512 |
32 | 33 |
33 # For ignoring lines before carets and to ignore caret positions. | 34 # For ignoring lines before carets and to ignore caret positions. |
34 CARET_RE = re.compile(r'^\s*\^\s*$') | 35 CARET_RE = re.compile(r'^\s*\^\s*$') |
35 | 36 |
36 # Ignore by original source files. Map from bug->relative file paths in V8, | 37 # Ignore by original source files. Map from bug->relative file paths in V8, |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
141 ] | 142 ] |
142 | 143 |
143 | 144 |
144 ############################################################################### | 145 ############################################################################### |
145 # Implementation - you should not need to change anything below this point. | 146 # Implementation - you should not need to change anything below this point. |
146 | 147 |
147 # Compile regular expressions. | 148 # Compile regular expressions. |
148 ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS] | 149 ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS] |
149 IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES] | 150 IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES] |
150 | 151 |
152 # The number of hex digits used from the hash of the original source file path. | |
153 # Keep the number small to avoid duplicate explosion. | |
154 SOURCE_HASH_LENGTH = 3 | |
155 | |
151 ORIGINAL_SOURCE_PREFIX = 'v8-foozzie source: ' | 156 ORIGINAL_SOURCE_PREFIX = 'v8-foozzie source: ' |
152 | 157 |
153 def line_pairs(lines): | 158 def line_pairs(lines): |
154 return itertools.izip_longest( | 159 return itertools.izip_longest( |
155 lines, itertools.islice(lines, 1, None), fillvalue=None) | 160 lines, itertools.islice(lines, 1, None), fillvalue=None) |
156 | 161 |
157 | 162 |
158 def caret_match(line1, line2): | 163 def caret_match(line1, line2): |
159 if (not line1 or | 164 if (not line1 or |
160 not line2 or | 165 not line2 or |
(...skipping 18 matching lines...) Expand all Loading... | |
179 match2 = exp.match(line2) | 184 match2 = exp.match(line2) |
180 if match1 and match2: | 185 if match1 and match2: |
181 # If there are groups in the regexp, ensure the groups matched the same | 186 # If there are groups in the regexp, ensure the groups matched the same |
182 # things. | 187 # things. |
183 if match1.groups() == match2.groups(): # tuple comparison | 188 if match1.groups() == match2.groups(): # tuple comparison |
184 return True | 189 return True |
185 return False | 190 return False |
186 | 191 |
187 | 192 |
188 def diff_output(output1, output2, allowed, ignore1, ignore2): | 193 def diff_output(output1, output2, allowed, ignore1, ignore2): |
189 """Returns a tuple (difference, source). | 194 """Returns a tuple (difference, source_key). |
190 | 195 |
191 The difference is None if there's no difference, otherwise a string | 196 The difference is None if there's no difference, otherwise a string |
192 with a readable diff. | 197 with a readable diff. |
193 | 198 |
194 The source is a string with the last source output within the test case. | 199 The source_key is a short hash of the last source output within the test |
195 It is the string 'none' if no such output existed. | 200 case. It is the string 'none' if no such output existed. |
196 """ | 201 """ |
197 def useful_line(ignore): | 202 def useful_line(ignore): |
198 def fun(line): | 203 def fun(line): |
199 return all(not e.match(line) for e in ignore) | 204 return all(not e.match(line) for e in ignore) |
200 return fun | 205 return fun |
201 | 206 |
202 lines1 = filter(useful_line(ignore1), output1) | 207 lines1 = filter(useful_line(ignore1), output1) |
203 lines2 = filter(useful_line(ignore2), output2) | 208 lines2 = filter(useful_line(ignore2), output2) |
204 | 209 |
205 # This keeps track where we are in the original source file of the fuzz | 210 # This keeps track where we are in the original source file of the fuzz |
206 # test case. | 211 # test case. |
207 source = 'none' | 212 source_key = 'none' |
208 | 213 |
209 for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest( | 214 for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest( |
210 line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)): | 215 line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)): |
211 | 216 |
212 # Only one of the two iterators should run out. | 217 # Only one of the two iterators should run out. |
213 assert not (line1 is None and line2 is None) | 218 assert not (line1 is None and line2 is None) |
214 | 219 |
215 # One iterator ends earlier. | 220 # One iterator ends earlier. |
216 if line1 is None: | 221 if line1 is None: |
217 return '+ %s' % short_line_output(line2), source | 222 return '+ %s' % short_line_output(line2), source_key |
218 if line2 is None: | 223 if line2 is None: |
219 return '- %s' % short_line_output(line1), source | 224 return '- %s' % short_line_output(line1), source_key |
220 | 225 |
221 # If lines are equal, no further checks are necessary. | 226 # If lines are equal, no further checks are necessary. |
222 if line1 == line2: | 227 if line1 == line2: |
223 # Instrumented original-source-file output must be equal in both | 228 # Instrumented original-source-file output must be equal in both |
224 # versions. It only makes sense to update it here when both lines | 229 # versions. It only makes sense to update it here when both lines |
225 # are equal. | 230 # are equal. |
226 if line1.startswith(ORIGINAL_SOURCE_PREFIX): | 231 if line1.startswith(ORIGINAL_SOURCE_PREFIX): |
227 source = line1[len(ORIGINAL_SOURCE_PREFIX):] | 232 source = line1[len(ORIGINAL_SOURCE_PREFIX):] |
233 source_key = hashlib.sha1(source).hexdigest()[:SOURCE_HASH_LENGTH] | |
Michael Achenbach
2017/01/13 08:13:40
Maybe not ideal that this is in this file. The has
| |
228 continue | 234 continue |
229 | 235 |
230 # Look ahead. If next line is a caret, ignore this line. | 236 # Look ahead. If next line is a caret, ignore this line. |
231 if caret_match(lookahead1, lookahead2): | 237 if caret_match(lookahead1, lookahead2): |
232 continue | 238 continue |
233 | 239 |
234 # Check if a regexp allows these lines to be different. | 240 # Check if a regexp allows these lines to be different. |
235 if ignore_by_regexp(line1, line2, allowed): | 241 if ignore_by_regexp(line1, line2, allowed): |
236 continue | 242 continue |
237 | 243 |
238 # Lines are different. | 244 # Lines are different. |
239 return ( | 245 return ( |
240 '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2)), | 246 '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2)), |
241 source, | 247 source_key, |
242 ) | 248 ) |
243 | 249 |
244 # No difference found. | 250 # No difference found. |
245 return None, source | 251 return None, source_key |
246 | 252 |
247 | 253 |
248 def get_suppression(arch1, config1, arch2, config2): | 254 def get_suppression(arch1, config1, arch2, config2): |
249 return V8Suppression(arch1, config1, arch2, config2) | 255 return V8Suppression(arch1, config1, arch2, config2) |
250 | 256 |
251 | 257 |
252 class Suppression(object): | 258 class Suppression(object): |
253 def diff(self, output1, output2): | 259 def diff(self, output1, output2): |
254 return None | 260 return None |
255 | 261 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
312 bug = check(IGNORE_OUTPUT.get(arch, {})) | 318 bug = check(IGNORE_OUTPUT.get(arch, {})) |
313 if bug: | 319 if bug: |
314 return bug | 320 return bug |
315 bug = check(IGNORE_OUTPUT.get(config, {})) | 321 bug = check(IGNORE_OUTPUT.get(config, {})) |
316 if bug: | 322 if bug: |
317 return bug | 323 return bug |
318 bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {})) | 324 bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {})) |
319 if bug: | 325 if bug: |
320 return bug | 326 return bug |
321 return None | 327 return None |
OLD | NEW |