diff --git a/utah/scripts/jxyang/RunSafely.sh b/utah/scripts/jxyang/RunSafely.sh new file mode 100644 index 000000000..59570bcda --- /dev/null +++ b/utah/scripts/jxyang/RunSafely.sh @@ -0,0 +1,168 @@ +#!/bin/sh +# +# Program: RunSafely.sh +# +# Synopsis: This script simply runs another program. If the program works +# correctly, this script has no effect, otherwise it will do things +# like print a stack trace of a core dump. It always returns +# "successful" so that tests will continue to be run. +# +# This script funnels stdout and stderr from the program into the +# fourth argument specified, and outputs a .time file which +# contains a timing of the program and the program's exit code. +# +# If the parameter is 0 then this script always returns 0, +# regardless of the actual exit of the . +# If the parameter is non-zero then this script returns +# the exit code of the . If there is an error in getting +# the 's exit code, this script returns 99. +# +# If optional parameters -r -l are +# specified, it execute the program remotely using rsh. +# +# Syntax: +# +# RunSafely.sh [-r ] [-l ] +# +# +# where: +# is the remote host to execute the program +# is the username on the remote host +# is the maximum number of seconds to let the run +# is 1 if the program must exit with 0 return code +# is a file from which standard input is directed +# is a file to which standard output and error are directed +# is the path to the program to run +# are the arguments to pass to the program. +# +if [ $# -lt 4 ]; then + echo "./RunSafely.sh " + exit 1 +fi + +DIR=${0%%`basename $0`} + +RHOST= +RUSER=`id -un` +FLAG=$1 +if [ $1 = "-r" ]; then + RHOST=$2 + shift 2 +fi +if [ $1 = "-l" ]; then + RUSER=$2 + shift 2 +fi + +ULIMIT=$1 +EXITOK=$2 +INFILE=$3 +OUTFILE=$4 +PROGRAM=$5 +shift 5 +SYSTEM=`uname -s` + +ULIMITCMD="" +case $SYSTEM in + CYGWIN*) + ;; + Darwin*) + # Disable core file emission, the script doesn't find it anyway because it is put + # into /cores. + ULIMITCMD="$ULIMITCMD ulimit -c 0;" + ULIMITCMD="$ULIMITCMD ulimit -t $ULIMIT;" + # To prevent infinite loops which fill up the disk, specify a limit on size of + # files being output by the tests. 10 MB should be enough for anybody. ;) + ULIMITCMD="$ULIMITCMD ulimit -f 10485760;" + ;; + *) + ULIMITCMD="$ULIMITCMD ulimit -t $ULIMIT;" + ULIMITCMD="$ULIMITCMD ulimit -c unlimited;" + # To prevent infinite loops which fill up the disk, specify a limit on size of + # files being output by the tests. 10 MB should be enough for anybody. ;) + ULIMITCMD="$ULIMITCMD ulimit -f 10485760;" + + ULIMITCMD="$ULIMITCMD ulimit -m 2000000 -v 2000000;" + #ULIMITCMD="$ULIMITCMD ulimit -m 2000000 -v 2000000;" +esac +rm -f core core.* + +# +# Run the command, timing its execution. +# The standard output and standard error of $PROGRAM should go in $OUTFILE, +# and the standard error of time should go in $OUTFILE.time. Note that the +# return code of the program is appended to the $OUTFILE on an "Exit Val =" +# line. +# +# To get the time program and the specified program different output filenames, +# we tell time to launch a shell which in turn executes $PROGRAM with the +# necessary I/O redirection. +# +PWD=`pwd` +COMMAND="$PROGRAM $*" +if [ "$SYSTEM" = "Darwin" ]; then + COMMAND="${DIR}TimedExec.sh $ULIMIT $PWD $COMMAND" +fi + +if [ "x$RHOST" = x ] ; then + ( sh -c "$ULIMITCMD time -p $COMMAND >$OUTFILE 2>&1 < $INFILE; echo exit \$?" ) 2>&1 \ + | awk -- '\ +BEGIN { cpu = 0.0; } +/^user/ { cpu += $2; print; } +/^sys/ { cpu += $2; print; } +!/^user/ && !/^sys/ { print; } +END { printf("cpu time= %f\n", cpu); }' > ${OUTFILE}.time +else + rm -f "$PWD/${PROGRAM}.command" + rm -f "$PWD/${PROGRAM}.remote" + rm -f "$PWD/${PROGRAM}.remote.time" + echo "$ULIMITCMD cd $PWD; (time -p ($COMMAND > $OUTFILE.remote 2>&1 < $INFILE;); echo exit $?) > $OUTFILE.remote.time 2>&1" > "$PWD/${PROGRAM}.command" + chmod +x "$PWD/${PROGRAM}.command" + + ( rsh -l $RUSER $RHOST "ls $PWD/${PROGRAM}.command" ) > /dev/null 2>&1 + ( rsh -l $RUSER $RHOST "$PWD/${PROGRAM}.command" ) + cat $OUTFILE.remote.time | awk -- '\ +BEGIN { cpu = 0.0; } +/^user/ { cpu += $2; print; } +/^sys/ { cpu += $2; print; } +!/^user/ && !/^sys/ { print; } +END { printf("program %f\n", cpu); }' > ${OUTFILE}.time +sleep 1 +cp -f $OUTFILE.remote $OUTFILE +rm -f $OUTFILE.remote +rm -f $OUTFILE.remote.time +fi + +exitval=`grep '^exit ' $OUTFILE.time | sed -e 's/^exit //'` +if [ -z "$exitval" ] ; then + exitval=99 + echo "TEST $PROGRAM failed: CAN'T GET EXIT CODE!" +fi +echo "exit $exitval" >> $OUTFILE + +if [ "$EXITOK" -ne 0 ] ; then + if test "$exitval" -ne 0 ; then + echo "test $PROGRAM failed: EXIT != 0" + fi +else + exitval=0 +fi + +if ls | egrep "^core" > /dev/null +then + # If we are on a sun4u machine (UltraSparc), then the code we're generating + # is 64 bit code. In that case, use gdb-64 instead of gdb. + myarch=`uname -m` + if [ "$myarch" = "sun4u" ] + then + GDB="gdb-64" + else + GDB=gdb + fi + + corefile=`ls core* | head -n 1` + echo "where 100" > StackTrace.$$ + $GDB -q -batch --command=StackTrace.$$ --core=$corefile $PROGRAM < /dev/null + rm -f StackTrace.$$ $corefile +fi +exit "$exitval" diff --git a/utah/scripts/jxyang/compilers.txt b/utah/scripts/jxyang/compilers.txt new file mode 100644 index 000000000..2bc1e7dc1 --- /dev/null +++ b/utah/scripts/jxyang/compilers.txt @@ -0,0 +1,14 @@ +$COMPILER_HOME/gcc-320/bin/gcc-320 +$COMPILER_HOME/gcc-330/bin/gcc-330 +$COMPILER_HOME/gcc-340/bin/gcc-340 +$COMPILER_HOME/gcc-400/bin/gcc-400 +$COMPILER_HOME/gcc-410/bin/gcc-410 +$COMPILER_HOME/gcc-420/bin/gcc-420 +$COMPILER_HOME/gcc-430/bin/gcc-430 +$COMPILER_HOME/gcc-440/bin/gcc-440 +$COMPILER_HOME/gcc-450/bin/gcc-450 +#$COMPILER_HOME/llvm-gcc-25/bin/llvm-gcc-25 +$COMPILER_HOME/clang-26/bin/clang +$COMPILER_HOME/clang-27/bin/clang +$COMPILER_HOME/clang-28/bin/clang +$COMPILER_HOME/clang-29/bin/clang diff --git a/utah/scripts/jxyang/parallel_test.pl b/utah/scripts/jxyang/parallel_test.pl new file mode 100644 index 000000000..e32664d12 --- /dev/null +++ b/utah/scripts/jxyang/parallel_test.pl @@ -0,0 +1,49 @@ +#!/usr/bin/perl -w + use strict; +use warnings; +#use Sys::CPU; + +sub usage () { + die "usage: parallel_test.pl \n"; +} + +my $CPUS = 2; #Sys::CPU::cpu_count(); + +if (scalar (@ARGV) != 2 || !(-e $ARGV[0]) ) { + usage(); +} +print "looks like we have $CPUS cpus\n"; + +my $CONFIG_FILE = $ARGV[0]; +my $CSMITH_OPTION = $ARGV[1]; +my @ALT_OPTIONS = (); + +if ($CSMITH_OPTION =~ /--no-(.*)/) { + push @ALT_OPTIONS, $CSMITH_OPTION; + push @ALT_OPTIONS, "--$1"; +} +# todo: for options like "max-block-depth 8", try to make +# a list of alternative options including "max-block-depth 2", +# "max-block-depth 4" etc if there is enough CPUs + +my $cpu_per_option = $CPUS / @ALT_OPTIONS; +print "using $cpu_per_option CPU each for options: "; +print @ALT_OPTIONS; +print "\n"; + +for (my $i=0; $i<@ALT_OPTIONS; $i++) { + $ALT_OPTIONS[$i] =~ /--(.*)/; + my $opt = $1; + $opt =~ s/ //g; + for (my $j=0; $j<$cpu_per_option; $j++) { + my $cpuid = $i * $cpu_per_option + $j; + my $dir = "work$cpuid"; + system "rm -rf $dir"; + system "mkdir $dir"; + chdir $dir; + my $cmd = "nohup ../test.pl 0 ../$CONFIG_FILE $ALT_OPTIONS[$i] > ${opt}_output.txt 2>&1 &"; + print "running $cmd on CPU $cpuid\n"; + system $cmd; + chdir ".."; + } +} \ No newline at end of file diff --git a/utah/scripts/jxyang/test.pl b/utah/scripts/jxyang/test.pl new file mode 100644 index 000000000..c3f011f6e --- /dev/null +++ b/utah/scripts/jxyang/test.pl @@ -0,0 +1,349 @@ +#!/usr/bin/perl -w +## +## Copyright (c) 2011 The University of Utah +## All rights reserved. +## +## This file is part of `csmith', a random generator of C programs. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are met: +## +## * Redistributions of source code must retain the above copyright notice, +## this list of conditions and the following disclaimer. +## +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. + +################################################################# + +use strict; +use File::stat; + +################################################################# +#################### user-configurable stuff #################### + +# programs shorter than this many bytes are too boring to test +my $MIN_PROGRAM_SIZE = 8000; + +# kill Csmith after this many seconds +my $CSMITH_TIMEOUT = 90; + +# kill a compiler after this many seconds +my $COMPILER_TIMEOUT = 120; + +# kill a compiler's output after this many seconds +my $PROG_TIMEOUT = 8; + +# extra options here +my $CSMITH_USER_OPTIONS = " --bitfields --packed-struct"; + +################# end user-configurable stuff ################### + +my $RUN_PROGRAM = 0; + +my $CSMITH_HOME = $ENV{"CSMITH_HOME"}; +my $good = 0; +my $crash_bug = 0; +my $wrongcode_bug = 0; +my $csmith_bug = 0; + +my $HEADER = "-I$CSMITH_HOME/runtime"; +my $CYGWIN_HEADER = "-I`cygpath -d ${CSMITH_HOME}/runtime`"; +my $COMPILE_OPTIONS = ""; +my @COMPILERS; + +sub read_value_from_file($$) { + my ($fn, $match) = @_; + open INF, "<$fn" or die; + while (my $line = ) { + $line =~ s/\r?\n?$//; # get rid of LF/CR + if ($line =~ /$match/) { + close INF; + return $1; + } + } + close INF; + return ""; +} + +sub write_bug_desc_to_file($$) { + my ($fn, $desc) = @_; + open OUT, ">>$fn" or die "cannot write to $fn\n"; + print OUT "/* $desc */\n"; + close OUT; +} + +# properly parse the return value from system() +sub runit ($$$) { + my ($cmd, $timeout, $out) = @_; + my $res; + if ($RUN_PROGRAM) { + $res = system "timeout $timeout $cmd > $out 2>&1"; + } else { + $res = system "$cmd > $out 2>&1"; + } + my $success = 0; + if ($? == -1) { + print "can't execute $cmd\n"; + } + elsif ($? & 127) { + print "died while executing $cmd\n"; + } + elsif ($res == -1) { + print "can't execute $cmd\n"; + } + else { + $success = 1; + } + my $exit_value = $? >> 8; + if ($exit_value == 124) { + print "hangs while executing $cmd\n"; + $success = 0; + } + return ($success, $exit_value); +} + +# compile a program and execute +# return code 0: normal; +# 1: compiler crashes; +# 2: compiler hangs; +# 3: executable crashes; +# 4: executable hangs +sub compile_and_run($$$$) { + my ($compiler, $src_file, $exe, $out) = @_; + my $command = "$compiler $src_file $COMPILE_OPTIONS $HEADER -o $exe"; + + my @a = split(" ", $compiler); + # special treatment of MS compiler: convert header path to unix-style + if ($a[0] =~ /cl$/) { + $command = "$compiler $src_file $COMPILE_OPTIONS $CYGWIN_HEADER -o $exe"; + } + + # compile random program + my ($res, $exit_value) = runit($command, $COMPILER_TIMEOUT, "compiler.out"); + # print "after run compiler: $res, $exit_value\n"; + if (($res == 0) || (!(-e $exe))) { + # exit code 124 means time out + return ($exit_value == 124 ? 2 : 1); + } + + # run random program + if ($RUN_PROGRAM) { + ($res, $exit_value) = runit("./$exe", $PROG_TIMEOUT, $out); + # print "after run program: $res, $exit_value\n"; + if (($res == 0) || (!(-e $out))) { + # exit code 124 means time out + return ($exit_value == 124 ? 4 : 3); + } + } + return 0; +} + +# evaluate a random program +# return code: -2: crashes (a likely wrong-code bug) +# -1: hangs (not interesting) +# 0: normal, but found no compiler error (not interesting) +# 1: found compiler crash error(s) +# 2: found compiler wrong code error(s) +sub evaluate_program ($) { + my ($test_file) = @_; + my @checksums; + my @tested_compilers; + my $interesting = 0; + my $i = 0; + foreach my $compiler (@COMPILERS) { + my $out = "out$i.log"; + my $exe = "a.out$i"; + $i++; + my $res = compile_and_run($compiler, $test_file, $exe, $out); + + if ($res) { + if ($res == 1 || $res == 2) { + write_bug_desc_to_file($test_file, + "Compiler error! Can't compile with $compiler $COMPILE_OPTIONS $HEADER"); + $interesting = 1; + } + elsif ($res == 3) { + write_bug_desc_to_file($test_file, "random program crashed!"); + # random program crashes, a likely wrong-code bug, but + # can't rule out the probablity of a Csmith bug + $interesting = -2; + last; + } else { + print "random program hangs!\n"; + # program hangs, not interesting + $interesting = -1; + last; + } + } + else { + if ($RUN_PROGRAM) { + die "cannot find $out.\n" if (!(-e $out)); + my $sum = read_value_from_file($out, "checksum = (.*)"); + $interesting = 2 if + (scalar(@checksums) > 0 && $sum ne $checksums[0]); + push @checksums, $sum; + push @tested_compilers, "$compiler $COMPILE_OPTIONS"; + } + } + } + if ($interesting >= 1) { + if ($interesting == 2) { + write_bug_desc_to_file ($test_file, + "Found checksum difference between compiler implementations"); + for (my $i=0; $i < scalar (@checksums); $i++) { + write_bug_desc_to_file ($test_file, + "$tested_compilers[$i]: $checksums[$i]"); + } + } + write_bug_desc_to_file($test_file, + "please refer to http://embed.cs.utah.edu/csmith/using.html on how to report a bug"); + } + system "rm -f out*.log a.out* test*.obj compiler.out csmith.out"; + return $interesting; +} + +sub test_one ($) { + (my $n) = @_; + my $cfile = "test$n.c"; + my $seed; + my $filesize; + + # run Csmith until generate a big enough program + while (1) { + unlink $cfile; + my $cmd = "$CSMITH_HOME/src/csmith $CSMITH_USER_OPTIONS --output $cfile"; + my ($res, $exitcode) = runit($cmd, $CSMITH_TIMEOUT, "csmith.out"); + # print "after run csmith: $res, $exitcode\n"; + + $seed = read_value_from_file($cfile, "Seed:\\s+([0-9]+)"); + die "Random program $cfile has no seed information!\n" if (!$seed); + + if ($res == 0) { + print "CSMITH BUG FOUND: number $csmith_bug\n"; + $csmith_bug++; + system "cp $cfile csmith_bug_${csmith_bug}.c"; + next; + } + else { + $filesize = stat("$cfile")->size; + # print "$cfile is $filesize bytes\n"; + last if ($filesize >= $MIN_PROGRAM_SIZE); + } + } + + print "seed= $seed, size= $filesize\n"; + + # test if the random program is interesting + my $ret = evaluate_program($cfile); + if ($ret >= 0) { + $good++; + print "GOOD PROGRAM: number $good\n"; + if ($ret == 1) { + print "COMPILER CRASH ERROR FOUND: number $crash_bug\n"; + $crash_bug++; + system "cp $cfile crash${crash_bug}.c"; + } + if ($ret == 2 || $ret == -2) { + print "LIKELY WRONG CODE ERROR FOUND: number $wrongcode_bug\n"; + $wrongcode_bug++; + system "cp $cfile wrong${wrongcode_bug}.c"; + } + } else { + print "BAD PROGRAM: doesn't count towards goal.\n"; + } + unlink $cfile; + return $ret; +} + +sub usage () { + print "usage: test.pl (0 for unlimited) \n"; + exit -1; +} + +########################### main ################################## + +if (!(-f "$CSMITH_HOME/runtime/csmith.h")) { + print "Please point the environment variable CSMITH_HOME to the top-level\n"; + print "directory of your Csmith tree before running this script.\n"; + exit(-1); +} + +my $nargs = scalar(@ARGV); + +if ($nargs == 2) { + # no problem +} elsif ($nargs == 3) { + if ($ARGV[2] eq "--with-wrong-code-bugs") { + # without timeout, we cannot test wrong code bugs + my $r = system("timeout 1 date > /dev/null 2>&1"); + if ($?) { + print "Cannot find timeout on your system. Switch to finding crash bugs only.\n"; + } else { + print "Finding both crash bugs and wrong-code bugs\n"; + $RUN_PROGRAM = 1; + } + } else { + usage(); + } +} else { + usage(); +} + +my $cnt = $ARGV[0]; +usage() unless ($cnt =~ /^[0-9]+$/ && $cnt >= 0); + +my ($second0, $minute0, $hour0, $dayOfMonth, $month) = localtime(); +$month++; +print "start time: $month/$dayOfMonth $hour0:$minute0\n"; + +# figure out what compilers to test +my $infile = $ARGV[1]; +open INF, "<$infile" or die "Cannot read configuration file ${infile}.\n"; +while (my $line = ) { + chomp $line; + if ($line && !($line =~ /^\s*#/)) { + my $res = system ("echo \"int main() { return 0;}\" > foo.c ; $line foo.c > /dev/null 2>&1"); + unlink "foo.c", "a.out"; + die "cannot execute compiler $line\n" if ($res); + push @COMPILERS, $line; + } + + # print out time once per day + my ($second, $minute, $hour, $dayOfMonth, $month) = localtime(); + if ($hour == $hour0 && $minute == $minute0 && $second == $second0) { + $month++; + print "current time: $month/$dayOfMonth $hour:$minute"; + } +} +close INF; + +# MAIN LOOP +my $i = 0; +while ($cnt == 0 || $i < $cnt) { + if (test_one ($i) != -1) { + $i++; + } + print "\n"; +} + +print "Total csmith errors found: $csmith_bug\n"; +print "Total crash errors found: $crash_bug\n"; +if ($RUN_PROGRAM) { + print "Total wrong-code errors found: $wrongcode_bug\n"; +} + +##################################################################