996
|
1 #!/usr/bin/env bash
|
|
2 # -*- coding: utf-8 -*-
|
|
3 ###########################################################################
|
|
4 # #
|
|
5 # cfunge - A standard-conforming Befunge93/98/109 interpreter in C. #
|
|
6 # Copyright (C) 2008-2009 Arvid Norlander #
|
|
7 # #
|
|
8 # This program is free software: you can redistribute it and/or modify #
|
|
9 # it under the terms of the GNU General Public License as published by #
|
|
10 # the Free Software Foundation, either version 3 of the License, or #
|
|
11 # (at the proxy's option) any later version. Arvid Norlander is a #
|
|
12 # proxy who can decide which future versions of the GNU General Public #
|
|
13 # License can be used. #
|
|
14 # #
|
|
15 # This program is distributed in the hope that it will be useful, #
|
|
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
18 # GNU General Public License for more details. #
|
|
19 # #
|
|
20 # You should have received a copy of the GNU General Public License #
|
|
21 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
|
22 # #
|
|
23 ###########################################################################
|
|
24 #
|
|
25 # This script is used for simple fuzz testing, to use it:
|
|
26 # 1) uncomment the line:
|
|
27 # #define FUZZ_TESTING
|
|
28 # in global.h
|
|
29 # 2) Disable USE_GC in cmake, or valgrind will fail.
|
|
30 # 4) make
|
|
31 # 5) Run script from top source directory
|
|
32 # To test a specific fingerprint, run script with that fingerprint as
|
|
33 # the parameter. Otherwise no fingerprints are tested (just core).
|
|
34 # Note that this script has only been tried on Gentoo Linux 2.6.27 x86_64!
|
|
35 # I got no idea if it works elsewhere.
|
|
36 #
|
|
37 # Note that input/output isn't tested (this script is meant to be run
|
|
38 # non-interactively) and sandbox mode is used (for safety). You can modify the
|
|
39 # script to test in non-sandbox mode if you run fuzz testing in a chroot. How
|
|
40 # is left as an exercise for the reader.
|
|
41 #
|
|
42 # Another note: this script doesn't do much sanity checking on command line
|
|
43 # parameters
|
|
44 #
|
|
45
|
|
46 # Check bash version. We need at least 3.1
|
|
47 # Lets not use anything like =~ here because
|
|
48 # that may not work on old bash versions.
|
|
49 if [[ "${BASH_VERSINFO[0]}${BASH_VERSINFO[1]}" -lt 31 ]]; then
|
|
50 echo "Sorry your bash version is too old!"
|
|
51 echo "You need at least version 3.1 of bash."
|
|
52 echo "Please install a newer version:"
|
|
53 echo " * Either use your distro's packages."
|
|
54 echo " * Or see http://www.gnu.org/software/bash/"
|
|
55 exit 2
|
|
56 fi
|
|
57
|
|
58 die() {
|
|
59 echo "$1" >&2
|
|
60 exit 1
|
|
61 }
|
|
62
|
|
63 error() {
|
|
64 die "ERROR: $1"
|
|
65 }
|
|
66
|
|
67 # Return exit code for signal name
|
|
68 # $1 Out variable
|
|
69 # $2 Signal name.
|
|
70 get_exit_code()
|
|
71 {
|
|
72 local signum retval
|
|
73 signum=$(kill -l "$2")
|
|
74 retval=$(( 128 + signum ))
|
|
75 printf -v "$1" '%s' "$retval"
|
|
76 }
|
|
77
|
|
78 # Set up exit code info, to be used in checkerror() later.
|
|
79 RET_ABRT=
|
|
80 RET_ALRM=
|
|
81 RET_BUS=
|
|
82 RET_INT=
|
|
83 RET_KILL=
|
|
84 RET_SEGV=
|
|
85
|
|
86 get_exit_code RET_ABRT SIGABRT
|
|
87 get_exit_code RET_ALRM SIGALRM
|
|
88 get_exit_code RET_BUS SIGBUS
|
|
89 get_exit_code RET_INT SIGINT
|
|
90 get_exit_code RET_KILL SIGKILL
|
|
91 get_exit_code RET_SEGV SIGSEGV
|
|
92
|
|
93 # Check return code and decide if we should end the script or continue.
|
|
94 checkerror() {
|
|
95 # Ok
|
|
96 if [[ $1 -eq 0 ]]; then
|
|
97 echo " * Exit code was $1, ok"
|
|
98 return
|
|
99 # Most likely Ctrl-C
|
|
100 elif [[ $1 -eq $RET_INT ]]; then
|
|
101 die " * Exit code was $1 (SIGINT), most likely ctrl-c"
|
|
102 # abort(), or maybe just "*** glibc detected ***" ones
|
|
103 elif [[ $1 -eq $RET_BUS ]]; then
|
|
104 die " * Exit code was $1 (SIGBUS). This is very bad."
|
|
105 elif [[ $1 -eq $RET_ABRT ]]; then
|
|
106 die " * Exit code was $1 (SIGABRT). This is usually bad."
|
|
107 # Ok: ulimit
|
|
108 elif [[ $1 -eq $RET_KILL ]]; then
|
|
109 echo -e "\a * Exit code was $1 (SIGKILL): Hopefully due to ulimits. It"
|
|
110 echo -e '\a could also be caused by something else. Will continue after'
|
|
111 echo -e '\a waiting for 5 seconds to allow you to abort script if you'
|
|
112 echo -e '\a see anything indicating it is not due to ulimits.'
|
|
113 sleep 5
|
|
114 return
|
|
115 # SIGSEGV or q
|
|
116 elif [[ $1 -eq $RET_SEGV ]]; then
|
|
117 die " * Exit code was $1 (SIGSEGV). This is very bad."
|
|
118 # Ok: SIGALRM
|
|
119 elif [[ $1 -eq $RET_ALRM ]]; then
|
|
120 echo " * Exit code was $1 (SIGALRM). This is OK."
|
|
121 return
|
|
122 # Unknown
|
|
123 else
|
|
124 die " * Exit code was $1 (unknown), probably issues there!"
|
|
125 fi
|
|
126 }
|
|
127
|
|
128 if [[ ! -d src/fingerprints ]]; then
|
|
129 error "Run from top source directory please."
|
|
130 fi
|
|
131 if [[ ! -f ./cfunge ]]; then
|
|
132 error "There must be a copy of the binary in the top source directory."
|
|
133 fi
|
|
134 if ./cfunge -f | grep -q 'This binary uses Boehm GC'; then
|
|
135 error "This script doesn't work if cfunge was built against Bohem-GC. Please disable USE_GC in cmake and recompile."
|
|
136 fi
|
|
137 if ! ./cfunge -f | grep -q 'This is a fuzz testing build and thus not standard-conforming.'; then
|
|
138 error "cfunge was built without fuzz testing support. Please see instructions at the top of this script for how to fix."
|
|
139 fi
|
|
140
|
|
141 HAS_VALGRIND=
|
|
142 if hash valgrind >/dev/null 2>&1; then
|
|
143 HAS_VALGRIND=1
|
|
144 else
|
|
145 echo -e '\aWarning: You lack valgrind, if possible please install it.'
|
|
146 echo -e '\aFor now, will continue without valgrind.'
|
|
147 sleep 2
|
|
148 fi
|
|
149
|
|
150 # List of additional fingerprint instructions to test.
|
|
151 FPRINTINSTRS=""
|
|
152 FPRINT=""
|
|
153
|
|
154 # First parameter is fingerprint name
|
|
155 createfingerprint() {
|
|
156 echo -n "\"${1:3:1}${1:2:1}${1:1:1}${1:0:1}\"4( "
|
|
157 }
|
|
158
|
|
159 if [[ $1 ]]; then
|
|
160 echo "Will test fingerprint ${1}."
|
|
161 FPRINT=$1
|
|
162 # TODO: This should use *.spec parsing really... Parsing fingerprints.h is
|
|
163 # legacy code.
|
|
164 FPRINTINSTRS=$(grep finger_${1}_load src/fingerprints/fingerprints.h | grep -Eo '"[A-Z]+"' | tr -d '"')
|
|
165 fi
|
|
166
|
|
167 # This does not test fingerprints loaded randomly for the simple reason that it is very unlikely any will load.
|
|
168 # Therefore it does instead provide a way to select a fingerprint to test as first parameter.
|
|
169 while true; do
|
|
170 # Clean file
|
|
171 > fuzz.tmp
|
|
172 # Should we load a fingerprint?
|
|
173 if [[ $FPRINT ]]; then
|
|
174 createfingerprint "$FPRINT" >> fuzz.tmp
|
|
175 fi
|
|
176 echo " * Generating random program"
|
|
177 # We skip ? because that make things harder to debug, we also skip i, o and = for security reasons.
|
|
178 cat /dev/urandom | tr -Cd -- '-[:lower:][:digit:]\n\\/ ;",.+*[]{}^<>@`_|:%$#!'\'"${FPRINTINSTRS}" | tr -d 'mhlior' | head -n 100 >> fuzz.tmp
|
|
179
|
|
180 echo " * Running free standing"
|
|
181 (./cfunge -S fuzz.tmp); checkerror "$?"
|
|
182
|
|
183 if [[ $HAS_VALGRIND ]]; then
|
|
184 echo " * Running under valgrind"
|
|
185 (valgrind --leak-check=no ./cfunge -S fuzz.tmp) 2> valgnd.output; checkerror "$?"
|
|
186 grep -Eq "ERROR SUMMARY: 0 errors from 0 contexts \(suppressed: [0-9]+ from 1\)" valgnd.output || die "Valgrind detected issues!"
|
|
187 else
|
|
188 echo " * Skipping run under valgrind due to valgrind not being found"
|
|
189 fi
|
|
190
|
|
191 echo
|
|
192 done
|