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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/foozzie/v8_suppressions.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/foozzie/v8_suppressions.py
diff --git a/tools/foozzie/v8_suppressions.py b/tools/foozzie/v8_suppressions.py
new file mode 100644
index 0000000000000000000000000000000000000000..f5b736cdc3c1b60f93869ec1490674d82a2ce0f3
--- /dev/null
+++ b/tools/foozzie/v8_suppressions.py
@@ -0,0 +1,266 @@
+# Copyright 2016 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Suppressions for V8 correctness fuzzer failures.
+
+We support three types of suppressions:
+1. Ignore test case by pattern.
+Map a regular expression to a bug entry. A new failure will be reported
+when the pattern matches a JS test case.
+Subsequent matches will be recoreded under the first failure.
+
+2. Ignore test run by output pattern:
+Map a regular expression to a bug entry. A new failure will be reported
+when the pattern matches the output of a particular run.
+Subsequent matches will be recoreded under the first failure.
+
+3. Relax line-to-line comparisons with expressions of lines to ignore and
+lines to be normalized (i.e. ignore only portions of lines).
+These are not tied to bugs, be careful to not silently switch off this tool!
+
+Alternatively, think about adding a behavior change to v8_suppressions.js
+to silence a particular class of problems.
+"""
+
+import itertools
+import re
+
+# Max line length for regular experessions checking for lines to ignore.
+MAX_LINE_LENGTH = 512
+
+# For ignoring lines before carets and to ignore caret positions.
+CARET_RE = re.compile(r'^\s*\^\s*$')
+
+# Ignore by test case pattern. Map from bug->regexp.
+# Regular expressions are assumed to be compiled. We use regexp.match.
+IGNORE_TEST_CASES = {
+ 'crbug.com/662907':
+ re.compile(r'.*new Array.*\[\d+\] =.*'
+ r'((Array)|(Object)).prototype.__defineSetter__.*', re.S),
+
+ 'crbug.com/663340':
+ re.compile(r'.*\.shift\(\).*', re.S),
+
+ 'crbug.com/666308':
+ re.compile(r'.*End stripped down and modified version.*'
+ r'\.prototype.*instanceof.*.*', re.S),
+}
+
+# Ignore by output pattern. Map from config->bug->regexp. Config '' is used
+# to match all configurations. Otherwise use either a compiler configuration,
+# e.g. fullcode or validate_asm or an architecture, e.g. x64 or ia32 or a
+# comma-separated combination, e.g. x64,fullcode, for more specific
+# suppressions.
+# Bug is preferred to be a crbug.com/XYZ, but can be any short distinguishable
+# label.
+# Regular expressions are assumed to be compiled. We use regexp.search.
+IGNORE_OUTPUT = {
+ '': {
+ 'crbug.com/664068':
+ re.compile(r'RangeError', re.S),
+
+ 'crbug.com/669017':
+ re.compile(r'SyntaxError', re.S),
+ },
+ 'validate_asm': {
+ 'validate_asm':
+ re.compile(r'TypeError'),
+ },
+}
+
+# Lines matching any of the following regular expressions will be ignored
+# if appearing on both sides. The capturing groups need to match exactly.
+# Use uncompiled regular expressions - they'll be compiled later.
+ALLOWED_LINE_DIFFS = [
+ # Ignore caret position in stack traces.
+ r'^\s*\^\s*$',
+
+ # Ignore some stack trace headers as messages might not match.
+ r'^(.*)TypeError: .* is not a function$',
+ r'^(.*)TypeError: .* is not a constructor$',
+ r'^(.*)TypeError: (.*) is not .*$',
+ r'^(.*)ReferenceError: .* is not defined$',
+ r'^(.*):\d+: ReferenceError: .* is not defined$',
+
+ # These are rarely needed. It includes some cases above.
+ r'^\w*Error: .* is not .*$',
+ r'^(.*) \w*Error: .* is not .*$',
+ r'^(.*):\d+: \w*Error: .* is not .*$',
+
+ # Some test cases just print the message.
+ r'^.* is not a function(.*)$',
+ r'^(.*) is not a .*$',
+
+ # crbug.com/669017
+ r'^(.*)SyntaxError: .*$',
+
+ # Ignore lines of stack traces as character positions might not match.
+ r'^ at (?:new )?([^:]*):\d+:\d+(.*)$',
+ r'^(.*):\d+:(.*)$',
+
+ # crbug.com/662840
+ r"^.*(?:Trying to access ')?(\w*)(?:(?:' through proxy)|"
+ r"(?: is not defined))$",
+]
+
+# Lines matching any of the following regular expressions will be ignored.
+# Use uncompiled regular expressions - they'll be compiled later.
+IGNORE_LINES = [
+ r'^Validation of asm\.js module failed: .+$',
+ r'^.*:\d+: Invalid asm.js: .*$',
+ r'^Warning: unknown flag .*$',
+ r'^Warning: .+ is deprecated.*$',
+ r'^Try --help for options$',
+]
+
+
+###############################################################################
+# Implementation - you should not need to change anything below this point.
+
+# Compile regular expressions.
+ALLOWED_LINE_DIFFS = [re.compile(exp) for exp in ALLOWED_LINE_DIFFS]
+IGNORE_LINES = [re.compile(exp) for exp in IGNORE_LINES]
+
+
+def line_pairs(lines):
+ return itertools.izip_longest(
+ lines, itertools.islice(lines, 1, None), fillvalue=None)
+
+
+def caret_match(line1, line2):
+ if (not line1 or
+ not line2 or
+ len(line1) > MAX_LINE_LENGTH or
+ len(line2) > MAX_LINE_LENGTH):
+ return False
+ return bool(CARET_RE.match(line1) and CARET_RE.match(line2))
+
+
+def short_line_output(line):
+ if len(line) <= MAX_LINE_LENGTH:
+ # Avoid copying.
+ return line
+ return line[0:MAX_LINE_LENGTH] + '...'
+
+
+def ignore_by_regexp(line1, line2, allowed):
+ if len(line1) > MAX_LINE_LENGTH or len(line2) > MAX_LINE_LENGTH:
+ return False
+ for exp in allowed:
+ match1 = exp.match(line1)
+ match2 = exp.match(line2)
+ if match1 and match2:
+ # If there are groups in the regexp, ensure the groups matched the same
+ # things.
+ if match1.groups() == match2.groups(): # tuple comparison
+ return True
+ return False
+
+
+def diff_output(output1, output2, allowed, ignore1, ignore2):
+ def useful_line(ignore):
+ def fun(line):
+ return all(not e.match(line) for e in ignore)
+ return fun
+
+ lines1 = filter(useful_line(ignore1), output1)
+ lines2 = filter(useful_line(ignore2), output2)
+
+ for ((line1, lookahead1), (line2, lookahead2)) in itertools.izip_longest(
+ line_pairs(lines1), line_pairs(lines2), fillvalue=(None, None)):
+
+ # Only one of the two iterators should run out.
+ assert not (line1 is None and line2 is None)
+
+ # One iterator ends earlier.
+ if line1 is None:
+ return '+ %s' % short_line_output(line2)
+ if line2 is None:
+ return '- %s' % short_line_output(line1)
+
+ # If lines are equal, no further checks are necessary.
+ if line1 == line2:
+ continue
+
+ # Look ahead. If next line is a caret, ignore this line.
+ if caret_match(lookahead1, lookahead2):
+ continue
+
+ # Check if a regexp allows these lines to be different.
+ if ignore_by_regexp(line1, line2, allowed):
+ continue
+
+ # Lines are different.
+ return '- %s\n+ %s' % (short_line_output(line1), short_line_output(line2))
+
+ # No difference found.
+ return None
+
+
+def get_suppression(arch1, config1, arch2, config2):
+ return V8Suppression(arch1, config1, arch2, config2)
+
+
+class Suppression(object):
+ def diff(self, output1, output2):
+ return None
+
+ def ignore(self, testcase):
+ return False
+
+ def ignore_by_output1(self, output):
+ return False
+
+ def ignore_by_output2(self, output):
+ return False
+
+
+class V8Suppression(Suppression):
+ def __init__(self, arch1, config1, arch2, config2):
+ self.arch1 = arch1
+ self.config1 = config1
+ self.arch2 = arch2
+ self.config2 = config2
+
+ def diff(self, output1, output2):
+ return diff_output(
+ output1.splitlines(),
+ output2.splitlines(),
+ ALLOWED_LINE_DIFFS,
+ IGNORE_LINES,
+ IGNORE_LINES,
+ )
+
+ def ignore(self, testcase):
+ for bug, exp in IGNORE_TEST_CASES.iteritems():
+ if exp.match(testcase):
+ return bug
+ return False
+
+ def ignore_by_output1(self, output):
+ return self.ignore_by_output(output, self.arch1, self.config1)
+
+ def ignore_by_output2(self, output):
+ return self.ignore_by_output(output, self.arch2, self.config2)
+
+ def ignore_by_output(self, output, arch, config):
+ def check(mapping):
+ for bug, exp in mapping.iteritems():
+ if exp.search(output):
+ return bug
+ return None
+ bug = check(IGNORE_OUTPUT.get('', {}))
+ if bug:
+ return bug
+ bug = check(IGNORE_OUTPUT.get(arch, {}))
+ if bug:
+ return bug
+ bug = check(IGNORE_OUTPUT.get(config, {}))
+ if bug:
+ return bug
+ bug = check(IGNORE_OUTPUT.get('%s,%s' % (arch, config), {}))
+ if bug:
+ return bug
+ return None
« 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