fuzz.sh 2.73 KB
#!/bin/sh
#
# builds the fuzzers, runs old crashes etc
#
# Optional: set environment variable CLANG, otherwise clang is auto detected.
#
# By Paul Dreik 2019-2020 for the boost json project
# License: Boost 1.0

set -e

fuzzdir=$(dirname $0)
me=$(basename $0)

cd $fuzzdir

if [ -z $CLANG ] ; then
    #see if we can find clang
    for clangver in -10 -9 -8 -7 -6 -6.0 "" ;   do
	CLANG=clang++$clangver
	if which $CLANG >/dev/null; then
	    break
	fi
    done
fi

if ! which $CLANG >/dev/null; then
    if ! -x $CLANG; then
	echo $me: sorry, could not find clang $CLANG
	exit 1
    fi
fi
echo "$me: will use this compiler: $CLANG"

# set the maximum size of the input, to avoid
# big inputs which blow up the corpus size
MAXLEN="-max_len=4000"

# If doing fuzzing locally (not in CI), adjust this to utilize more
# of your cpu.
#JOBS="-jobs=32"
JOBS=

# set a timelimit (you may want to adjust this if you run locally)
MAXTIME="-max_total_time=30"

variants="basic_parser parse parser"

for variant in $variants; do

srcfile=fuzz_$variant.cpp
fuzzer=./fuzzer_$variant

if [ ! -e $fuzzer -o $srcfile -nt $fuzzer ] ; then
    # explicitly set BOOST_JSON_STACK_BUFFER_SIZE small so interesting
    # code paths are taken also for small inputs (see https://github.com/CPPAlliance/json/issues/333)
    $CLANG \
        -std=c++17 \
        -O3 \
        -g \
        -fsanitize=fuzzer,address,undefined \
        -fno-sanitize-recover=undefined \
        -I../include \
        -DBOOST_JSON_STACK_BUFFER_SIZE=64  \
        -o $fuzzer \
        ../src/src.cpp \
        $srcfile
fi

# make sure ubsan stops in case anything is found
export UBSAN_OPTIONS="halt_on_error=1"

# make sure the old crashes pass without problems
if [ -d old_crashes/$variant ]; then
  find old_crashes/$variant -type f -print0 |xargs -0 --no-run-if-empty $fuzzer
fi

# make an initial corpus from the test data already in the repo
seedcorpus=seedcorpus/$variant
if [ ! -d $seedcorpus ] ; then
    mkdir -p $seedcorpus
    find ../test -name "*.json" -type f -print0 |xargs -0 --no-run-if-empty cp -f -t $seedcorpus/
fi

# if an old corpus exists, use it
# get it with curl -O --location -J https://bintray.com/pauldreik/boost.json/download_file?file_path=corpus%2Fcorpus.tar
if [ -e corpus.tar ] ; then
  mkdir -p oldcorpus
  tar xf corpus.tar -C oldcorpus || echo "corpus.tar was broken! ignoring it"
  OLDCORPUS=oldcorpus/cmin/$variant
  # in case the old corpus did not have this variant (when adding/renaming a new fuzzer)
  mkdir -p $OLDCORPUS
else
  OLDCORPUS=
fi


# run the fuzzer for a short while
mkdir -p out/$variant
$fuzzer out/$variant $OLDCORPUS $seedcorpus/ $MAXTIME $MAXLEN $JOBS

# minimize the corpus
mkdir -p cmin/$variant
$fuzzer cmin/$variant $OLDCORPUS out/$variant $seedcorpus/ -merge=1 $MAXLEN
done