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)
Requires AFL++ with afl-clang-lto
to be installed.
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