diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/v8/tools/clusterfuzz | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/v8/tools/clusterfuzz')
-rw-r--r-- | chromium/v8/tools/clusterfuzz/v8_commands.py | 7 | ||||
-rwxr-xr-x | chromium/v8/tools/clusterfuzz/v8_foozzie.py | 80 | ||||
-rwxr-xr-x | chromium/v8/tools/clusterfuzz/v8_foozzie_test.py | 21 | ||||
-rw-r--r-- | chromium/v8/tools/clusterfuzz/v8_mock.js | 14 |
4 files changed, 104 insertions, 18 deletions
diff --git a/chromium/v8/tools/clusterfuzz/v8_commands.py b/chromium/v8/tools/clusterfuzz/v8_commands.py index 1956ef2802b..58a757e7a79 100644 --- a/chromium/v8/tools/clusterfuzz/v8_commands.py +++ b/chromium/v8/tools/clusterfuzz/v8_commands.py @@ -40,9 +40,6 @@ JS_SUPPRESSIONS = os.path.join(BASE_PATH, 'v8_suppressions.js') ARCH_MOCKS = os.path.join(BASE_PATH, 'v8_mock_archs.js') WEBASSEMBLY_MOCKS = os.path.join(BASE_PATH, 'v8_mock_webassembly.js') -# Timeout in seconds for one d8 run. -TIMEOUT = 3 - def _startup_files(options): """Default files and optional config-specific mock files.""" @@ -70,7 +67,7 @@ class Command(object): self.files = _startup_files(options) - def run(self, testcase, verbose=False): + def run(self, testcase, timeout, verbose=False): """Run the executable with a specific testcase.""" args = [self.executable] + self.flags + self.files + [testcase] if verbose: @@ -82,7 +79,7 @@ class Command(object): return Execute( args, cwd=os.path.dirname(os.path.abspath(testcase)), - timeout=TIMEOUT, + timeout=timeout, ) @property diff --git a/chromium/v8/tools/clusterfuzz/v8_foozzie.py b/chromium/v8/tools/clusterfuzz/v8_foozzie.py index b6638cc3774..b3cb8cf94fa 100755 --- a/chromium/v8/tools/clusterfuzz/v8_foozzie.py +++ b/chromium/v8/tools/clusterfuzz/v8_foozzie.py @@ -94,6 +94,10 @@ RETURN_FAIL = 2 BASE_PATH = os.path.dirname(os.path.abspath(__file__)) SANITY_CHECKS = os.path.join(BASE_PATH, 'v8_sanity_checks.js') +# Timeout for one d8 run. +SANITY_CHECK_TIMEOUT_SEC = 1 +TEST_TIMEOUT_SEC = 3 + SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64'] # Output for suppressed failure case. @@ -143,6 +147,25 @@ ORIGINAL_SOURCE_HASH_LENGTH = 3 # Placeholder string if no original source file could be determined. ORIGINAL_SOURCE_DEFAULT = 'none' +# Placeholder string for failures from crash tests. If a failure is found with +# this signature, the matching sources should be moved to the mapping below. +ORIGINAL_SOURCE_CRASHTESTS = 'placeholder for CrashTests' + +# Mapping from relative original source path (e.g. CrashTests/path/to/file.js) +# to a string key. Map to the same key for duplicate issues. The key should +# have more than 3 characters to not collide with other existing hashes. +# If a symptom from a particular original source file is known to map to a +# known failure, it can be added to this mapping. This should be done for all +# failures from CrashTests, as those by default map to the placeholder above. +KNOWN_FAILURES = { + # Foo.caller with asm.js: https://crbug.com/1042556 + 'CrashTests/5712410200899584/04483.js': '.caller', + 'CrashTests/5703451898085376/02176.js': '.caller', + 'CrashTests/4846282433495040/04342.js': '.caller', + # Flaky issue that almost never repros. + 'CrashTests/5694376231632896/1033966.js': 'flaky', +} + def infer_arch(d8): """Infer the V8 architecture from the build configuration next to the @@ -229,7 +252,7 @@ def parse_args(): options.first = first_config_arguments.make_options(options) options.second = second_config_arguments.make_options(options) - # Ensure we make a sane comparison. + # Ensure we make a valid comparison. if (options.first.d8 == options.second.d8 and options.first.config == options.second.config): parser.error('Need either executable or config difference.') @@ -292,6 +315,7 @@ def print_difference( else: first_stdout = first_config_output.stdout.decode('utf-8', 'replace') second_stdout = second_config_output.stdout.decode('utf-8', 'replace') + difference = difference.decode('utf-8', 'replace') text = (FAILURE_TEMPLATE % dict( configs='%s:%s' % (first_config_label, second_config_label), @@ -313,6 +337,31 @@ def print_difference( print(text.encode('utf-8', 'replace')) +def cluster_failures(source, known_failures=None): + """Returns a string key for clustering duplicate failures. + + Args: + source: The original source path where the failure happened. + known_failures: Mapping from original source path to failure key. + """ + known_failures = known_failures or KNOWN_FAILURES + # No source known. Typical for manually uploaded issues. This + # requires also manual issue creation. + if not source: + return ORIGINAL_SOURCE_DEFAULT + # Source is known to produce a particular failure. + if source in known_failures: + return known_failures[source] + # Subsume all other sources from CrashTests under one key. Otherwise + # failures lead to new crash tests which in turn lead to new failures. + if source.startswith('CrashTests'): + return ORIGINAL_SOURCE_CRASHTESTS + + # We map all remaining failures to a short hash of the original source. + long_key = hashlib.sha1(source.encode('utf-8')).hexdigest() + return long_key[:ORIGINAL_SOURCE_HASH_LENGTH] + + def main(): options = parse_args() @@ -342,8 +391,20 @@ def main(): # Sanity checks. Run both configurations with the sanity-checks file only and # bail out early if different. if not options.skip_sanity_checks: - first_config_output = first_cmd.run(SANITY_CHECKS) - second_config_output = second_cmd.run(SANITY_CHECKS) + first_config_output = first_cmd.run( + SANITY_CHECKS, timeout=SANITY_CHECK_TIMEOUT_SEC) + + # Early bailout if first run was a timeout. + if timeout_bailout(first_config_output, 1): + return RETURN_PASS + + second_config_output = second_cmd.run( + SANITY_CHECKS, timeout=SANITY_CHECK_TIMEOUT_SEC) + + # Bailout if second run was a timeout. + if timeout_bailout(second_config_output, 2): + return RETURN_PASS + difference, _ = suppress.diff(first_config_output, second_config_output) if difference: # Special source key for sanity checks so that clusterfuzz dedupes all @@ -354,13 +415,15 @@ def main(): first_config_output, second_config_output, difference) return RETURN_FAIL - first_config_output = first_cmd.run(options.testcase, verbose=True) + first_config_output = first_cmd.run( + options.testcase, timeout=TEST_TIMEOUT_SEC, verbose=True) # Early bailout if first run was a timeout. if timeout_bailout(first_config_output, 1): return RETURN_PASS - second_config_output = second_cmd.run(options.testcase, verbose=True) + second_config_output = second_cmd.run( + options.testcase, timeout=TEST_TIMEOUT_SEC, verbose=True) # Bailout if second run was a timeout. if timeout_bailout(second_config_output, 2): @@ -368,12 +431,6 @@ def main(): difference, source = suppress.diff(first_config_output, second_config_output) - if source: - long_key = hashlib.sha1(source.encode('utf-8')).hexdigest() - source_key = long_key[:ORIGINAL_SOURCE_HASH_LENGTH] - else: - source_key = ORIGINAL_SOURCE_DEFAULT - if difference: # Only bail out due to suppressed output if there was a difference. If a # suppression doesn't show up anymore in the statistics, we might want to @@ -383,6 +440,7 @@ def main(): if fail_bailout(second_config_output, suppress.ignore_by_output2): return RETURN_FAIL + source_key = cluster_failures(source) print_difference( options, source_key, first_cmd, second_cmd, first_config_output, second_config_output, difference, source) diff --git a/chromium/v8/tools/clusterfuzz/v8_foozzie_test.py b/chromium/v8/tools/clusterfuzz/v8_foozzie_test.py index f82afc9e205..4a5affd76ea 100755 --- a/chromium/v8/tools/clusterfuzz/v8_foozzie_test.py +++ b/chromium/v8/tools/clusterfuzz/v8_foozzie_test.py @@ -51,8 +51,8 @@ class ConfigTest(unittest.TestCase): assert all(map(lambda x: x[3] in KNOWN_BUILDS, EXPERIMENTS)) # Ensure we compare different configs and same d8, or same config # to different d8. - is_sane_comparison = lambda x: (x[1] == x[2]) == ('d8' != x[3]) - assert all(map(is_sane_comparison, EXPERIMENTS)) + is_valid_comparison = lambda x: (x[1] == x[2]) == ('d8' != x[3]) + assert all(map(is_valid_comparison, EXPERIMENTS)) # All flags have a probability. first_is_float = lambda x: type(x[0]) == float assert all(map(first_is_float, FLAGS)) @@ -101,6 +101,23 @@ class ConfigTest(unittest.TestCase): class UnitTest(unittest.TestCase): + def testCluster(self): + crash_test_example_path = 'CrashTests/path/to/file.js' + self.assertEqual( + v8_foozzie.ORIGINAL_SOURCE_DEFAULT, + v8_foozzie.cluster_failures('')) + self.assertEqual( + v8_foozzie.ORIGINAL_SOURCE_CRASHTESTS, + v8_foozzie.cluster_failures(crash_test_example_path)) + self.assertEqual( + '_o_O_', + v8_foozzie.cluster_failures( + crash_test_example_path, + known_failures={crash_test_example_path: '_o_O_'})) + self.assertEqual( + '980', + v8_foozzie.cluster_failures('v8/test/mjsunit/apply.js')) + def testDiff(self): def diff_fun(one, two, skip=False): suppress = v8_suppressions.get_suppression( diff --git a/chromium/v8/tools/clusterfuzz/v8_mock.js b/chromium/v8/tools/clusterfuzz/v8_mock.js index 6372a7afe2b..ca1336a0df6 100644 --- a/chromium/v8/tools/clusterfuzz/v8_mock.js +++ b/chromium/v8/tools/clusterfuzz/v8_mock.js @@ -149,6 +149,20 @@ Object.defineProperty( Float64Array = mock(Float64Array); })(); +// Mock buffer access via DataViews because of varying NaN patterns. +(function() { + const origIsNaN = isNaN; + const deNaNify = function(value) { return origIsNaN(value) ? 1 : value; }; + const origSetFloat32 = DataView.prototype.setFloat32; + DataView.prototype.setFloat32 = function(offset, value, ...rest) { + origSetFloat32.call(this, offset, deNaNify(value), ...rest); + }; + const origSetFloat64 = DataView.prototype.setFloat64; + DataView.prototype.setFloat64 = function(offset, value, ...rest) { + origSetFloat64.call(this, offset, deNaNify(value), ...rest); + }; +})(); + // Mock Worker. (function() { let index = 0; |