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.renderdeflate which calls std.compress.flate.decompressor().reader().readAllAlloc()deflate-puff which compares the results of puff.c to Zig's std.compress.flate.decompressordeflate-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.parseFromSlicesin which calls std.math.sin and compares the result to libc's sin/sinfxz which calls std.compress.xz.decompressxxhash 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.packgit fsck -> note the "dangling commit" ID (which matches the commit checked out below)git checkout 0a9b7c28d992347b3e237bb143c052b177ad388fRequires 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.Tokenizerstd.compress.flatestd.compress.deflate (second version of Deflate)std.compress.deflate (first version of Deflate)std.mathstd.compress.xzstd.compress.zstandardstd.tarfacebook/zstdzstandard-verifyRequires 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)