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

Unified Diff: tools/foozzie/v8_foozzie.py

Issue 2578503003: [foozzie] Initial correctness fuzzer harness. (Closed)
Patch Set: updates 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
Index: tools/foozzie/v8_foozzie.py
diff --git a/tools/foozzie/v8_foozzie.py b/tools/foozzie/v8_foozzie.py
new file mode 100755
index 0000000000000000000000000000000000000000..87cdb2124818b7c533b11184abcf66024f58c015
--- /dev/null
+++ b/tools/foozzie/v8_foozzie.py
@@ -0,0 +1,263 @@
+#!/usr/bin/env python
+# 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.
+
+"""
+V8 correctness fuzzer launcher script.
+"""
+
+import argparse
+import itertools
+import os
+import re
+import sys
+import traceback
+
+import v8_commands
+import v8_suppressions
+
+CONFIGS = {
+ 'default': [],
+ 'validate_asm': ['--validate-asm'], # Maybe add , '--disable-asm-warnings'
+ 'fullcode': ['--nocrankshaft', '--turbo-filter=~'],
+ 'noturbo': ['--turbo-filter=~', '--noturbo-asm'],
+ 'noturbo_opt': ['--always-opt', '--turbo-filter=~', '--noturbo-asm'],
+ 'ignition_staging': ['--ignition-staging'],
+ 'ignition_turbo': ['--ignition-staging', '--turbo'],
+ 'ignition_turbo_opt': ['--ignition-staging', '--turbo', '--always-opt'],
+}
+
+# Timeout in seconds for one d8 run.
+TIMEOUT = 3
+
+BASE_PATH = os.path.dirname(os.path.abspath(__file__))
+PREAMBLE = [
+ os.path.join(BASE_PATH, 'v8_mock.js'),
+ os.path.join(BASE_PATH, 'v8_suppressions.js'),
+]
+
+FLAGS = ['--abort_on_stack_overflow', '--expose-gc', '--allow-natives-syntax',
+ '--invoke-weak-callbacks', '--omit-quit', '--es-staging']
+
+SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64']
+
+# Output for suppressed failure case.
+FAILURE_HEADER_TEMPLATE = """#
tandrii(chromium) 2016/12/16 16:46:26 Nit: instead of """# i'd do: """ # .... """.strip
Michael Achenbach 2016/12/19 08:42:45 Done.
+# V8 correctness failure
+# V8 correctness configs: %(configs)s
+# V8 correctness sources: %(sources)s
+# V8 correctness suppression: %(suppression)s"""
+
+# Extended output for failure case. The 'CHECK' is for the minimizer.
+FAILURE_TEMPLATE = FAILURE_HEADER_TEMPLATE + """#
+# CHECK
+#
+# Compared %(first_config_label)s with %(second_config_label)s
+#
+# Flags of %(first_config_label)s:
+%(first_config_flags)s
+# Flags of %(second_config_label)s:
+%(second_config_flags)s
+#
+# Difference:
+%(difference)s
+#
+### Start of configuration %(first_config_label)s:
+%(first_config_output)s
+### End of configuration %(first_config_label)s
+#
+### Start of configuration %(second_config_label)s:
+%(second_config_output)s
+### End of configuration %(second_config_label)s
+"""
+
+
+def parse_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--random-seed', type=int, required=True,
+ help='random seed passed to both runs')
+ parser.add_argument(
+ '--first-arch', help='first architecture', default='x64')
+ parser.add_argument(
+ '--second-arch', help='second architecture', default='x64')
+ parser.add_argument(
+ '--first-config', help='first configuration', default='fullcode')
+ parser.add_argument(
+ '--second-config', help='second configuration', default='fullcode')
+ parser.add_argument(
+ '--first-d8', default='d8',
+ help='optional path to first d8 executable, default: side-by-side')
tandrii(chromium) 2016/12/16 16:46:26 what does "side-by-side" mean?
Michael Achenbach 2016/12/19 08:42:45 Clarified.
+ parser.add_argument(
+ '--second-d8',
+ help='optional path to second d8 executable, default: same as first')
+ parser.add_argument('testcase', help='path to test case')
+ options = parser.parse_args()
+
+ # Ensure we make a sane comparison.
+ assert (options.first_arch != options.second_arch or
+ options.first_config != options.second_config) , (
+ 'Need either arch or config difference.')
+ assert options.first_arch in SUPPORTED_ARCHS
+ assert options.second_arch in SUPPORTED_ARCHS
+ assert options.first_config in CONFIGS
+ assert options.second_config in CONFIGS
+
+ # Ensure we have a test case.
+ assert (os.path.exists(options.testcase) and
tandrii(chromium) 2016/12/16 16:46:26 if x: parser.error() is nicer, but assert is cer
Michael Achenbach 2016/12/19 08:42:45 The script is designed to be called from automated
+ os.path.isfile(options.testcase)), (
+ 'Test case %s doesn\'t exist' % options.testcase)
+
+ # Use first d8 as default for second d8.
+ options.second_d8 = options.second_d8 or options.first_d8
+
+ # Ensure absolute paths.
+ options.first_d8 = os.path.abspath(options.first_d8)
+ options.second_d8 = os.path.abspath(options.second_d8)
+
+ # Ensure executables exist.
+ assert os.path.exists(options.first_d8)
+ assert os.path.exists(options.second_d8)
+
+ # Ensure we use different executables when we claim we compare
+ # different architectures.
+ # TODO(machenbach): Infer arch from gn's build output.
+ if options.first_arch != options.second_arch:
+ assert options.first_d8 != options.second_d8
+
+ return options
+
+
+def test_pattern_bailout(testcase, ignore_fun):
+ """Print failure state and return if ignore_fun matches testcase."""
+ with open(testcase) as f:
+ bug = (ignore_fun(f.read()) or '').strip()
+ if bug:
+ print FAILURE_HEADER_TEMPLATE % {
+ 'configs': '',
+ 'sources': '',
+ 'suppression': bug,
+ }
+ return True
+ return False
+
+
+def pass_bailout(output, step_number):
+ """Print info and return if in timeout or crash pass states."""
+ if output.HasTimedOut():
+ # Dashed output, so that no other clusterfuzz tools can match the
+ # words timeout or crash.
+ print '# V8 correctness - T-I-M-E-O-U-T %d' % step_number
+ return True
+ if output.HasCrashed():
+ print '# V8 correctness - C-R-A-S-H %d' % step_number
+ return True
+ return False
+
+
+def fail_bailout(output, ignore_by_output_fun):
+ """Print failure state and return if ignore_by_output_fun matches output."""
+ bug = (ignore_by_output_fun(output.stdout) or '').strip()
+ if bug:
+ print FAILURE_HEADER_TEMPLATE % {
+ 'configs': '',
+ 'sources': '',
+ 'suppression': bug,
+ }
+ return True
+ return False
+
+
+def main():
+ options = parse_args()
+
+ # Suppressions are architecture and configuration specific.
+ suppress = v8_suppressions.get_suppression(
+ options.first_arch, options.first_config,
+ options.second_arch, options.second_config,
+ )
+
+ if test_pattern_bailout(options.testcase, suppress.ignore):
+ return 2
tandrii(chromium) 2016/12/16 16:46:26 i'd make 2 a meaningful constant, perhaps 0 too.
Michael Achenbach 2016/12/19 08:42:45 Done.
+
+ common_flags = FLAGS + ['--random-seed', str(options.random_seed)]
+ first_config_flags = common_flags + CONFIGS[options.first_config]
+ second_config_flags = common_flags + CONFIGS[options.second_config]
+
+ def run_d8(d8, config_flags):
+ return v8_commands.Execute(
+ [d8] + config_flags + PREAMBLE + [options.testcase],
+ cwd=os.path.dirname(options.testcase),
+ timeout=TIMEOUT,
+ )
+
+ first_config_output = run_d8(options.first_d8, first_config_flags)
+
+ # Early bailout based on first run's output.
+ if pass_bailout(first_config_output, 1):
+ return 0
+ if fail_bailout(first_config_output, suppress.ignore_by_output1):
+ return 2
+
+ second_config_output = run_d8(options.second_d8, second_config_flags)
+
+ # Bailout based on second run's output.
+ if pass_bailout(second_config_output, 2):
+ return 0
+ if fail_bailout(second_config_output, suppress.ignore_by_output2):
+ return 2
+
+ difference = suppress.diff(
+ first_config_output.stdout, second_config_output.stdout)
+ if difference:
+ # The first three entries will be parsed by clusterfuzz. Format changes
+ # will require changes on the clusterfuzz side.
+ first_config_label = '%s,%s' % (options.first_arch, options.first_config)
+ second_config_label = '%s,%s' % (options.second_arch, options.second_config)
+ print FAILURE_TEMPLATE % {
+ 'configs': '%s:%s' % (first_config_label, second_config_label),
+ 'sources': '', # TODO
+ 'suppression': '', # We can't tie bugs to differences.
+ 'first_config_label': first_config_label,
+ 'second_config_label': second_config_label,
+ 'first_config_flags': ' '.join(first_config_flags),
+ 'second_config_flags': ' '.join(second_config_flags),
+ 'first_config_output': first_config_output.stdout,
+ 'second_config_output': second_config_output.stdout,
+ 'difference': difference,
+ }
+ return 2
+
+ # TODO(machenbach): Figure out if we could also return a bug in case there's
+ # no difference, but one of the line suppressions has matched - and without
+ # the match there would be a difference.
+
+ print '# V8 correctness - pass'
+ return 0
+
+
+if __name__ == "__main__":
+ try:
+ result = main()
+ except SystemExit:
+ # Make sure clusterfuzz reports internal errors and wrong usage.
+ # Use one label for all internal and usage errors.
+ print FAILURE_HEADER_TEMPLATE % {
+ 'configs': '',
tandrii(chromium) 2016/12/19 08:43:32 nitty IMO: % dict(configs='', sources='', suppress
Michael Achenbach 2016/12/19 09:42:19 Done. Also for the other dicts here.
+ 'sources': '',
+ 'suppression': 'wrong_usage',
+ }
+ result = 2
+ except Exception as e:
+ print FAILURE_HEADER_TEMPLATE % {
+ 'configs': '',
+ 'sources': '',
+ 'suppression': 'internal_error',
+ }
+ print '# Internal error: %s' % e
+ traceback.print_exc(file=sys.stdout)
+ result = 2
+
+ sys.exit(result)
+

Powered by Google App Engine
This is Rietveld 408576698