blob: 7762cb2c944da85cb8a22700f198e21ed2442a93 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2020 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.
"""
Helper script to execute fuzz tests in a single process.
Expects fuzz tests in workdir/output/dir-<dir number>/fuzz-XXX.js.
Expects the <dir number> as single parameter.
"""
import json
import os
import random
import re
import subprocess
import sys
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FOOZZIE = os.path.join(BASE_PATH, 'workdir', 'app_dir', 'v8_foozzie.py')
TEST_CASES = os.path.join(BASE_PATH, 'workdir', 'output')
# Output pattern from foozzie.py when it finds a failure.
FAILURE_RE = re.compile(
r'# V8 correctness failure.'
r'# V8 correctness configs: (?P<configs>.*).'
r'# V8 correctness sources: (?P<source>.*).'
r'# V8 correctness suppression:.*', re.S)
assert(len(sys.argv) > 1)
dir_number = int(sys.argv[1])
assert(dir_number >= 0)
test_dir = os.path.join(TEST_CASES, 'dir-%d' % dir_number)
assert os.path.exists(test_dir)
def failure_state(command, stdout):
return dict(FAILURE_RE.search(stdout).groupdict(), command=command)
def random_seed():
"""Returns random, non-zero seed."""
seed = 0
while not seed:
seed = random.SystemRandom().randint(-2147483648, 2147483647)
return seed
def run(fuzz_file, flag_file):
"""Executes the differential-fuzzing harness foozzie with one fuzz test."""
with open(flag_file) as f:
flags = f.read().split(' ')
args = [FOOZZIE, '--random-seed=%d' % random_seed()] + flags + [fuzz_file]
cmd = ' '.join(args)
try:
output = subprocess.check_output(cmd, stderr=subprocess.PIPE, shell=True)
return (cmd, output)
except Exception as e:
return (cmd, e.output)
def list_tests():
"""Iterates all fuzz tests and corresponding flags in the given base dir."""
for f in os.listdir(test_dir):
if f.startswith('fuzz'):
n = int(re.match(r'fuzz-(\d+)\.js', f).group(1))
ff = 'flags-%d.js' % n
yield (os.path.join(test_dir, f), os.path.join(test_dir, ff))
# Some counters for the statistics.
count = 0
count_timeout = 0
count_crash = 0
count_failure = 0
failures = []
# Execute all tests in the given directory. Interpret foozzie's output and add
# it to the statistics.
for fuzz_file, flag_file in list_tests():
cmd, output = run(fuzz_file, flag_file)
count += 1
if '# V8 correctness - pass' in output:
continue
if '# V8 correctness - T-I-M-E-O-U-T' in output:
count_timeout += 1
continue
if '# V8 correctness - C-R-A-S-H' in output:
count_crash += 1
continue
count_failure += 1
failures.append(failure_state(cmd, output))
with open(os.path.join(test_dir, 'failures.json'), 'w') as f:
json.dump(failures, f)
stats = {
'total': count,
'timeout': count_timeout,
'crash': count_crash,
'failure': count_failure,
}
with open(os.path.join(test_dir, 'stats.json'), 'w') as f:
json.dump(stats, f)