xref: /isa-l/tools/test_fuzz.sh (revision bde3fc5ff1067f8f6dbd53ba268a13876b64661e)
1#!/usr/bin/env bash
2
3usage ()
4{
5test_ids=$(echo "${llvm_all_ids[*]}" | sed 's/ /, /g')
6cat << EOF
7usage: $0 options
8options:
9   -h                 Help
10   -l, --llvm <n>     Use llvm fuzz tests and run n times 0=just build, -1=skip (default $use_llvm).
11   -a, --afl  <n>     Use AFL fuzz tests and run n times 0=just build, -1=skip (default $use_afl).
12   -t, --time <n>     Run each group of max time <n>[s,h,m,d] - n seconds, hours, minutes or days.
13   -e <exec|rand|all> Run a specific llvm test or [$test_ids, rand, all].
14   -f <file>          Use this file as initial raw input.  Can be repeated.
15   -d <0,1>           Use dump of internal inflate test corpus (default $use_internal_corp).
16   -i <dir>           Fuzz input dir (default $fuzzin_dir).
17   -o <dir>           Fuzz output dir (default $fuzzout_dir).
18EOF
19exit 0
20}
21
22# Defaults
23use_afl=-1
24use_llvm=1
25samp_files=
26use_internal_corp=0
27fuzzin_dir=fuzzin
28fuzzout_dir=fuzzout
29llvm_opts=" -print_final_stats=1"
30afl_timeout_cmd=""
31run_secs=0
32llvm_tests=("igzip_simple_inflate_fuzz_test")
33llvm_all_ids=("simple" "checked" "round_trip")
34llvm_all_tests=("igzip_simple_inflate_fuzz_test" "igzip_checked_inflate_fuzz_test" "igzip_simple_round_trip_fuzz_test")
35
36# Options
37while [ "$1" != "${1##-}" ]; do
38    case $1 in
39	-h | --help)
40	    usage
41	    ;;
42	-t | --time)
43	    run_secs=$(echo $2 | sed -e 's/d$/*24h/' -e 's/h$/*60m/' -e 's/m$/*60/' -e 's/s$//'| bc)
44	    llvm_opts+=" -max_total_time=$run_secs"
45	    afl_timeout_cmd="timeout --preserve-status $run_secs"
46	    echo Run each for $run_secs seconds
47	    shift 2
48	    ;;
49	-a | --afl)
50	    use_afl=$2
51	    shift 2
52	    ;;
53	-l | --llvm)
54	    use_llvm=$2
55	    shift 2
56	    ;;
57	-f)
58	    samp_files+="$2 "
59	    use_internal_corp=0
60	    shift 2
61	    ;;
62	-d)
63	    use_internal_corp=$2
64	    shift 2
65	    ;;
66	-e)
67	    case $2 in
68		all)
69		    llvm_tests=${llvm_all_tests[@]}
70		    ;;
71		rand)
72		    llvm_tests=${llvm_all_tests[$RANDOM % ${#llvm_all_tests[@]} ]}
73		    ;;
74		*)
75		    flag=0
76		    for id_index in "${!llvm_all_ids[@]}"; do
77			 if [[ "${llvm_all_ids[$id_index]}" = "$2" ]]; then
78			     flag=1
79			     llvm_tests[0]="${llvm_all_tests[$id_index]}"
80			     break;
81			 fi
82		    done
83
84		    if [ $flag -eq 0 ]; then
85			test_ids=$(echo "${llvm_all_ids[*]}" | sed 's/ /, /g')
86			echo "Invalid test, valid options: $test_ids, rand, or all"
87			exit 0
88		    fi
89		    ;;
90	    esac
91	    shift 2
92	    ;;
93	-i)
94	    fuzzin_dir=$2
95	    shift 2
96	    ;;
97	-o)
98	    fuzzout_dir=$2
99	    shift 2
100	    ;;
101    esac
102done
103
104set -xe #exit on fail
105
106# Optionally build afl fuzz tests
107if [ $use_afl -ge 0 ]; then
108    echo Build afl fuzz tests
109    if ! command -V afl-gcc > /dev/null; then
110	echo $0 option --afl requires package afl installed
111	exit 0
112    fi
113    make -f Makefile.unx clean
114    make -f Makefile.unx units=igzip CC=afl-gcc other
115fi
116
117# Optionally build llvm fuzz tests
118if [ $use_llvm -ge 0 ]; then
119    echo Build llvm fuzz tests
120    if ( command -V clang++ > /dev/null ); then
121	if (echo int LLVMFuzzerTestOneInput\(\)\{return 0\;\} | clang++ -x c - -fsanitize=fuzzer,address -lpthread -o /dev/null >& /dev/null); then
122	    echo have modern clang
123	    llvm_link_args='FUZZLINK=-fsanitize=fuzzer,address'
124	elif (echo int LLVMFuzzerTestOneInput\(\)\{return 0\;\} | clang++ -x c - -lFuzzer -lpthread -o /dev/null >& /dev/null); then
125	    echo have libFuzzer
126	    llvm_link_args='FUZZLINK=-lFuzzer'
127	else
128	    echo $0 option --llvm requires clang++ and libFuzzer
129	    exit 0
130	fi
131    fi
132    rm -rf bin
133    make -f Makefile.unx units=igzip llvm_fuzz_tests igzip_dump_inflate_corpus CC=clang CXX=clang++ ${llvm_link_args}
134fi
135
136#Create fuzz input/output directories
137mkdir -p $fuzzin_dir
138if [ $use_afl -ge 0 ]; then
139       mkdir -p $fuzzout_dir
140fi
141
142# Optionally fill fuzz input with internal tests corpus
143[ $use_internal_corp -gt 0 ] && ./igzip_dump_inflate_corpus $fuzzin_dir
144
145# Optionally compress input samples as input into fuzz dir
146for f in $samp_files; do
147    echo Using sample file $f
148    f_base=`basename $f`
149    ./igzip_file_perf $f -o $fuzzin_dir/samp_${f_base}_cmp
150done
151
152# Optionally run tests alternately one after the other
153while [ $use_llvm -gt 0 -o $use_afl -gt 0 ]; do
154    if [ $use_afl -gt 0 ]; then
155	echo afl run $use_afl
156	let use_afl--
157	$afl_timeout_cmd afl-fuzz -T "Run inflate $run_secs s" -i $fuzzin_dir -o $fuzzout_dir -M fuzzer1 -- ./igzip_fuzz_inflate @@
158	afl-whatsup $fuzzout_dir
159    fi
160
161    if [ $use_llvm -gt 0 ]; then
162	echo llvm run $use_llvm
163	let use_llvm--
164	for test in $llvm_tests; do
165	    echo "Run llvm test $test"
166	    ./$test $fuzzin_dir $llvm_opts
167	done
168    fi
169done
170
171make -f Makefile.unx clean
172