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:
tokenizer
which callsstd.zig.Tokenizer.next
until it gets aneof
tokenparse
which callsstd.zig.Ast.parse
and thenstd.zig.Ast.render
deflate
which callsstd.compress.flate.decompressor().reader().readAllAlloc()
deflate-puff
which compares the results ofpuff.c
to Zig'sstd.compress.flate.decompressor
deflate-roundtrip
which sends the input throughcompressor
, then throughdecompressor
, and then checks that the output is the same as the inputjson
which callsstd.json.parseFromSlice
sin
which callsstd.math.sin
and compares the result to libc'ssin
/sinf
xz
which callsstd.compress.xz.decompress
xxhash
which compares the results ofxxhash.c
to Zig'sstd.hash.xxhash
implementationzstandard
which calls thestd.compress.zstd
decode
,decodeAlloc
, anddecompressStream
APIs.zstandard-compare
which compares the results of thezstd
reference implementation to Zig'sstd.compress.zstd.decompress.decode
implementationzstandard-compare-alloc
which compares the results of thezstd
reference implementation to Zig'sstd.compress.zstd.decompress.decodeAlloc
implementationzstandard-compare-stream
which compares the results of thezstd
reference implementation to Zig'sstd.compress.zstd.decompressStream
implementationtar
which usesstd.tar.iterator
to simulate an untar operation (but does not write to the filesystem)tar-fs
which callsstd.tar.pipeToFileSystem
(and actually writes to the filesystem)
Non-std
fuzzers (requires -Dzig-src=/path/to/zig/sources
):
markdown
which calls Autodoc'smarkdown.Parser
to parse an input line by linegit
which callsgit.indexPack
on a Git packfile-
Requires a patch (
fuzzers/git.patch
) to be applied to upstreamgit.zig
so 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.pack
git 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 --version
matches the same version that your Zig uses
cd AFLplusplus
make source-only NO_NYX=1
make install
(or sudo make install
if needed)