view interps/cfunge/cfunge-src/tools/fuzz-test.sh @ 7945:34fac2ce839a

<moon__> mkx bin/hfs//erro \'You have discovered an eerie cavern. The air aboe the dar kstone floor is alive ith vortices of purple light and dark, boiling clouds. Seemingly bottemless pits mark the surface. "$1" stand below\'
author HackBot
date Sat, 07 May 2016 18:36:03 +0000
parents 859f9b4339e6
children
line wrap: on
line source

#!/usr/bin/env bash
# -*- coding: utf-8 -*-
###########################################################################
#                                                                         #
#  cfunge - A standard-conforming Befunge93/98/109 interpreter in C.      #
#  Copyright (C) 2008-2009  Arvid Norlander                               #
#                                                                         #
#  This program is free software: you can redistribute it and/or modify   #
#  it under the terms of the GNU General Public License as published by   #
#  the Free Software Foundation, either version 3 of the License, or      #
#  (at the proxy's option) any later version. Arvid Norlander is a        #
#  proxy who can decide which future versions of the GNU General Public   #
#  License can be used.                                                   #
#                                                                         #
#  This program is distributed in the hope that it will be useful,        #
#  but WITHOUT ANY WARRANTY; without even the implied warranty of         #
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          #
#  GNU General Public License for more details.                           #
#                                                                         #
#  You should have received a copy of the GNU General Public License      #
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.  #
#                                                                         #
###########################################################################
#
# This script is used for simple fuzz testing, to use it:
# 1) uncomment the line:
#      #define FUZZ_TESTING
#    in global.h
# 2) Disable USE_GC in cmake, or valgrind will fail.
# 4) make
# 5) Run script from top source directory
#    To test a specific fingerprint, run script with that fingerprint as
#    the parameter. Otherwise no fingerprints are tested (just core).
# Note that this script has only been tried on Gentoo Linux 2.6.27 x86_64!
# I got no idea if it works elsewhere.
#
# Note that input/output isn't tested (this script is meant to be run
# non-interactively) and sandbox mode is used (for safety). You can modify the
# script to test in non-sandbox mode if you run fuzz testing in a chroot. How
# is left as an exercise for the reader.
#
# Another note: this script doesn't do much sanity checking on command line
# parameters
#

# Check bash version. We need at least 3.1
# Lets not use anything like =~ here because
# that may not work on old bash versions.
if [[ "${BASH_VERSINFO[0]}${BASH_VERSINFO[1]}" -lt 31 ]]; then
	echo "Sorry your bash version is too old!"
	echo "You need at least version 3.1 of bash."
	echo "Please install a newer version:"
	echo " * Either use your distro's packages."
	echo " * Or see http://www.gnu.org/software/bash/"
	exit 2
fi

die() {
	echo "$1" >&2
	exit 1
}

error() {
	die "ERROR: $1"
}

# Return exit code for signal name
#  $1 Out variable
#  $2 Signal name.
get_exit_code()
{
	local signum retval
	signum=$(kill -l "$2")
	retval=$(( 128 + signum ))
	printf -v "$1" '%s' "$retval"
}

# Set up exit code info, to be used in checkerror() later.
RET_ABRT=
RET_ALRM=
RET_BUS=
RET_INT=
RET_KILL=
RET_SEGV=

get_exit_code RET_ABRT SIGABRT
get_exit_code RET_ALRM SIGALRM
get_exit_code RET_BUS SIGBUS
get_exit_code RET_INT SIGINT
get_exit_code RET_KILL SIGKILL
get_exit_code RET_SEGV SIGSEGV

# Check return code and decide if we should end the script or continue.
checkerror() {
	# Ok
	if [[ $1 -eq 0 ]]; then
		echo " * Exit code was $1, ok"
		return
	# Most likely Ctrl-C
	elif [[ $1 -eq $RET_INT ]]; then
		die " * Exit code was $1 (SIGINT), most likely ctrl-c"
	# abort(), or maybe just "*** glibc detected ***" ones
	elif [[ $1 -eq $RET_BUS ]]; then
		die " * Exit code was $1 (SIGBUS). This is very bad."
	elif [[ $1 -eq $RET_ABRT ]]; then
		die " * Exit code was $1 (SIGABRT). This is usually bad."
	# Ok: ulimit
	elif [[ $1 -eq $RET_KILL ]]; then
		echo -e "\a * Exit code was $1 (SIGKILL): Hopefully due to ulimits. It"
		echo -e '\a   could also be caused by something else. Will continue after'
		echo -e '\a   waiting for 5 seconds to allow you to abort script if you'
		echo -e '\a   see anything indicating it is not due to ulimits.'
		sleep 5
		return
	# SIGSEGV or q
	elif [[ $1 -eq $RET_SEGV ]]; then
		die  " * Exit code was $1 (SIGSEGV). This is very bad."
	# Ok: SIGALRM
	elif [[ $1 -eq $RET_ALRM ]]; then
		echo " * Exit code was $1 (SIGALRM). This is OK."
		return
	# Unknown
	else
		die  " * Exit code was $1 (unknown), probably issues there!"
	fi
}

if [[ ! -d src/fingerprints ]]; then
	error "Run from top source directory please."
fi
if [[ ! -f ./cfunge ]]; then
	error "There must be a copy of the binary in the top source directory."
fi
if ./cfunge -f | grep -q 'This binary uses Boehm GC'; then
	error "This script doesn't work if cfunge was built against Bohem-GC. Please disable USE_GC in cmake and recompile."
fi
if ! ./cfunge -f | grep -q 'This is a fuzz testing build and thus not standard-conforming.'; then
	error "cfunge was built without fuzz testing support. Please see instructions at the top of this script for how to fix."
fi

HAS_VALGRIND=
if hash valgrind >/dev/null 2>&1; then
	HAS_VALGRIND=1
else
	echo -e '\aWarning: You lack valgrind, if possible please install it.'
	echo -e '\aFor now, will continue without valgrind.'
	sleep 2
fi

# List of additional fingerprint instructions to test.
FPRINTINSTRS=""
FPRINT=""

# First parameter is fingerprint name
createfingerprint() {
	echo -n "\"${1:3:1}${1:2:1}${1:1:1}${1:0:1}\"4( "
}

if [[ $1 ]]; then
	echo "Will test fingerprint ${1}."
	FPRINT=$1
	# TODO: This should use *.spec parsing really... Parsing fingerprints.h is
	# legacy code.
	FPRINTINSTRS=$(grep finger_${1}_load src/fingerprints/fingerprints.h | grep -Eo '"[A-Z]+"' | tr -d '"')
fi

# This does not test fingerprints loaded randomly for the simple reason that it is very unlikely any will load.
# Therefore it does instead provide a way to select a fingerprint to test as first parameter.
while true; do
	# Clean file
	> fuzz.tmp
	# Should we load a fingerprint?
	if [[ $FPRINT ]]; then
		createfingerprint "$FPRINT" >> fuzz.tmp
	fi
	echo " * Generating random program"
	# We skip ? because that make things harder to debug, we also skip i, o and = for security reasons.
	cat /dev/urandom | tr -Cd -- '-[:lower:][:digit:]\n\\/ ;",.+*[]{}^<>@`_|:%$#!'\'"${FPRINTINSTRS}" | tr -d 'mhlior' | head -n 100 >> fuzz.tmp

	echo " * Running free standing"
	(./cfunge -S fuzz.tmp); checkerror "$?"

	if [[ $HAS_VALGRIND ]]; then
		echo " * Running under valgrind"
		(valgrind --leak-check=no ./cfunge -S fuzz.tmp) 2> valgnd.output; checkerror "$?"
		grep -Eq "ERROR SUMMARY: 0 errors from 0 contexts \(suppressed: [0-9]+ from 1\)" valgnd.output || die "Valgrind detected issues!"
	else
		echo " * Skipping run under valgrind due to valgrind not being found"
	fi

	echo
done