diff --git a/.github/workflows/fuzzers.yml b/.github/workflows/fuzzers.yml index 69309c55c..8f9eba87a 100644 --- a/.github/workflows/fuzzers.yml +++ b/.github/workflows/fuzzers.yml @@ -19,6 +19,9 @@ jobs: implementations: haswell westmere fallback UBSAN_OPTIONS: halt_on_error=1 MAXLEN: -max_len=4000 + CLANGVERSION: 11 + # which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh) + OPTLEVEL: -O3 steps: - name: Install packages necessary for building @@ -27,7 +30,7 @@ jobs: sudo apt-get install --quiet ninja-build valgrind zip unzip wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 10 + sudo ./llvm.sh $CLANGVERSION - uses: actions/checkout@v1 @@ -51,7 +54,7 @@ jobs: clang++ --version - name: Build all the variants - run: fuzz/build_fuzzer_variants.sh + run: CLANGSUFFIX=-$CLANGVERSION fuzz/build_fuzzer_variants.sh - name: Explore fast (release build, default implementation) run: | @@ -71,7 +74,7 @@ jobs: others=$(find out -type d -not -name $fuzzer -not -name out -not -name cmin) for implementation in $implementations; do export SIMDJSON_FORCE_IMPLEMENTATION=$implementation - build-sanitizers/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=20 $MAXLEN + build-sanitizers$OPTLEVEL/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=20 $MAXLEN done echo now have $(ls out/$fuzzer |wc -l) files in corpus done @@ -82,7 +85,7 @@ jobs: for fuzzer in $implfuzzers; do # get input from everyone else (corpus cross pollination) others=$(find out -type d -not -name $fuzzer -not -name out -not -name cmin) - build-sanitizers/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=20 $MAXLEN + build-sanitizers$OPTLEVEL/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=20 $MAXLEN echo now have $(ls out/$fuzzer |wc -l) files in corpus done diff --git a/fuzz/build_fuzzer_variants.sh b/fuzz/build_fuzzer_variants.sh index 78c51fdc8..322b406c1 100755 --- a/fuzz/build_fuzzer_variants.sh +++ b/fuzz/build_fuzzer_variants.sh @@ -4,17 +4,27 @@ # - different sanitizers # - different build options # - reproduce build, for running through valgrind +# +# Set environment variable CLANGSUFFIX to select clang version (example: "-11") # fail on error -set -eu +set -e unset CXX CC CFLAGS CXXFLAGS LDFLAGS me=$(basename $0) + +if [ -z $CLANGSUFFIX ] ; then + # the default clang version is set low enough to be found on current Debian stable (Buster) + CLANGSUFFIX=-8 +fi + +# detect unset variables +set -u + # common options -CLANGVER=-9 -COMMON="-GNinja -DCMAKE_CXX_COMPILER=clang++$CLANGVER -DCMAKE_C_COMPILER=clang$CLANGVER -DSIMDJSON_BUILD_STATIC=Off -DENABLE_FUZZING=On -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_GIT=Off" +COMMON="-GNinja -DCMAKE_CXX_COMPILER=clang++$CLANGSUFFIX -DCMAKE_C_COMPILER=clang$CLANGSUFFIX -DSIMDJSON_BUILD_STATIC=Off -DENABLE_FUZZING=On -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_GIT=Off" # A replay build, as plain as it gets. For use with valgrind/gdb. variant=replay @@ -33,17 +43,28 @@ fi # A fuzzer with sanitizers. For improved capability to find bugs. -variant=sanitizers +# About the optimization level: (measured for fuzz_atpointer) +# -O0 gives 4000 executions/s +# -O1 gives 20000 executions/s +# -O2 gives 32000 executions/s +# -O3 gives 32000 executions/s +# for reference, the release build (without sanitizers, but with fuzzing instrumentation) +# gives 80000 executions/s. +# A low level is good for debugging. A higher level gets more work done. +# Different levels may uncover different types of bugs, see this interesting +# thread: https://github.com/google/oss-fuzz/issues/2295#issuecomment-481493392 +# Oss-fuzz uses -O1 so it may be relevant to use something else than that, +# to do something oss-fuzz doesn't. +variant=sanitizers-O3 if [ ! -d build-$variant ] ; then mkdir build-$variant cd build-$variant - cmake .. \ $COMMON \ - -DCMAKE_CXX_FLAGS="-fsanitize=fuzzer-no-link,address,undefined -fno-sanitize-recover=undefined" \ - -DCMAKE_C_FLAGS="-fsanitize=fuzzer-no-link,address,undefined -fno-sanitize-recover=undefined" \ + -DCMAKE_CXX_FLAGS="-O3 -fsanitize=fuzzer-no-link,address,undefined -fno-sanitize-recover=undefined" \ + -DCMAKE_C_FLAGS="-O3 -fsanitize=fuzzer-no-link,address,undefined -fno-sanitize-recover=undefined" \ -DCMAKE_BUILD_TYPE=Debug \ -DSIMDJSON_FUZZ_LINKMAIN=Off \ -DSIMDJSON_FUZZ_LDFLAGS="-fsanitize=fuzzer" @@ -52,6 +73,23 @@ variant=sanitizers cd .. fi +variant=sanitizers-O0 + + if [ ! -d build-$variant ] ; then + + mkdir build-$variant + cd build-$variant + cmake .. \ + $COMMON \ + -DCMAKE_CXX_FLAGS="-O0 -fsanitize=fuzzer-no-link,address,undefined -fno-sanitize-recover=undefined" \ + -DCMAKE_C_FLAGS="-O0 -fsanitize=fuzzer-no-link,address,undefined -fno-sanitize-recover=undefined" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DSIMDJSON_FUZZ_LINKMAIN=Off \ + -DSIMDJSON_FUZZ_LDFLAGS="-fsanitize=fuzzer" + + ninja all_fuzzers + cd .. + fi # A fast fuzzer, for fast exploration rather than finding bugs. diff --git a/fuzz/quick_check.sh b/fuzz/quick_check.sh index 0dc30c58f..fce257274 100755 --- a/fuzz/quick_check.sh +++ b/fuzz/quick_check.sh @@ -27,7 +27,11 @@ if [ ! -d out ] ; then tar xf corpus.tar && rm corpus.tar fi -builddir=build-sanitizers +# By default, use the debug friendly variant since this script is intended +# for developers reproducing bugs/validating fixes locally. +builddir=build-sanitizers-O0 +#...but feel free to use this one instead, if you want to build coverage fast. +#builddir=build-fast if [ ! -d $builddir ] ; then fuzz/build_fuzzer_variants.sh