This is for fuzzing libfmt which is proposed for standardization, so it's extra important that bugs are smoked out.
It has found bugs:
Unfortunately one has to limit the maximum memory allocation, otherwise the fuzzing will soon interrupt after trying to allocate many GB of memory. That is why the submodule does not point to upstream fmt, but instead to a branch in fmt fork which introduces the nice blocks like:
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if(spec.precision>100000) {
throw std::runtime_error("fuzz mode - avoiding large precision");
}
#endif
This macro is the defacto standard for making fuzzing practically possible, see the libFuzzer documentation.
With afl, reaches about 3000 iterations per second on a single core. With libFuzzer, about 200000.
Building with afl and undefined behaviour sanitizer:
mkdir build-afl-ubsan
cd build-afl-ubsan
CXX=afl-g++ CXXFLAGS="-fsanitize=undefined" cmake .. -Dreproduce_mode=on
make
corpus minimization:
afl-cmin -i lots/of/files/ -o corpus/ -- ./reproducer_fuzz_two_args @@
fuzzing:
export UBSAN_OPTIONS=abort_on_error=1
afl-fuzz -i corpus -o out -- ./reproducer_fuzz_two_args @@
mkdir build-libfuzzer-sanitizers
cd build-libfuzzer-sanitizers/
CXX=clang++ CXXFLAGS="-fsanitize=address,undefined -O3" cmake .. -Dreproduce_mode=off
make
mkdir out
./fuzzer_fuzz_two_args out corpus
mkdir build-libfuzzer-plain
cd build-libfuzzer-plain/
CXX=clang++ CXXFLAGS="-O3" cmake .. -Dreproduce_mode=off
make
mkdir -p out corpus
./fuzzer_fuzz_two_args out corpus