code_coverage: fuzzilli: run all JS testcases separately
This is necessary because `d8` runs the test cases in the same JS
namespace. This means that if identifiers are shared in between those,
we'll fail with errors such as TypeError.
Change-Id: Ide287027c278f9b4d986fa885d47969c8fe41df2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6449806
Commit-Queue: Paul Semel <[email protected]>
Reviewed-by: Ali Hijazi <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1446424}
NOKEYCHECK=True
GitOrigin-RevId: b9e0508865db219977ed75521e7d8abe54ec014e
diff --git a/run_all_fuzzers.py b/run_all_fuzzers.py
index 21ae013..65b5dcb 100644
--- a/run_all_fuzzers.py
+++ b/run_all_fuzzers.py
@@ -149,9 +149,20 @@
@dataclasses.dataclass
-class FuzzilliRunner(CmdRunner):
+class FuzzilliRunner(EngineRunner):
"""Runs a given target with Fuzzilli.
"""
+ d8_path: str
+ target_arguments: Sequence[str]
+ source_dir: str
+
+ def __post_init__(self):
+ self.d8_path = os.path.abspath(self.d8_path)
+ self.source_dir = os.path.abspath(self.source_dir)
+
+ @property
+ def cmd(self):
+ return [self.d8_path] + self.target_arguments
def run_full_corpus(self, env: Mapping[str, str], timeout: float,
annotation: str, corpus_dir: Optional[str]) -> bool:
@@ -161,11 +172,18 @@
def run_testcases(self, env: Mapping[str, str], timeout: float,
annotation: str, testcases: Sequence[str]) -> bool:
- # That's a tricky part here. Basically, running cases by cases takes a
- # gigantic amount of time, and given that we split initial targets chunks
- # into even smaller chunks, we just hope that we execute as much test cases
- # as possible in those runs and consider it a success.
- super().run_testcases(env, timeout, annotation, testcases)
+ run_dir = tempfile.TemporaryDirectory()
+ os.symlink(os.path.join(self.source_dir, 'v8/test/'),
+ os.path.join(run_dir.name, 'test'))
+ # We need to run the test cases separately, because otherwise the JS files
+ # will be ran in the same JS namespace.
+ for testcase in testcases:
+ testcase = os.path.abspath(testcase)
+ _run_and_log(cmd=self.cmd + [testcase],
+ env=env,
+ timeout=timeout,
+ annotation=annotation,
+ cwd=run_dir.name)
return True
@@ -206,8 +224,11 @@
return False
-def _run_and_log(cmd: Sequence[str], env: Mapping[str, str], timeout: float,
- annotation: str) -> bool:
+def _run_and_log(cmd: Sequence[str],
+ env: Mapping[str, str],
+ timeout: float,
+ annotation: str,
+ cwd: str = None) -> bool:
"""Runs a given command and logs output in case of failure.
Args:
@@ -225,7 +246,8 @@
env=env,
timeout=timeout,
capture_output=True,
- check=True)
+ check=True,
+ cwd=cwd)
return True
except Exception as e:
if type(e) == subprocess.TimeoutExpired:
@@ -678,6 +700,7 @@
def _get_fuzzilli_target_details(args):
all_target_details = []
fuzzer_target_binpath = os.path.join(args.fuzzer_binaries_dir, 'd8')
+ source_dir = os.path.abspath(os.path.join(args.fuzzer_binaries_dir, '../../'))
if not os.path.isfile(fuzzer_target_binpath):
logging.warning(f'Could not find binary file: {fuzzer_target_binpath}')
return all_target_details
@@ -692,8 +715,6 @@
'settings.json')
with open(path_to_settings, 'r') as fp:
settings = json.load(fp)
- cmd = [fuzzer_target_binpath]
- cmd.extend(settings['processArguments'])
path_to_js_dir = os.path.join(target_corpora_dir, 'fuzzdir', 'corpus')
jsfiles = [
os.path.join(path_to_js_dir, file)
@@ -711,7 +732,9 @@
'env':
dict(),
'cmd_runner':
- FuzzilliRunner(cmd=cmd),
+ FuzzilliRunner(d8_path=fuzzer_target_binpath,
+ target_arguments=settings['processArguments'],
+ source_dir=source_dir),
'corpus':
None,
'files':