squeek502/zig-std-lib-fuzzing
A set of fuzzers for fuzzing various parts of the Zig standard library
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 calls std.zig.Tokenizer.next
until it gets an eof
tokenparse
which calls std.zig.Ast.parse
and then std.zig.Ast.render
deflate
which calls std.compress.flate.decompressor().reader().readAllAlloc()
deflate-puff
which compares the results of puff.c
to Zig's std.compress.flate.decompressor
deflate-roundtrip
which sends the input through compressor
, then through decompressor
, and then checks that the output is the same as the inputjson
which calls std.json.parseFromSlice
sin
which calls std.math.sin
and compares the result to libc's sin
/sinf
xz
which calls std.compress.xz.decompress
xxhash
which compares the results of xxhash.c
to Zig's std.hash.xxhash
implementationzstandard
which calls the std.compress.zstd
decode
, decodeAlloc
, and decompressStream
APIs.zstandard-compare
which compares the results of the zstd
reference implementation to Zig's std.compress.zstd.decompress.decode
implementationzstandard-compare-alloc
which compares the results of the zstd
reference implementation to Zig's std.compress.zstd.decompress.decodeAlloc
implementationzstandard-compare-stream
which compares the results of the zstd
reference implementation to Zig's std.compress.zstd.decompressStream
implementationtar
which uses std.tar.iterator
to simulate an untar operation (but does not write to the filesystem)tar-fs
which calls std.tar.pipeToFileSystem
(and actually writes to the filesystem)Non-std
fuzzers (requires -Dzig-src=/path/to/zig/sources
):
markdown
which calls Autodoc's markdown.Parser
to parse an input line by linegit
which calls git.indexPack
on a Git packfileRequires a patch (fuzzers/git.patch
) to be applied to upstream git.zig
so I/O can be avoided.
To verify the contents of the input packfile (small.pack
):
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
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).
std.zig.Tokenizer
std.compress.flate
std.compress.deflate
(second version of Deflate)std.compress.deflate
(first version of Deflate)std.math
std.compress.xz
std.compress.zstandard
std.tar
facebook/zstd
zstandard-verify
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
https://github.com/AFLplusplus/AFLplusplus
(avoid recursively cloning, avoid initializing submodules--they are huge and unnecessary for our purposes)llvm-config --version
matches the same version that your Zig usescd AFLplusplus
make source-only NO_NYX=1
make install
(or sudo make install
if needed)