tools/clusterfuzz/js_fuzzer/README.md
JavaScript fuzzer for stand-alone shells like D8, Chakra, JSC or Spidermonkey.
Original author: Oliver Chang
This fuzzer may require versions of node that are newer than available on ClusterFuzz, so we use pkg to create a self-contained binary out of this.
You need to install nodejs and npm. Run npm install in this directory.
This fuzzer requires a fuzzing DB. To build one, get the latest web_tests.zip
from gs://clusterfuzz-data/web_tests.zip and unzip it
(note https://crbug.com/40643747 for making this data publicly available).
Then run:
$ mkdir db
$ node build_db.js -i /path/to/web_tests -o db chakra v8 spidermonkey WebKit/JSTests fuzzilli
$ node validate_db.js -i db -o db/index.json
This may take a while. Optionally test the fuzzing DB with:
$ node test_db.js -i db
Then, to build the fuzzer,
$ ./node_modules/.bin/pkg -t node18-linux-x64 .
Replace "linux" with either "win" or "macos" for those platforms.
This builds a binary named ochang_js_fuzzer for Linux / macOS OR
ochang_js_fuzzer.exe for Windows.
Use ./package.sh, ./package.sh win or ./package.sh macos to build and
create the output.zip archive or use these raw commands:
$ mkdir output
$ cd output
$ ln -s ../db db
$ ln -s ../ochang_js_fuzzer run
$ zip -r /path/output.zip *
NOTE: Add .exe to ochang_js_fuzzer and run filename above if archiving
for Windows platform.
Run the tests with:
$ npm test
When test expectations change, generate them with:
$ GENERATE=1 npm test
Tests that fail to parse or show very bad performance can be automatically skipped or soft-skipped with the following script (takes >1h):
$ WEB_TESTS=/path/to/web_tests OUTPUT=/path/to/output/folder ./gen_exceptions.sh
To locally evaluate the fuzzer, set up a work directory as follows:
$ workdir/
$ workdir/app_dir
$ workdir/fuzzer
$ workdir/input
$ workdir/output
The app_dir folder can be a symlink or should contain the bundled
version of d8 with all files required for execution.
Copy the packaged ochang_js_fuzzer executable and the db folder
to the fuzzer directory or use a symlink.
The input directory is the root folder of the corpus, i.e., pointing
to the unzipped data of gs://clusterfuzz-data/web_tests.zip.
The output directory is expected to be empty. It'll contain all
output of the fuzzing session. Start the experiments with:
$ # Around ~40000 corresponds to 24h of fuzzing on a workstation.
$ NUM_RUNS=40000
$ python tools/workbench.py $NUM_RUNS
You can check current stats with:
$ cat workdir/output/stats.json | python -m json.tool
When failures are found, you can forge minimization command lines with:
$ MINIMIZER_PATH=path/to/minimizer
$ python tools/minimize.py $MINIMIZER_PATH
The path should point to a local checkout of the minimizer.
To simulate Clusterfuzz's behavior locally—generating test cases and running
them against a d8 binary to find crashes—use the
tools/run_locally_against_d8.py script.
This script automates:
d8 (applying any generated flags).$ python3 tools/run_locally_against_d8.py [options]
--num-tests <n>: Total number of test cases to generate and run (default: 10000).--num-crashes <n>: Stop execution after finding this many crashes
(default: 10).--d8 <path>: Path to the d8 binary to test (default:
../../../../out/x64.release/d8 relative to script).--crash-dir <path>: Directory where crashing test cases will be saved
(default: workdir/crash/ in js_fuzzer directory).--batch-size <n>: Number of tests to generate in each fuzzer invocation
(default: 100).--extra-flags "<flags>": Extra flags to always pass to d8
(e.g. --extra-flags "--turbofan --allow-natives-syntax").--jobs <n>: Number of parallel d8 jobs to run (default: CPU count).d8 to crash are saved in the
crash/ directory (or the directory specified by --crash-dir). Each crash
artifact includes the .js test file and its corresponding flags-N.js file
if applicable.