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 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 | 138 |
139 # Compile regular expressions. | 139 # Compile regular expressions. |
140 ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS] | 140 ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS] |
141 IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES] | 141 IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES] |
142 | 142 |
143 # The number of hex digits used from the hash of the original source file path. | 143 # The number of hex digits used from the hash of the original source file path. |
144 # Keep the number small to avoid duplicate explosion. | 144 # Keep the number small to avoid duplicate explosion. |
145 SOURCE_HASH_LENGTH = 3 | 145 SOURCE_HASH_LENGTH = 3 |
146 | 146 |
147 ORIGINAL_SOURCE_PREFIX = 'v8-foozzie source: ' | 147 ORIGINAL_SOURCE_PREFIX = 'v8-foozzie source: ' |
148 ORIGINAL_SOURCE_DEFAULT = 'none' | |
148 | 149 |
149 def line_pairs(lines): | 150 def line_pairs(lines): |
150 return itertools.izip_longest( | 151 return itertools.izip_longest( |
151 lines, itertools.islice(lines, 1, None), fillvalue=None) | 152 lines, itertools.islice(lines, 1, None), fillvalue=None) |
152 | 153 |
153 | 154 |
154 def caret_match(line1, line2): | 155 def caret_match(line1, line2): |
155 if (not line1 or | 156 if (not line1 or |
156 not line2 or | 157 not line2 or |
157 len(line1) > MAX_LINE_LENGTH or | 158 len(line1) > MAX_LINE_LENGTH or |
(...skipping 17 matching lines...) Expand all Loading... | |
175 match2 = exp.match(line2) | 176 match2 = exp.match(line2) |
176 if match1 and match2: | 177 if match1 and match2: |
177 # If there are groups in the regexp, ensure the groups matched the same | 178 # If there are groups in the regexp, ensure the groups matched the same |
178 # things. | 179 # things. |
179 if match1.groups() == match2.groups(): # tuple comparison | 180 if match1.groups() == match2.groups(): # tuple comparison |
180 return True | 181 return True |
181 return False | 182 return False |
182 | 183 |
183 | 184 |
184 def diff_output(output1, output2, allowed, ignore1, ignore2): | 185 def diff_output(output1, output2, allowed, ignore1, ignore2): |
185 """Returns a tuple (difference, source_key). | 186 """Returns a tuple (difference, source, source_key). |
tandrii(chromium)
2017/01/16 13:39:40
the source -> source_key is deterministic here.
ho
Michael Achenbach
2017/01/16 13:46:47
Sg, will prepare a fix.
| |
186 | 187 |
187 The difference is None if there's no difference, otherwise a string | 188 The difference is None if there's no difference, otherwise a string |
188 with a readable diff. | 189 with a readable diff. |
189 | 190 |
190 The source_key is a short hash of the last source output within the test | 191 The source is the last source output within the test case. It is the string |
191 case. It is the string 'none' if no such output existed. | 192 'none' if no such output existed. |
193 | |
194 The source_key is a short hash of source or 'none'. | |
192 """ | 195 """ |
193 def useful_line(ignore): | 196 def useful_line(ignore): |
194 def fun(line): | 197 def fun(line): |
195 return all(not e.match(line) for e in ignore) | 198 return all(not e.match(line) for e in ignore) |
196 return fun | 199 return fun |
197 | 200 |
198 lines1 = filter(useful_line(ignore1), output1) | 201 lines1 = filter(useful_line(ignore1), output1) |
199 lines2 = filter(useful_line(ignore2), output2) | 202 lines2 = filter(useful_line(ignore2), output2) |
200 | 203 |
201 # This keeps track where we are in the original source file of the fuzz | 204 # This keeps track where we are in the original source file of the fuzz |
202 # test case. | 205 # test case. |
203 source_key = 'none' | 206 source = ORIGINAL_SOURCE_DEFAULT |
207 source_key = ORIGINAL_SOURCE_DEFAULT | |
204 | 208 |
205 for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest( | 209 for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest( |
206 line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)): | 210 line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)): |
207 | 211 |
208 # Only one of the two iterators should run out. | 212 # Only one of the two iterators should run out. |
209 assert not (line1 is None and line2 is None) | 213 assert not (line1 is None and line2 is None) |
210 | 214 |
211 # One iterator ends earlier. | 215 # One iterator ends earlier. |
212 if line1 is None: | 216 if line1 is None: |
213 return '+ %s' % short_line_output(line2), source_key | 217 return '+ %s' % short_line_output(line2), source, source_key |
214 if line2 is None: | 218 if line2 is None: |
215 return '- %s' % short_line_output(line1), source_key | 219 return '- %s' % short_line_output(line1), source, source_key |
216 | 220 |
217 # If lines are equal, no further checks are necessary. | 221 # If lines are equal, no further checks are necessary. |
218 if line1 == line2: | 222 if line1 == line2: |
219 # Instrumented original-source-file output must be equal in both | 223 # Instrumented original-source-file output must be equal in both |
220 # versions. It only makes sense to update it here when both lines | 224 # versions. It only makes sense to update it here when both lines |
221 # are equal. | 225 # are equal. |
222 if line1.startswith(ORIGINAL_SOURCE_PREFIX): | 226 if line1.startswith(ORIGINAL_SOURCE_PREFIX): |
223 source = line1[len(ORIGINAL_SOURCE_PREFIX):] | 227 source = line1[len(ORIGINAL_SOURCE_PREFIX):] |
224 source_key = hashlib.sha1(source).hexdigest()[:SOURCE_HASH_LENGTH] | 228 source_key = hashlib.sha1(source).hexdigest()[:SOURCE_HASH_LENGTH] |
225 continue | 229 continue |
226 | 230 |
227 # Look ahead. If next line is a caret, ignore this line. | 231 # Look ahead. If next line is a caret, ignore this line. |
228 if caret_match(lookahead1, lookahead2): | 232 if caret_match(lookahead1, lookahead2): |
229 continue | 233 continue |
230 | 234 |
231 # Check if a regexp allows these lines to be different. | 235 # Check if a regexp allows these lines to be different. |
232 if ignore_by_regexp(line1, line2, allowed): | 236 if ignore_by_regexp(line1, line2, allowed): |
233 continue | 237 continue |
234 | 238 |
235 # Lines are different. | 239 # Lines are different. |
236 return ( | 240 return ( |
237 '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2)), | 241 '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2)), |
242 source, | |
238 source_key, | 243 source_key, |
239 ) | 244 ) |
240 | 245 |
241 # No difference found. | 246 # No difference found. |
242 return None, source_key | 247 return None, source, source_key |
243 | 248 |
244 | 249 |
245 def get_suppression(arch1, config1, arch2, config2): | 250 def get_suppression(arch1, config1, arch2, config2): |
246 return V8Suppression(arch1, config1, arch2, config2) | 251 return V8Suppression(arch1, config1, arch2, config2) |
247 | 252 |
248 | 253 |
249 class Suppression(object): | 254 class Suppression(object): |
250 def diff(self, output1, output2): | 255 def diff(self, output1, output2): |
251 return None | 256 return None |
252 | 257 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
309 bug = check(IGNORE_OUTPUT.get(arch, {})) | 314 bug = check(IGNORE_OUTPUT.get(arch, {})) |
310 if bug: | 315 if bug: |
311 return bug | 316 return bug |
312 bug = check(IGNORE_OUTPUT.get(config, {})) | 317 bug = check(IGNORE_OUTPUT.get(config, {})) |
313 if bug: | 318 if bug: |
314 return bug | 319 return bug |
315 bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {})) | 320 bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {})) |
316 if bug: | 321 if bug: |
317 return bug | 322 return bug |
318 return None | 323 return None |
OLD | NEW |