A set of fuzzers for fuzzing various parts of the Zig standard library. See 'Fuzzing Zig Code Using AFL++' for more information about the particular fuzzing setup used.
Current fuzzers:
tokenizerwhich callsstd.zig.Tokenizer.nextuntil it gets aneoftokenparsewhich callsstd.zig.Ast.parseand thenstd.zig.Ast.renderdeflatewhich callsstd.compress.flate.decompressor().reader().readAllAlloc()deflate-puffwhich compares the results ofpuff.cto Zig'sstd.compress.flate.decompressordeflate-roundtripwhich sends the input throughcompressor, then throughdecompressor, and then checks that the output is the same as the inputjsonwhich callsstd.json.parseFromSlicesinwhich callsstd.math.sinand compares the result to libc'ssin/sinfxzwhich callsstd.compress.xz.decompressxxhashwhich compares the results ofxxhash.cto Zig'sstd.hash.xxhashimplementationzstandardwhich calls thestd.compress.zstddecode,decodeAlloc, anddecompressStreamAPIs.zstandard-comparewhich compares the results of thezstdreference implementation to Zig'sstd.compress.zstd.decompress.decodeimplementationzstandard-compare-allocwhich compares the results of thezstdreference implementation to Zig'sstd.compress.zstd.decompress.decodeAllocimplementationzstandard-compare-streamwhich compares the results of thezstdreference implementation to Zig'sstd.compress.zstd.decompressStreamimplementationtarwhich usesstd.tar.iteratorto simulate an untar operation (but does not write to the filesystem)tar-fswhich callsstd.tar.pipeToFileSystem(and actually writes to the filesystem)
Non-std fuzzers (requires -Dzig-src=/path/to/zig/sources):
markdownwhich calls Autodoc'smarkdown.Parserto parse an input line by linegitwhich callsgit.indexPackon a Git packfile-
Requires a patch (
fuzzers/git.patch) to be applied to upstreamgit.zigso I/O can be avoided. -
To verify the contents of the input packfile (
small.pack):- Create a new empty Git repository (
git init) git unpack-objects <path/to/small.packgit fsck-> note the "dangling commit" ID (which matches the commit checked out below)git checkout 0a9b7c28d992347b3e237bb143c052b177ad388f
- Create a new empty Git repository (
-
Requires AFL++ with afl-clang-lto to be installed (see Compiling AFL++).
Run zig build fuzz-<fuzzer name>, e.g. zig build fuzz-tokenizer
The instrumented fuzzer will be installed to zig-out/bin/fuzz-<fuzzer name>. You'll probably also need to run mkdir outputs (if you're planning on using outputs as an output directory) before fuzzing. Here's a simple example of running the tokenizer fuzzer:
afl-fuzz -i inputs/tokenizer -o outputs/tokenizer -x dictionaries/zig.dict -- ./zig-out/bin/fuzz-tokenizer
(the -x option is not necessary but using a dictionary is recommended if possible)
See AFL++'s 'fuzzing the target' section for more recommendations to improve fuzzing effectiveness (using multiple cores, etc).
If a crash is found during fuzzing, the companion fuzz-<fuzzer name>-debug executable can be used to debug the crash. For example, for the tokenizer fuzzer, a stack trace could be gotten with:
$ ./zig-out/bin/fuzz-tokenizer-debug < 'outputs/tokenizer/default/crashes/id:000000,sig:06,src:000908+000906,time:117053,op:splice,rep:16'
thread 2730086 panic: index out of bounds
/home/ryan/Programming/zig/zig/build/lib/zig/std/zig/tokenizer.zig:408:34: 0x215131 in std.zig.tokenizer.Tokenizer.next (fuzz-tokenizer-debug)
const c = self.buffer[self.index];
^
/home/ryan/Programming/zig/zig/build/lib/zig/std/zig/parse.zig:24:37: 0x20af60 in std.zig.parse.parse (fuzz-tokenizer-debug)
const token = tokenizer.next();
^
...Alternatively, the crash can be debugged via gdb:
gdb -ex 'set args < outputs/tokenizer/default/crashes/id:000000,sig:06,src:000908+000906,time:117053,op:splice,rep:16' ./zig-out/bin/fuzz-tokenizer-debug
Or valgrind:
valgrind ./zig-out/bin/fuzz-tokenizer-debug < 'outputs/tokenizer/default/crashes/id:000000,sig:06,src:000908+000906,time:117053,op:splice,rep:16'
zigescape can also be used to convert inputs into string literals for the creation of test cases (preferrably after using afl-tmin to minimize the input).
- https://github.com/ianic/flate/issues (a bunch of stuff before it was submitted as a PR)
obsoleted Deflate implementations
sin: ziglang/zig#9901
- ziglang/zig#14394 (a whole bunch of stuff during the PR process)
Requires the decodecorpus tool from zstd and the zstandard-verify tool from this repo (can be built with zig build tools). Run the following command to use it to continuously test the zstandard Zig decompressor with generated compressed .zst files:
./tools/zstandard-decodecorpus.sh /path/to/decodecorpus ./zig-out/bin/zstandard-verify
- Clone
https://github.com/AFLplusplus/AFLplusplus(avoid recursively cloning, avoid initializing submodules--they are huge and unnecessary for our purposes) - Make sure
llvm-config --versionmatches the same version that your Zig uses
cd AFLplusplus
make source-only NO_NYX=1
make install
(or sudo make install if needed)