Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: tools/foozzie/v8_suppressions.py

Issue 2578503003: [foozzie] Initial correctness fuzzer harness. (Closed)
Patch Set: Presubmit Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/foozzie/v8_suppressions.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 # found in the LICENSE file.
4
5 """
6 Suppressions for V8 correctness fuzzer failures.
7
8 We support three types of suppressions:
9 1. Ignore test case by pattern.
10 Map a regular expression to a bug entry. A new failure will be reported
11 when the pattern matches a JS test case.
12 Subsequent matches will be recoreded under the first failure.
13
14 2. Ignore test run by output pattern:
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.
17 Subsequent matches will be recoreded under the first failure.
18
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).
21 These are not tied to bugs, be careful to not silently switch off this tool!
22
23 Alternatively, think about adding a behavior change to v8_suppressions.js
24 to silence a particular class of problems.
25 """
26
27 import itertools
28 import re
29
30 # Max line length for regular experessions checking for lines to ignore.
31 MAX_LINE_LENGTH = 512
32
33 # For ignoring lines before carets and to ignore caret positions.
34 CARET_RE = re.compile(r'^\s*\^\s*$')
35
36 # Ignore by test case pattern. Map from bug->regexp.
37 # Regular expressions are assumed to be compiled. We use regexp.match.
38 IGNORE_TEST_CASES = {
39 'crbug.com/662907':
40 re.compile(r'.*new Array.*\[\d+\] =.*'
41 r'((Array)|(Object)).prototype.__defineSetter__.*', re.S),
42
43 'crbug.com/663340':
44 re.compile(r'.*\.shift\(\).*', re.S),
45
46 'crbug.com/666308':
47 re.compile(r'.*End stripped down and modified version.*'
48 r'\.prototype.*instanceof.*.*', re.S),
49 }
50
51 # Ignore by output pattern. Map from config->bug->regexp. Config '' is used
52 # to match all configurations. Otherwise use either a compiler configuration,
53 # e.g. fullcode or validate_asm or an architecture, e.g. x64 or ia32 or a
54 # comma-separated combination, e.g. x64,fullcode, for more specific
55 # suppressions.
56 # Bug is preferred to be a crbug.com/XYZ, but can be any short distinguishable
57 # label.
58 # Regular expressions are assumed to be compiled. We use regexp.search.
59 IGNORE_OUTPUT = {
60 '': {
61 'crbug.com/664068':
62 re.compile(r'RangeError', re.S),
63
64 'crbug.com/669017':
65 re.compile(r'SyntaxError', re.S),
66 },
67 'validate_asm': {
68 'validate_asm':
69 re.compile(r'TypeError'),
70 },
71 }
72
73 # Lines matching any of the following regular expressions will be ignored
74 # if appearing on both sides. The capturing groups need to match exactly.
75 # Use uncompiled regular expressions - they'll be compiled later.
76 ALLOWED_LINE_DIFFS = [
77 # Ignore caret position in stack traces.
78 r'^\s*\^\s*$',
79
80 # Ignore some stack trace headers as messages might not match.
81 r'^(.*)TypeError: .* is not a function$',
82 r'^(.*)TypeError: .* is not a constructor$',
83 r'^(.*)TypeError: (.*) is not .*$',
84 r'^(.*)ReferenceError: .* is not defined$',
85 r'^(.*):\d+: ReferenceError: .* is not defined$',
86
87 # These are rarely needed. It includes some cases above.
88 r'^\w*Error: .* is not .*$',
89 r'^(.*) \w*Error: .* is not .*$',
90 r'^(.*):\d+: \w*Error: .* is not .*$',
91
92 # Some test cases just print the message.
93 r'^.* is not a function(.*)$',
94 r'^(.*) is not a .*$',
95
96 # crbug.com/669017
97 r'^(.*)SyntaxError: .*$',
98
99 # Ignore lines of stack traces as character positions might not match.
100 r'^ at (?:new )?([^:]*):\d+:\d+(.*)$',
101 r'^(.*):\d+:(.*)$',
102
103 # crbug.com/662840
104 r"^.*(?:Trying to access ')?(\w*)(?:(?:' through proxy)|"
105 r"(?: is not defined))$",
106 ]
107
108 # Lines matching any of the following regular expressions will be ignored.
109 # Use uncompiled regular expressions - they'll be compiled later.
110 IGNORE_LINES = [
111 r'^Validation of asm\.js module failed: .+$',
112 r'^.*:\d+: Invalid asm.js: .*$',
113 r'^Warning: unknown flag .*$',
114 r'^Warning: .+ is deprecated.*$',
115 r'^Try --help for options$',
116 ]
117
118
119 ###############################################################################
120 # Implementation - you should not need to change anything below this point.
121
122 # Compile regular expressions.
123 ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS]
124 IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES]
125
126
127 def line_pairs(lines):
128 return itertools.izip_longest(
129 lines, itertools.islice(lines, 1, None), fillvalue=None)
130
131
132 def caret_match(line1, line2):
133 if (not line1 or
134 not line2 or
135 len(line1) > MAX_LINE_LENGTH or
136 len(line2) > MAX_LINE_LENGTH):
137 return False
138 return bool(CARET_RE.match(line1) and CARET_RE.match(line2))
139
140
141 def short_line_output(line):
142 if len(line) <= MAX_LINE_LENGTH:
143 # Avoid copying.
144 return line
145 return line[0:MAX_LINE_LENGTH] + '...'
146
147
148 def ignore_by_regexp(line1, line2, allowed):
149 if len(line1) > MAX_LINE_LENGTH or len(line2) > MAX_LINE_LENGTH:
150 return False
151 for exp in allowed:
152 match1 = exp.match(line1)
153 match2 = exp.match(line2)
154 if match1 and match2:
155 # If there are groups in the regexp, ensure the groups matched the same
156 # things.
157 if match1.groups() == match2.groups(): # tuple comparison
158 return True
159 return False
160
161
162 def diff_output(output1, output2, allowed, ignore1, ignore2):
163 def useful_line(ignore):
164 def fun(line):
165 return all(not e.match(line) for e in ignore)
166 return fun
167
168 lines1 = filter(useful_line(ignore1), output1)
169 lines2 = filter(useful_line(ignore2), output2)
170
171 for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest(
172 line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)):
173
174 # Only one of the two iterators should run out.
175 assert not (line1 is None and line2 is None)
176
177 # One iterator ends earlier.
178 if line1 is None:
179 return '+ %s' % short_line_output(line2)
180 if line2 is None:
181 return '- %s' % short_line_output(line1)
182
183 # If lines are equal, no further checks are necessary.
184 if line1 == line2:
185 continue
186
187 # Look ahead. If next line is a caret, ignore this line.
188 if caret_match(lookahead1, lookahead2):
189 continue
190
191 # Check if a regexp allows these lines to be different.
192 if ignore_by_regexp(line1, line2, allowed):
193 continue
194
195 # Lines are different.
196 return '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2))
197
198 # No difference found.
199 return None
200
201
202 def get_suppression(arch1, config1, arch2, config2):
203 return V8Suppression(arch1, config1, arch2, config2)
204
205
206 class Suppression(object):
207 def diff(self, output1, output2):
208 return None
209
210 def ignore(self, testcase):
211 return False
212
213 def ignore_by_output1(self, output):
214 return False
215
216 def ignore_by_output2(self, output):
217 return False
218
219
220 class V8Suppression(Suppression):
221 def __init__(self, arch1, config1, arch2, config2):
222 self.arch1 = arch1
223 self.config1 = config1
224 self.arch2 = arch2
225 self.config2 = config2
226
227 def diff(self, output1, output2):
228 return diff_output(
229 output1.splitlines(),
230 output2.splitlines(),
231 ALLOWED_LINE_DIFFS,
232 IGNORE_LINES,
233 IGNORE_LINES,
234 )
235
236 def ignore(self, testcase):
237 for bug, exp in IGNORE_TEST_CASES.iteritems():
238 if exp.match(testcase):
239 return bug
240 return False
241
242 def ignore_by_output1(self, output):
243 return self.ignore_by_output(output, self.arch1, self.config1)
244
245 def ignore_by_output2(self, output):
246 return self.ignore_by_output(output, self.arch2, self.config2)
247
248 def ignore_by_output(self, output, arch, config):
249 def check(mapping):
250 for bug, exp in mapping.iteritems():
251 if exp.search(output):
252 return bug
253 return None
254 bug = check(IGNORE_OUTPUT.get('', {}))
255 if bug:
256 return bug
257 bug = check(IGNORE_OUTPUT.get(arch, {}))
258 if bug:
259 return bug
260 bug = check(IGNORE_OUTPUT.get(config, {}))
261 if bug:
262 return bug
263 bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {}))
264 if bug:
265 return bug
266 return None
OLDNEW
« no previous file with comments | « tools/foozzie/v8_suppressions.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698