diff options
171 files changed, 3879 insertions, 2979 deletions
diff --git a/.gitignore b/.gitignore index fb468a14..ba543c8a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ cscope.* *.status *.config -*.cfg config.h site.exp + +# Site file for llvm-lit +lit.site.cfg diff --git a/Makefile b/Makefile index 1612efc1..2e02e578 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,12 @@ LEVEL = . include $(LEVEL)/Makefile.config +# The header files are normally installed +# by the install-local target in the top-level +# makefile. This disables installing anything +# in the top-level makefile. +NO_INSTALL=1 + DIRS = lib tools runtime EXTRA_DIST = include diff --git a/Makefile.common b/Makefile.common index 3f60bbec..e5e3c18a 100644 --- a/Makefile.common +++ b/Makefile.common @@ -30,9 +30,17 @@ endif # Needed to build runtime library using clang (gnu89 is the gcc default) C.Flags += -std=gnu89 +# This is filename that KLEE will look for when trying to load klee-uclibc +KLEE_UCLIBC_BCA_NAME="klee-uclibc.bca" + LD.Flags += -L$(STP_ROOT)/lib CXX.Flags += -I$(STP_ROOT)/include -CXX.Flags += -DKLEE_DIR=\"$(PROJ_OBJ_ROOT)\" -DKLEE_LIB_DIR=\"$(PROJ_libdir)\" +CXX.Flags += -DKLEE_DIR=\"$(PROJ_OBJ_ROOT)\" -DKLEE_INSTALL_BIN_DIR=\"$(PROJ_bindir)\" +CXX.Flags += -DKLEE_INSTALL_LIB_DIR=\"$(PROJ_libdir)\" + +ifeq ($(ENABLE_UCLIBC),1) + CXX.Flags += -DKLEE_UCLIBC_BCA_NAME=\"$(KLEE_UCLIBC_BCA_NAME)\" +endif # For STP. CXX.Flags += -DEXT_HASH_MAP diff --git a/Makefile.config.in b/Makefile.config.in index 452cc1a1..a6dcdcaa 100644 --- a/Makefile.config.in +++ b/Makefile.config.in @@ -29,6 +29,12 @@ PROJ_INSTALL_ROOT := @prefix@ STP_ROOT := @STP_ROOT@ +STP_NEEDS_BOOST := @STP_NEEDS_BOOST@ + +ifeq ($(STP_NEEDS_BOOST),1) + UPSTREAM_STP_LINK_FLAGS = @UPSTREAM_STP_LINK_FLAGS@ +endif + ENABLE_METASMT := @ENABLE_METASMT@ METASMT_ROOT := @METASMT_ROOT@ @@ -36,6 +42,8 @@ ENABLE_POSIX_RUNTIME := @ENABLE_POSIX_RUNTIME@ ENABLE_STPLOG := @ENABLE_STPLOG@ ENABLE_UCLIBC := @ENABLE_UCLIBC@ +KLEE_UCLIBC_BCA := @KLEE_UCLIBC_BCA@ + HAVE_SELINUX := @HAVE_SELINUX@ RUNTIME_ENABLE_OPTIMIZED := @RUNTIME_ENABLE_OPTIMIZED@ @@ -66,3 +74,4 @@ LDFLAGS := @LDFLAGS@ -g REQUIRES_RTTI := @REQUIRES_RTTI@ RUNTEST := @RUNTEST@ +TCLSH := @TCLSH@ diff --git a/README.txt b/README.md index 96d60a9e..fd724614 100644 --- a/README.txt +++ b/README.md @@ -1,8 +1,7 @@ -//===----------------------------------------------------------------------===// -// Klee Symbolic Virtual Machine -//===----------------------------------------------------------------------===// +Klee Symbolic Virtual Machine +============================= -klee is a symbolic virtual machine built on top of the LLVM compiler +`klee` is a symbolic virtual machine built on top of the LLVM compiler infrastructure. Currently, there are two primary components: 1. The core symbolic virtual machine engine; this is responsible for @@ -21,4 +20,4 @@ environment that matches a computed test input, including setting up files, pipes, environment variables, and passing command line arguments. -For further information, see the webpage or docs in www/. +For further information, see the [webpage](http://klee.github.io/klee/). diff --git a/autoconf/configure.ac b/autoconf/configure.ac index 4bd79557..c1b1d2b8 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -161,8 +161,7 @@ AC_ARG_WITH(llvm-build-mode, AC_MSG_CHECKING([llvm build mode]) if test X${with_llvm_build_mode} = Xcheck ; then - llvm_configs="`echo $llvm_obj/*/bin/llvm-config`" - dnl This will be true if the user has exactly 1 build mode built + llvm_configs="`ls -1 $llvm_obj/*/bin/llvm-config 2>/dev/null | head -n 1`" if test -x "$llvm_configs" ; then llvm_build_mode="`$llvm_configs --build-mode`" else @@ -342,38 +341,52 @@ dnl User option to enable uClibc support. AC_ARG_WITH(uclibc, AS_HELP_STRING([--with-uclibc], - [Enable use of the klee uclibc at the given path]),,) - -dnl If uclibc wasn't given, check for a uclibc in the current -dnl directory. -if (test X${with_uclibc} = X && test -d uclibc); then - with_uclibc=uclibc -fi + [Enable use of the klee uclibc at the given path (klee-uclibc root directory or libc.a file]),,) dnl Validate uclibc if given. AC_MSG_CHECKING([uclibc]) if (test X${with_uclibc} != X); then - if test ! -d ${with_uclibc}; then - AC_MSG_ERROR([invalid uclibc directory: ${with_uclibc}]) + if test -d ${with_uclibc}; then + dnl Support the legacy way of configuring with + dnl klee-uclibc, i.e. the root klee-uclibc + dnl directory is passed as an argument. + + dnl Make the path absolute + with_uclibc=`cd $with_uclibc 2> /dev/null; pwd` + + dnl create path to libc file + KLEE_UCLIBC_BCA="${with_uclibc}/lib/libc.a" + + if test ! -e "${KLEE_UCLIBC_BCA}"; then + AC_MSG_ERROR([Could not find file ${KLEE_UCLIBC_BCA}]) + fi + elif test -f ${with_uclibc}; then + dnl Support the new way of configuring klee-uclibc + dnl i.e. the built bitcode archive is passed as the + dnl argument. + + dnl Get absolute path to file + _kud=`dirname ${with_uclibc}` + _kud=`cd ${_kud}; pwd 2> /dev/null` + _kuf=`basename ${with_uclibc}` + + KLEE_UCLIBC_BCA="${_kud}/${_kuf}" + else + AC_MSG_ERROR([Could not detect klee-uclibc]) fi - dnl Make the path absolute - with_uclibc=`cd $with_uclibc 2> /dev/null; pwd` + dnl FIXME: Validate the libc.a file - AC_MSG_RESULT([$with_uclibc]) + AC_MSG_RESULT([$KLEE_UCLIBC_BCA]) + AC_SUBST(ENABLE_UCLIBC,[[1]]) + AC_SUBST(KLEE_UCLIBC_BCA) + AC_DEFINE(SUPPORT_KLEE_UCLIBC, [[1]], [klee-uclibc is supported]) else AC_MSG_RESULT([no]) + AC_SUBST(ENABLE_UCLIBC,[[0]]) fi -AC_DEFINE_UNQUOTED(KLEE_UCLIBC, "$with_uclibc", [Path to KLEE's uClibc]) -AC_SUBST(KLEE_UCLIBC) - -if test X${with_uclibc} != X ; then - AC_SUBST(ENABLE_UCLIBC,[[1]]) -else - AC_SUBST(ENABLE_UCLIBC,[[0]]) -fi dnl ************************************************************************** dnl User option to enable the POSIX runtime @@ -483,6 +496,14 @@ AC_CHECK_HEADERS([selinux/selinux.h], AC_SUBST(HAVE_SELINUX, 0)) dnl ************************************************************************** +dnl Test for features +dnl ************************************************************************** +AC_SEARCH_LIBS(mallinfo,malloc, + AC_DEFINE([HAVE_MALLINFO],[1],[Define if mallinfo() is available on this platform.]), + AC_MSG_ERROR([mallinfo() must be supported by your malloc implementation]) + ) + +dnl ************************************************************************** dnl Find an install of STP dnl ************************************************************************** @@ -510,10 +531,30 @@ else ]) CPPFLAGS="$old_CPPFLAGS" + STP_NEEDS_BOOST=0 + + # Try old STP AC_CHECK_LIB(stp, vc_setInterfaceFlags,, [ - AC_MSG_ERROR([Unable to link with libstp]) + STP_NEEDS_BOOST=1 ; AC_MSG_RESULT([Could not link with libstp. Checking if newer STP is being used]) ], -L$stp_root/lib) + dnl Flags for upstream STP which has boost dependency + UPSTREAM_STP_LINK_FLAGS="-lboost_system -lboost_program_options" + if test "X$STP_NEEDS_BOOST" != X0 ; then + # Need to clear cached result + unset ac_cv_lib_stp_vc_setInterfaceFlags + + AC_CHECK_LIB(stp, + vc_setInterfaceFlags,, [ + AC_MSG_ERROR([Unable to link with libstp. Check config.log to see what went wrong]) + ], -L$stp_root/lib $UPSTREAM_STP_LINK_FLAGS ) + + AC_SUBST(UPSTREAM_STP_LINK_FLAGS, $UPSTREAM_STP_LINK_FLAGS) + AC_SUBST(STP_NEEDS_BOOST, $STP_NEEDS_BOOST) + else + AC_MSG_RESULT([Using old STP]) + fi + AC_SUBST(STP_ROOT,$stp_root) fi @@ -551,10 +592,6 @@ else AC_SUBST(REQUIRES_RTTI,[[1]]) fi -dnl ************************************************************************** -dnl * Check for dejagnu -dnl ************************************************************************** -AC_PATH_PROG(RUNTEST, [runtest]) dnl ************************************************************************** dnl * Create the output files diff --git a/configure b/configure index ab148c2c..78e6ac69 100755 --- a/configure +++ b/configure @@ -624,10 +624,11 @@ ac_includes_default="\ ac_subst_vars='LTLIBOBJS LIBOBJS -RUNTEST METASMT_ROOT ENABLE_METASMT STP_ROOT +STP_NEEDS_BOOST +UPSTREAM_STP_LINK_FLAGS CXXCPP ac_ct_CXX CXXFLAGS @@ -648,8 +649,8 @@ RUNTIME_DEBUG_SYMBOLS RUNTIME_DISABLE_ASSERTIONS RUNTIME_ENABLE_OPTIMIZED ENABLE_POSIX_RUNTIME +KLEE_UCLIBC_BCA ENABLE_UCLIBC -KLEE_UCLIBC KLEE_BITCODE_CXX_COMPILER KLEE_BITCODE_C_COMPILER clang_cxx @@ -1372,6 +1373,7 @@ Optional Packages: (Default: auto-detect). If set, --with-llvmcc= must be set too. --with-uclibc Enable use of the klee uclibc at the given path + (klee-uclibc root directory or libc.a file --with-runtime Select build configuration for runtime libraries (default [Release+Asserts]) --with-stp Location of STP installation directory @@ -2660,8 +2662,8 @@ fi $as_echo_n "checking llvm build mode... " >&6; } if test X${with_llvm_build_mode} = Xcheck ; then - llvm_configs="`echo $llvm_obj/*/bin/llvm-config`" - if test -x "$llvm_configs" ; then + llvm_configs="`ls -1 $llvm_obj/*/bin/llvm-config 2>/dev/null | head -n 1`" + if test -x "$llvm_configs" ; then llvm_build_mode="`$llvm_configs --build-mode`" else as_fn_error $? "Could not autodetect build mode" "$LINENO" 5 @@ -2988,43 +2990,48 @@ if test "${with_uclibc+set}" = set; then : fi -if (test X${with_uclibc} = X && test -d uclibc); then - with_uclibc=uclibc -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking uclibc" >&5 $as_echo_n "checking uclibc... " >&6; } if (test X${with_uclibc} != X); then - if test ! -d ${with_uclibc}; then - as_fn_error $? "invalid uclibc directory: ${with_uclibc}" "$LINENO" 5 - fi + if test -d ${with_uclibc}; then - with_uclibc=`cd $with_uclibc 2> /dev/null; pwd` + with_uclibc=`cd $with_uclibc 2> /dev/null; pwd` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_uclibc" >&5 -$as_echo "$with_uclibc" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi + KLEE_UCLIBC_BCA="${with_uclibc}/lib/libc.a" + if test ! -e "${KLEE_UCLIBC_BCA}"; then + as_fn_error $? "Could not find file ${KLEE_UCLIBC_BCA}" "$LINENO" 5 + fi + elif test -f ${with_uclibc}; then + + _kud=`dirname ${with_uclibc}` + _kud=`cd ${_kud}; pwd 2> /dev/null` + _kuf=`basename ${with_uclibc}` + + KLEE_UCLIBC_BCA="${_kud}/${_kuf}" + else + as_fn_error $? "Could not detect klee-uclibc" "$LINENO" 5 + fi -cat >>confdefs.h <<_ACEOF -#define KLEE_UCLIBC "$with_uclibc" -_ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $KLEE_UCLIBC_BCA" >&5 +$as_echo "$KLEE_UCLIBC_BCA" >&6; } + ENABLE_UCLIBC=1 -if test X${with_uclibc} != X ; then - ENABLE_UCLIBC=1 + +$as_echo "#define SUPPORT_KLEE_UCLIBC 1" >>confdefs.h else - ENABLE_UCLIBC=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ENABLE_UCLIBC=0 fi + # Check whether --enable-posix-runtime was given. if test "${enable_posix_runtime+set}" = set; then : enableval=$enable_posix_runtime; @@ -4827,6 +4834,68 @@ fi done +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing mallinfo" >&5 +$as_echo_n "checking for library containing mallinfo... " >&6; } +if ${ac_cv_search_mallinfo+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char mallinfo (); +int +main () +{ +return mallinfo (); + ; + return 0; +} +_ACEOF +for ac_lib in '' malloc; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_search_mallinfo=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_mallinfo+:} false; then : + break +fi +done +if ${ac_cv_search_mallinfo+:} false; then : + +else + ac_cv_search_mallinfo=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_mallinfo" >&5 +$as_echo "$ac_cv_search_mallinfo" >&6; } +ac_res=$ac_cv_search_mallinfo +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define HAVE_MALLINFO 1" >>confdefs.h + +else + as_fn_error $? "mallinfo() must be supported by your malloc implementation" "$LINENO" 5 + +fi + + # Check whether --with-stp was given. @@ -4863,6 +4932,9 @@ fi CPPFLAGS="$old_CPPFLAGS" + STP_NEEDS_BOOST=0 + + # Try old STP { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vc_setInterfaceFlags in -lstp" >&5 $as_echo_n "checking for vc_setInterfaceFlags in -lstp... " >&6; } if ${ac_cv_lib_stp_vc_setInterfaceFlags+:} false; then : @@ -4908,11 +4980,76 @@ _ACEOF else - as_fn_error $? "Unable to link with libstp" "$LINENO" 5 + STP_NEEDS_BOOST=1 ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Could not link with libstp. Checking if newer STP is being used" >&5 +$as_echo "Could not link with libstp. Checking if newer STP is being used" >&6; } + +fi + + + UPSTREAM_STP_LINK_FLAGS="-lboost_system -lboost_program_options" + if test "X$STP_NEEDS_BOOST" != X0 ; then + # Need to clear cached result + unset ac_cv_lib_stp_vc_setInterfaceFlags + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vc_setInterfaceFlags in -lstp" >&5 +$as_echo_n "checking for vc_setInterfaceFlags in -lstp... " >&6; } +if ${ac_cv_lib_stp_vc_setInterfaceFlags+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lstp -L$stp_root/lib $UPSTREAM_STP_LINK_FLAGS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char vc_setInterfaceFlags (); +int +main () +{ +return vc_setInterfaceFlags (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_stp_vc_setInterfaceFlags=yes +else + ac_cv_lib_stp_vc_setInterfaceFlags=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_stp_vc_setInterfaceFlags" >&5 +$as_echo "$ac_cv_lib_stp_vc_setInterfaceFlags" >&6; } +if test "x$ac_cv_lib_stp_vc_setInterfaceFlags" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSTP 1 +_ACEOF + + LIBS="-lstp $LIBS" + +else + + as_fn_error $? "Unable to link with libstp. Check config.log to see what went wrong" "$LINENO" 5 fi + UPSTREAM_STP_LINK_FLAGS=$UPSTREAM_STP_LINK_FLAGS + + STP_NEEDS_BOOST=$STP_NEEDS_BOOST + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using old STP" >&5 +$as_echo "Using old STP" >&6; } + fi + STP_ROOT=$stp_root fi @@ -4985,46 +5122,6 @@ $as_echo "#define SUPPORT_METASMT 1" >>confdefs.h fi -# Extract the first word of "runtest", so it can be a program name with args. -set dummy runtest; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_RUNTEST+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $RUNTEST in - [\\/]* | ?:[\\/]*) - ac_cv_path_RUNTEST="$RUNTEST" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_RUNTEST="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -RUNTEST=$ac_cv_path_RUNTEST -if test -n "$RUNTEST"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUNTEST" >&5 -$as_echo "$RUNTEST" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - ac_config_commands="$ac_config_commands Makefile" diff --git a/examples/get_sign/get_sign.c b/examples/get_sign/get_sign.c index a97ac375..fd2ad9f2 100644 --- a/examples/get_sign/get_sign.c +++ b/examples/get_sign/get_sign.c @@ -2,6 +2,7 @@ * First KLEE tutorial: testing a small function */ +#include <klee/klee.h> int get_sign(int x) { if (x == 0) diff --git a/include/klee/Config/config.h.in b/include/klee/Config/config.h.in index 0a94de8f..5e49e35d 100644 --- a/include/klee/Config/config.h.in +++ b/include/klee/Config/config.h.in @@ -12,6 +12,9 @@ /* Define to 1 if you have the `stp' library (-lstp). */ #undef HAVE_LIBSTP +/* Define if mallinfo() is available on this platform. */ +#undef HAVE_MALLINFO + /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H @@ -45,9 +48,6 @@ /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H -/* Path to KLEE's uClibc */ -#undef KLEE_UCLIBC - /* LLVM version is release (instead of development) */ #undef LLVM_IS_RELEASE @@ -81,6 +81,9 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* klee-uclibc is supported */ +#undef SUPPORT_KLEE_UCLIBC + /* Supporting metaSMT API */ #undef SUPPORT_METASMT diff --git a/include/klee/ExecutionState.h b/include/klee/ExecutionState.h index 720488cc..824fbed5 100644 --- a/include/klee/ExecutionState.h +++ b/include/klee/ExecutionState.h @@ -32,7 +32,7 @@ namespace klee { class PTreeNode; struct InstructionInfo; -std::ostream &operator<<(std::ostream &os, const MemoryMap &mm); +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const MemoryMap &mm); struct StackFrame { KInstIterator caller; @@ -137,7 +137,7 @@ public: } bool merge(const ExecutionState &b); - void dumpStack(std::ostream &out) const; + void dumpStack(llvm::raw_ostream &out) const; }; } diff --git a/include/klee/Expr.h b/include/klee/Expr.h index 4bebd521..c78cd690 100644 --- a/include/klee/Expr.h +++ b/include/klee/Expr.h @@ -17,13 +17,15 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" +#include <sstream> #include <set> #include <vector> -#include <iosfwd> // FIXME: Remove this!!! namespace llvm { class Type; + class raw_ostream; } namespace klee { @@ -181,7 +183,7 @@ public: virtual unsigned getNumKids() const = 0; virtual ref<Expr> getKid(unsigned i) const = 0; - virtual void print(std::ostream &os) const; + virtual void print(llvm::raw_ostream &os) const; /// dump - Print the expression to stderr. void dump() const; @@ -197,8 +199,10 @@ public: typedef llvm::DenseSet<std::pair<const Expr *, const Expr *> > ExprEquivSet; int compare(const Expr &b, ExprEquivSet &equivs) const; int compare(const Expr &b) const { - ExprEquivSet equivs; - return compare(b, equivs); + static ExprEquivSet equivs; + int r = compare(b, equivs); + equivs.clear(); + return r; } virtual int compareContents(const Expr &b) const { return 0; } @@ -219,8 +223,8 @@ public: /* Static utility methods */ - static void printKind(std::ostream &os, Kind k); - static void printWidth(std::ostream &os, Expr::Width w); + static void printKind(llvm::raw_ostream &os, Kind k); + static void printWidth(llvm::raw_ostream &os, Expr::Width w); /// returns the smallest number of bytes in which the given width fits static inline unsigned getMinBytesForWidth(Width w) { @@ -289,15 +293,34 @@ inline bool operator>=(const Expr &lhs, const Expr &rhs) { // Printing operators -inline std::ostream &operator<<(std::ostream &os, const Expr &e) { +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Expr &e) { e.print(os); return os; } -inline std::ostream &operator<<(std::ostream &os, const Expr::Kind kind) { +// XXX the following macro is to work around the ExprTest unit test compile error +#ifndef LLVM_29_UNITTEST +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Expr::Kind kind) { Expr::printKind(os, kind); return os; } +#endif + +inline std::stringstream &operator<<(std::stringstream &os, const Expr &e) { + std::string str; + llvm::raw_string_ostream TmpStr(str); + e.print(TmpStr); + os << TmpStr.str(); + return os; +} + +inline std::stringstream &operator<<(std::stringstream &os, const Expr::Kind kind) { + std::string str; + llvm::raw_string_ostream TmpStr(str); + Expr::printKind(TmpStr, kind); + os << TmpStr.str(); + return os; +} // Terminal Exprs @@ -585,7 +608,9 @@ public: /// a symbolic array. If non-empty, this size of this array is equivalent to /// the array size. const std::vector< ref<ConstantExpr> > constantValues; - + + Expr::Width domain, range; + public: /// Array - Construct a new array object. /// @@ -596,9 +621,11 @@ public: /// distinguished once printed. Array(const std::string &_name, uint64_t _size, const ref<ConstantExpr> *constantValuesBegin = 0, - const ref<ConstantExpr> *constantValuesEnd = 0) + const ref<ConstantExpr> *constantValuesEnd = 0, + Expr::Width _domain = Expr::Int32, Expr::Width _range = Expr::Int8) : name(_name), size(_size), - constantValues(constantValuesBegin, constantValuesEnd) { + constantValues(constantValuesBegin, constantValuesEnd), + domain(_domain), range(_range) { assert((isSymbolicArray() || constantValues.size() == size) && "Invalid size for constant array!"); computeHash(); @@ -614,8 +641,8 @@ public: bool isSymbolicArray() const { return constantValues.empty(); } bool isConstantArray() const { return !isSymbolicArray(); } - Expr::Width getDomain() const { return Expr::Int32; } - Expr::Width getRange() const { return Expr::Int8; } + Expr::Width getDomain() const { return domain; } + Expr::Width getRange() const { return range; } unsigned computeHash(); unsigned hash() const { return hashValue; } @@ -669,15 +696,15 @@ public: static ref<Expr> create(const UpdateList &updates, ref<Expr> i); - Width getWidth() const { return Expr::Int8; } + Width getWidth() const { assert(updates.root); return updates.root->getRange(); } Kind getKind() const { return Read; } unsigned getNumKids() const { return numKids; } - ref<Expr> getKid(unsigned i) const { return !i ? index : 0; } + ref<Expr> getKid(unsigned i) const { return !i ? index : 0; } int compareContents(const Expr &b) const; - virtual ref<Expr> rebuild(ref<Expr> kids[]) const { + virtual ref<Expr> rebuild(ref<Expr> kids[]) const { return create(updates, kids[0]); } @@ -685,7 +712,7 @@ public: private: ReadExpr(const UpdateList &_updates, const ref<Expr> &_index) : - updates(_updates), index(_index) {} + updates(_updates), index(_index) { assert(updates.root); } public: static bool classof(const Expr *E) { diff --git a/include/klee/Internal/ADT/TreeStream.h b/include/klee/Internal/ADT/TreeStream.h index 63e49dbb..1494aa76 100644 --- a/include/klee/Internal/ADT/TreeStream.h +++ b/include/klee/Internal/ADT/TreeStream.h @@ -11,7 +11,6 @@ #define __UTIL_TREESTREAM_H__ #include <string> -#include <iostream> #include <vector> namespace klee { diff --git a/include/klee/Internal/Module/KModule.h b/include/klee/Internal/Module/KModule.h index 86be131b..80672b5e 100644 --- a/include/klee/Internal/Module/KModule.h +++ b/include/klee/Internal/Module/KModule.h @@ -110,6 +110,13 @@ namespace klee { Cell *constantTable; + // Functions which are part of KLEE runtime + std::set<const llvm::Function*> internalFunctions; + + private: + // Mark function with functionName as part of the KLEE runtime + void addInternalFunction(const char* functionName); + public: KModule(llvm::Module *_module); ~KModule(); diff --git a/include/klee/Internal/System/MemoryUsage.h b/include/klee/Internal/System/MemoryUsage.h new file mode 100644 index 00000000..e8e5d769 --- /dev/null +++ b/include/klee/Internal/System/MemoryUsage.h @@ -0,0 +1,21 @@ +//===-- MemoryUsage.h -------------------------------------------*- C++ -*-===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef KLEE_UTIL_MEMORYUSAGE_H +#define KLEE_UTIL_MEMORYUSAGE_H + +#include <cstddef> + +namespace klee { + namespace util { + size_t GetTotalMallocUsage(); + } +} + +#endif diff --git a/include/klee/Interpreter.h b/include/klee/Interpreter.h index e93284d6..abd454b1 100644 --- a/include/klee/Interpreter.h +++ b/include/klee/Interpreter.h @@ -19,6 +19,8 @@ struct KTest; namespace llvm { class Function; class Module; +class raw_ostream; +class raw_fd_ostream; } namespace klee { @@ -31,10 +33,10 @@ public: InterpreterHandler() {} virtual ~InterpreterHandler() {} - virtual std::ostream &getInfoStream() const = 0; + virtual llvm::raw_ostream &getInfoStream() const = 0; virtual std::string getOutputFilename(const std::string &filename) = 0; - virtual std::ostream *openOutputFile(const std::string &filename) = 0; + virtual llvm::raw_fd_ostream *openOutputFile(const std::string &filename) = 0; virtual void incPathsExplored() = 0; diff --git a/include/klee/util/ArrayExprHash.h b/include/klee/util/ArrayExprHash.h index 9a527bcd..1e5ffc2e 100644 --- a/include/klee/util/ArrayExprHash.h +++ b/include/klee/util/ArrayExprHash.h @@ -132,4 +132,4 @@ void ArrayExprHash<T>::hashUpdateNodeExpr(const UpdateNode* un, T& exp) } -#endif \ No newline at end of file +#endif diff --git a/include/klee/util/Assignment.h b/include/klee/util/Assignment.h index 838d03bd..63df4b65 100644 --- a/include/klee/util/Assignment.h +++ b/include/klee/util/Assignment.h @@ -67,15 +67,16 @@ namespace klee { inline ref<Expr> Assignment::evaluate(const Array *array, unsigned index) const { + assert(array); bindings_ty::const_iterator it = bindings.find(array); if (it!=bindings.end() && index<it->second.size()) { - return ConstantExpr::alloc(it->second[index], Expr::Int8); + return ConstantExpr::alloc(it->second[index], array->getRange()); } else { if (allowFreeValues) { return ReadExpr::create(UpdateList(array, 0), - ConstantExpr::alloc(index, Expr::Int32)); + ConstantExpr::alloc(index, array->getDomain())); } else { - return ConstantExpr::alloc(0, Expr::Int8); + return ConstantExpr::alloc(0, array->getRange()); } } } diff --git a/include/klee/util/ExprPPrinter.h b/include/klee/util/ExprPPrinter.h index 4d1930d8..622b0e80 100644 --- a/include/klee/util/ExprPPrinter.h +++ b/include/klee/util/ExprPPrinter.h @@ -12,6 +12,9 @@ #include "klee/Expr.h" +namespace llvm { + class raw_ostream; +} namespace klee { class ConstraintManager; @@ -20,11 +23,12 @@ namespace klee { ExprPPrinter() {} public: - static ExprPPrinter *create(std::ostream &os); + static ExprPPrinter *create(llvm::raw_ostream &os); virtual ~ExprPPrinter() {} virtual void setNewline(const std::string &newline) = 0; + virtual void setForceNoLineBreaks(bool forceNoLineBreaks) = 0; virtual void reset() = 0; virtual void scan(const ref<Expr> &e) = 0; virtual void print(const ref<Expr> &e, unsigned indent=0) = 0; @@ -44,7 +48,7 @@ namespace klee { /// printOne - Pretty print a single expression prefixed by a /// message and followed by a line break. - static void printOne(std::ostream &os, const char *message, + static void printOne(llvm::raw_ostream &os, const char *message, const ref<Expr> &e); /// printSingleExpr - Pretty print a single expression. @@ -54,12 +58,12 @@ namespace klee { /// Note that if the output stream is not positioned at the /// beginning of a line then printing will not resume at the /// correct position following any output line breaks. - static void printSingleExpr(std::ostream &os, const ref<Expr> &e); + static void printSingleExpr(llvm::raw_ostream &os, const ref<Expr> &e); - static void printConstraints(std::ostream &os, + static void printConstraints(llvm::raw_ostream &os, const ConstraintManager &constraints); - static void printQuery(std::ostream &os, + static void printQuery(llvm::raw_ostream &os, const ConstraintManager &constraints, const ref<Expr> &q, const ref<Expr> *evalExprsBegin = 0, diff --git a/include/klee/util/ExprRangeEvaluator.h b/include/klee/util/ExprRangeEvaluator.h index 34b85520..fea30b5b 100644 --- a/include/klee/util/ExprRangeEvaluator.h +++ b/include/klee/util/ExprRangeEvaluator.h @@ -102,7 +102,7 @@ T ExprRangeEvaluator<T>::evaluate(const ref<Expr> &e) { const ReadExpr *re = cast<ReadExpr>(e); T index = evaluate(re->index); - assert(re->getWidth()==Expr::Int8 && "unexpected multibyte read"); + assert(re->updates.root && re->getWidth() == re->updates.root->range && "unexpected multibyte read"); return evalRead(re->updates, index); } diff --git a/include/klee/util/ExprSMTLIBLetPrinter.h b/include/klee/util/ExprSMTLIBLetPrinter.h index 56c8f008..dd97e0d5 100644 --- a/include/klee/util/ExprSMTLIBLetPrinter.h +++ b/include/klee/util/ExprSMTLIBLetPrinter.h @@ -1,4 +1,5 @@ -//===-- ExprSMTLIBLetPrinter.h ------------------------------------------*- C++ -*-===// +//===-- ExprSMTLIBLetPrinter.h ------------------------------------------*- C++ +//-*-===// // // The KLEE Symbolic Virtual Machine // @@ -11,63 +12,62 @@ #ifndef EXPRSMTLETPRINTER_H_ #define EXPRSMTLETPRINTER_H_ -namespace klee -{ - /// This printer behaves like ExprSMTLIBPrinter except that it will abbreviate expressions - /// using the (let) SMT-LIBv2 command. Expression trees that appear two or more times in the Query - /// passed to setQuery() will be abbreviated. - /// - /// This class should be used just like ExprSMTLIBPrinter. - class ExprSMTLIBLetPrinter : public ExprSMTLIBPrinter - { - public: - ExprSMTLIBLetPrinter(); - virtual ~ExprSMTLIBLetPrinter() { } - virtual void generateOutput(); - protected: - virtual void scan(const ref<Expr>& e); - virtual void reset(); - virtual void generateBindings(); - void printExpression(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort); - void printLetExpression(); +namespace klee { +/// This printer behaves like ExprSMTLIBPrinter except that it will abbreviate +/// expressions +/// using the (let) SMT-LIBv2 command. Expression trees that appear two or more +/// times in the Query +/// passed to setQuery() will be abbreviated. +/// +/// This class should be used just like ExprSMTLIBPrinter. +class ExprSMTLIBLetPrinter : public ExprSMTLIBPrinter { +public: + ExprSMTLIBLetPrinter(); + virtual ~ExprSMTLIBLetPrinter() {} + virtual void generateOutput(); - private: - ///Let expression binding number map. - std::map<const ref<Expr>,unsigned int> bindings; +protected: + virtual void scan(const ref<Expr> &e); + virtual void reset(); + virtual void generateBindings(); + void printExpression(const ref<Expr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT expectedSort); + void printLetExpression(); - /* These are effectively expression counters. - * firstEO - first Occurrence of expression contains - * all expressions that occur once. It is - * only used to help us fill twoOrMoreOE - * - * twoOrMoreEO - Contains occur all expressions that - * that occur two or more times. These - * are the expressions that will be - * abbreviated by using (let () ()) expressions. - * - * - * - */ - std::set<ref<Expr> > firstEO, twoOrMoreEO; +private: + /// Let expression binding number map. + std::map<const ref<Expr>, unsigned int> bindings; - ///This is the prefix string used for all abbreviations in (let) expressions. - static const char BINDING_PREFIX[]; + /* These are effectively expression counters. + * firstEO - first Occurrence of expression contains + * all expressions that occur once. It is + * only used to help us fill twoOrMoreOE + * + * twoOrMoreEO - Contains occur all expressions that + * that occur two or more times. These + * are the expressions that will be + * abbreviated by using (let () ()) expressions. + * + * + * + */ + std::set<ref<Expr> > firstEO, twoOrMoreEO; - /* This is needed during un-abbreviated printing. - * Because we have overloaded printExpression() - * the parent will call it and will abbreviate - * when we don't want it to. This bool allows us - * to switch it on/off easily. - */ - bool disablePrintedAbbreviations; + /// This is the prefix string used for all abbreviations in (let) expressions. + static const char BINDING_PREFIX[]; + /* This is needed during un-abbreviated printing. + * Because we have overloaded printExpression() + * the parent will call it and will abbreviate + * when we don't want it to. This bool allows us + * to switch it on/off easily. + */ + bool disablePrintedAbbreviations; +}; - - }; - - ///Create a SMT-LIBv2 printer based on command line options - ///The caller is responsible for deleting the printer - ExprSMTLIBPrinter* createSMTLIBPrinter(); +/// Create a SMT-LIBv2 printer based on command line options +/// The caller is responsible for deleting the printer +ExprSMTLIBPrinter *createSMTLIBPrinter(); } #endif /* EXPRSMTLETPRINTER_H_ */ diff --git a/include/klee/util/ExprSMTLIBPrinter.h b/include/klee/util/ExprSMTLIBPrinter.h index 83f48eb6..8b072242 100644 --- a/include/klee/util/ExprSMTLIBPrinter.h +++ b/include/klee/util/ExprSMTLIBPrinter.h @@ -1,4 +1,5 @@ -//===-- ExprSMTLIBPrinter.h ------------------------------------------*- C++ -*-===// +//===-- ExprSMTLIBPrinter.h ------------------------------------------*- C++ +//-*-===// // // The KLEE Symbolic Virtual Machine // @@ -10,7 +11,6 @@ #ifndef KLEE_EXPRSMTLIBPRINTER_H #define KLEE_EXPRSMTLIBPRINTER_H -#include <ostream> #include <string> #include <set> #include <map> @@ -19,304 +19,330 @@ #include <klee/util/PrintContext.h> #include <klee/Solver.h> +namespace llvm { +class raw_ostream; +} + namespace klee { - ///Base Class for SMTLIBv2 printer for KLEE Queries. It uses the QF_ABV logic. Note however the logic can be - ///set to QF_AUFBV because some solvers (e.g. STP) complain if this logic is set to QF_ABV. - /// - ///This printer does not abbreviate expressions. The printer ExprSMTLIBLetPrinter does though. - /// - /// It is intended to be used as follows - /// -# Create instance of this class - /// -# Set output ( setOutput() ) - /// -# Set query to print ( setQuery() ) - /// -# Set options using the methods prefixed with the word "set". - /// -# Call generateOutput() +/// Base Class for SMTLIBv2 printer for KLEE Queries. It uses the QF_ABV logic. +/// Note however the logic can be +/// set to QF_AUFBV because some solvers (e.g. STP) complain if this logic is +/// set to QF_ABV. +/// +/// This printer does not abbreviate expressions. The printer +/// ExprSMTLIBLetPrinter does though. +/// +/// It is intended to be used as follows +/// -# Create instance of this class +/// -# Set output ( setOutput() ) +/// -# Set query to print ( setQuery() ) +/// -# Set options using the methods prefixed with the word "set". +/// -# Call generateOutput() +/// +/// The class can then be used again on another query ( setQuery() ). +/// The options set are persistent across queries (apart from +/// setArrayValuesToGet() and PRODUCE_MODELS). +/// +/// +/// Note that in KLEE at the lowest level the solver checks for validity of the +/// query, i.e. +/// +/// \f[ \forall X constraints(X) \to query(X) \f] +/// +/// Where \f$X\f$ is some assignment, \f$constraints(X)\f$ are the constraints +/// in the query and \f$query(X)\f$ is the query expression. +/// If the above formula is true the query is said to be **valid**, otherwise it +/// is +/// **invalid**. +/// +/// The SMTLIBv2 language works in terms of satisfiability rather than validity +/// so instead +/// this class must ask the equivalent query but in terms of satisfiability +/// which is: +/// +/// \f[ \lnot \exists X constraints(X) \land \lnot query(X) \f] +/// +/// The printed SMTLIBv2 query actually asks the following: +/// +/// \f[ \exists X constraints(X) \land \lnot query(X) \f] +/// Hence the printed SMTLIBv2 query will just assert the constraints and the +/// negation +/// of the query expression. +/// +/// If a SMTLIBv2 solver says the printed query is satisfiable the then original +/// query passed to this class was **invalid** and if a SMTLIBv2 solver says the +/// printed +/// query is unsatisfiable then the original query passed to this class was +/// **valid**. +/// +class ExprSMTLIBPrinter { +public: + /// Different SMTLIBv2 logics supported by this class + /// \sa setLogic() + enum SMTLIBv2Logic { + QF_ABV, ///< Logic using Theory of Arrays and Theory of Bitvectors + QF_AUFBV ///< Logic using Theory of Arrays and Theory of Bitvectors and has + ///uninterpreted functions + }; + + /// Different SMTLIBv2 options that have a boolean value that can be set + /// \sa setSMTLIBboolOption + enum SMTLIBboolOptions { + PRINT_SUCCESS, ///< print-success SMTLIBv2 option + PRODUCE_MODELS, ///< produce-models SMTLIBv2 option + INTERACTIVE_MODE ///< interactive-mode SMTLIBv2 option + }; + + /// Different SMTLIBv2 bool option values + /// \sa setSMTLIBboolOption + enum SMTLIBboolValues { + OPTION_TRUE, ///< Set option to true + OPTION_FALSE, ///< Set option to false + OPTION_DEFAULT ///< Use solver's defaults (the option will not be set in + ///output) + }; + + enum ConstantDisplayMode { + BINARY, ///< Display bit vector constants in binary e.g. #b00101101 + HEX, ///< Display bit vector constants in Hexidecimal e.g.#x2D + DECIMAL ///< Display bit vector constants in Decimal e.g. (_ bv45 8) + }; + + /// Different supported SMTLIBv2 sorts (a.k.a type) in QF_AUFBV + enum SMTLIB_SORT { SORT_BITVECTOR, SORT_BOOL }; + + /// Allows the way Constant bitvectors are printed to be changed. + /// This setting is persistent across queries. + /// \return true if setting the mode was successful + bool setConstantDisplayMode(ConstantDisplayMode cdm); + + ConstantDisplayMode getConstantDisplayMode() { return cdm; } + + /// Create a new printer that will print a query in the SMTLIBv2 language. + ExprSMTLIBPrinter(); + + /// Set the output stream that will be printed to. + /// This call is persistent across queries. + void setOutput(llvm::raw_ostream &output); + + /// Set the query to print. This will setArrayValuesToGet() + /// to none (i.e. no array values will be requested using + /// the SMTLIBv2 (get-value ()) command). + void setQuery(const Query &q); + + virtual ~ExprSMTLIBPrinter(); + + /// Print the query to the llvm::raw_ostream + /// setOutput() and setQuery() must be called before calling this. /// - ///The class can then be used again on another query ( setQuery() ). - ///The options set are persistent across queries (apart from setArrayValuesToGet() and PRODUCE_MODELS). + /// All options should be set before calling this. + /// \sa setConstantDisplayMode + /// \sa setLogic() + /// \sa setHumanReadable + /// \sa setSMTLIBboolOption + /// \sa setArrayValuesToGet /// + /// Mostly it does not matter what order the options are set in. However + /// calling + /// setArrayValuesToGet() implies PRODUCE_MODELS is set so, if a call to + /// setSMTLIBboolOption() + /// is made that uses the PRODUCE_MODELS before calling setArrayValuesToGet() + /// then the setSMTLIBboolOption() + /// call will be ineffective. + virtual void generateOutput(); + + /// Set which SMTLIBv2 logic to use. + /// This only affects what logic is used in the (set-logic <logic>) command. + /// The rest of the printed SMTLIBv2 commands are the same regardless of the + /// logic used. /// - ///Note that in KLEE at the lowest level the solver checks for validity of the query, i.e. - /// - /// \f[ \forall X constraints(X) \to query(X) \f] - /// - /// Where \f$X\f$ is some assignment, \f$constraints(X)\f$ are the constraints - /// in the query and \f$query(X)\f$ is the query expression. - /// If the above formula is true the query is said to be **valid**, otherwise it is - /// **invalid**. + /// \return true if setting logic was successful. + bool setLogic(SMTLIBv2Logic l); + + /// Sets how readable the printed SMTLIBv2 commands are. + /// \param hr If set to true the printed commands are made more human + /// readable. /// - /// The SMTLIBv2 language works in terms of satisfiability rather than validity so instead - /// this class must ask the equivalent query but in terms of satisfiability which is: + /// The printed commands are made human readable by... + /// - Indenting and line breaking. + /// - Adding comments + void setHumanReadable(bool hr); + + /// Set SMTLIB options. + /// These options will be printed when generateOutput() is called via + /// the SMTLIBv2 command (set-option :option-name <value>) /// - /// \f[ \lnot \exists X constraints(X) \land \lnot query(X) \f] + /// By default no options will be printed so the SMTLIBv2 solver will use + /// its default values for all options. /// - /// The printed SMTLIBv2 query actually asks the following: + /// \return true if option was successfully set. /// - /// \f[ \exists X constraints(X) \land \lnot query(X) \f] - /// Hence the printed SMTLIBv2 query will just assert the constraints and the negation - /// of the query expression. + /// The options set are persistent across calls to setQuery() apart from the + /// PRODUCE_MODELS option which this printer may automatically set/unset. + bool setSMTLIBboolOption(SMTLIBboolOptions option, SMTLIBboolValues value); + + /// Set the array names that the SMTLIBv2 solver will be asked to determine. + /// Calling this method implies the PRODUCE_MODELS option is true and will + /// change + /// any previously set value. /// - /// If a SMTLIBv2 solver says the printed query is satisfiable the then original - /// query passed to this class was **invalid** and if a SMTLIBv2 solver says the printed - /// query is unsatisfiable then the original query passed to this class was **valid**. + /// If no call is made to this function before + /// ExprSMTLIBPrinter::generateOutput() then + /// the solver will only be asked to check satisfiability. /// - class ExprSMTLIBPrinter - { - public: - - ///Different SMTLIBv2 logics supported by this class - /// \sa setLogic() - enum SMTLIBv2Logic - { - QF_ABV, ///< Logic using Theory of Arrays and Theory of Bitvectors - QF_AUFBV ///< Logic using Theory of Arrays and Theory of Bitvectors and has uninterpreted functions - }; - - ///Different SMTLIBv2 options that have a boolean value that can be set - /// \sa setSMTLIBboolOption - enum SMTLIBboolOptions - { - PRINT_SUCCESS, ///< print-success SMTLIBv2 option - PRODUCE_MODELS,///< produce-models SMTLIBv2 option - INTERACTIVE_MODE ///< interactive-mode SMTLIBv2 option - }; - - ///Different SMTLIBv2 bool option values - /// \sa setSMTLIBboolOption - enum SMTLIBboolValues - { - OPTION_TRUE, ///< Set option to true - OPTION_FALSE, ///< Set option to false - OPTION_DEFAULT ///< Use solver's defaults (the option will not be set in output) - }; - - enum ConstantDisplayMode - { - BINARY,///< Display bit vector constants in binary e.g. #b00101101 - HEX, ///< Display bit vector constants in Hexidecimal e.g.#x2D - DECIMAL ///< Display bit vector constants in Decimal e.g. (_ bv45 8) - }; - - ///Different supported SMTLIBv2 sorts (a.k.a type) in QF_AUFBV - enum SMTLIB_SORT - { - SORT_BITVECTOR, - SORT_BOOL - }; - - - - ///Allows the way Constant bitvectors are printed to be changed. - ///This setting is persistent across queries. - /// \return true if setting the mode was successful - bool setConstantDisplayMode(ConstantDisplayMode cdm); - - ConstantDisplayMode getConstantDisplayMode() { return cdm;} - - ///Create a new printer that will print a query in the SMTLIBv2 language. - ExprSMTLIBPrinter(); - - ///Set the output stream that will be printed to. - ///This call is persistent across queries. - void setOutput(std::ostream& output); - - ///Set the query to print. This will setArrayValuesToGet() - ///to none (i.e. no array values will be requested using - ///the SMTLIBv2 (get-value ()) command). - void setQuery(const Query& q); - - virtual ~ExprSMTLIBPrinter(); - - /// Print the query to the std::ostream - /// setOutput() and setQuery() must be called before calling this. - /// - /// All options should be set before calling this. - /// \sa setConstantDisplayMode - /// \sa setLogic() - /// \sa setHumanReadable - /// \sa setSMTLIBboolOption - /// \sa setArrayValuesToGet - /// - /// Mostly it does not matter what order the options are set in. However calling - /// setArrayValuesToGet() implies PRODUCE_MODELS is set so, if a call to setSMTLIBboolOption() - /// is made that uses the PRODUCE_MODELS before calling setArrayValuesToGet() then the setSMTLIBboolOption() - /// call will be ineffective. - virtual void generateOutput(); - - ///Set which SMTLIBv2 logic to use. - ///This only affects what logic is used in the (set-logic <logic>) command. - ///The rest of the printed SMTLIBv2 commands are the same regardless of the logic used. - /// - /// \return true if setting logic was successful. - bool setLogic(SMTLIBv2Logic l); - - ///Sets how readable the printed SMTLIBv2 commands are. - /// \param hr If set to true the printed commands are made more human readable. - /// - /// The printed commands are made human readable by... - /// - Indenting and line breaking. - /// - Adding comments - void setHumanReadable(bool hr); - - ///Set SMTLIB options. - /// These options will be printed when generateOutput() is called via - /// the SMTLIBv2 command (set-option :option-name <value>) - /// - /// By default no options will be printed so the SMTLIBv2 solver will use - /// its default values for all options. - /// - /// \return true if option was successfully set. - /// - /// The options set are persistent across calls to setQuery() apart from the - /// PRODUCE_MODELS option which this printer may automatically set/unset. - bool setSMTLIBboolOption(SMTLIBboolOptions option, SMTLIBboolValues value); - - /// Set the array names that the SMTLIBv2 solver will be asked to determine. - /// Calling this method implies the PRODUCE_MODELS option is true and will change - /// any previously set value. - /// - /// If no call is made to this function before ExprSMTLIBPrinter::generateOutput() then - /// the solver will only be asked to check satisfiability. - /// - /// If the passed vector is not empty then the values of those arrays will be requested - /// via (get-value ()) SMTLIBv2 command in the output stream in the same order as vector. - void setArrayValuesToGet(const std::vector<const Array*>& a); - - /// \return True if human readable mode is switched on - bool isHumanReadable(); - - - protected: - ///Contains the arrays found during scans - std::set<const Array*> usedArrays; - - ///Output stream to write to - std::ostream* o; - - ///The query to print - const Query* query; - - ///Determine the SMTLIBv2 sort of the expression - SMTLIB_SORT getSort(const ref<Expr>& e); - - ///Print an expression but cast it to a particular SMTLIBv2 sort first. - void printCastToSort(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT sort); - - //Resets various internal objects for a new query - virtual void reset(); - - //Scan all constraints and the query - virtual void scanAll(); - - //Print an initial SMTLIBv2 comment before anything else is printed - virtual void printNotice(); - - //Print SMTLIBv2 options e.g. (set-option :option-name <value>) command - virtual void printOptions(); - - //Print SMTLIBv2 logic to use e.g. (set-logic QF_ABV) - virtual void printSetLogic(); - - //Print SMTLIBv2 assertions for constant arrays - virtual void printArrayDeclarations(); - - //Print SMTLIBv2 for all constraints in the query - virtual void printConstraints(); - - //Print SMTLIBv2 assert statement for the negated query expression - virtual void printQuery(); - - ///Print the SMTLIBv2 command to check satisfiability and also optionally request for values - /// \sa setArrayValuesToGet() - virtual void printAction(); - - ///Print the SMTLIBv2 command to exit - virtual void printExit(); - - ///Print a Constant in the format specified by the current "Constant Display Mode" - void printConstant(const ref<ConstantExpr>& e); - - ///Recursively print expression - /// \param e is the expression to print - /// \param expectedSort is the sort we want. If "e" is not of the right type a cast will be performed. - virtual void printExpression(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort); - - ///Scan Expression recursively for Arrays in expressions. Found arrays are added to - /// the usedArrays vector. - virtual void scan(const ref<Expr>& e); - - /* Rules of recursion for "Special Expression handlers" and printSortArgsExpr() - * - * 1. The parent of the recursion will have created an indent level for you so you don't need to add another initially. - * 2. You do not need to add a line break (via printSeperator() ) at the end, the parent caller will handle that. - * 3. The effect of a single recursive call should not affect the depth of the indent stack (nor the contents - * of the indent stack prior to the call). I.e. After executing a single recursive call the indent stack - * should have the same size and contents as before executing the recursive call. - */ - - //Special Expression handlers - virtual void printReadExpr(const ref<ReadExpr>& e); - virtual void printExtractExpr(const ref<ExtractExpr>& e); - virtual void printCastExpr(const ref<CastExpr>& e); - virtual void printNotEqualExpr(const ref<NeExpr>& e); - virtual void printSelectExpr(const ref<SelectExpr>& e, ExprSMTLIBPrinter::SMTLIB_SORT s); - - //For the set of operators that take sort "s" arguments - virtual void printSortArgsExpr(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT s); - - ///For the set of operators that come in two sorts (e.g. (and () ()) (bvand () ()) ) - ///These are and,xor,or,not - /// \param e the Expression to print - /// \param s the sort of the expression we want - virtual void printLogicalOrBitVectorExpr(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT s); - - ///Recursively prints updatesNodes - virtual void printUpdatesAndArray(const UpdateNode* un, const Array* root); - - ///This method does the translation between Expr classes and SMTLIBv2 keywords - /// \return A C-string of the SMTLIBv2 keyword - virtual const char* getSMTLIBKeyword(const ref<Expr>& e); - - virtual void printSeperator(); - - ///Helper function for scan() that scans the expressions of an update node - virtual void scanUpdates(const UpdateNode* un); - - ///Helper printer class - PrintContext* p; - - ///This contains the query from the solver but negated for our purposes. - /// \sa negateQueryExpression() - ref<Expr> queryAssert; - - ///Indicates if there were any constant arrays founds during a scan() - bool haveConstantArray; - - - private: - SMTLIBv2Logic logicToUse; - - volatile bool humanReadable; - - //Map of enabled SMTLIB Options - std::map<SMTLIBboolOptions,bool> smtlibBoolOptions; - - ///This sets queryAssert to be the boolean negation of the original Query - void negateQueryExpression(); - - //Print a SMTLIBv2 option as a C-string - const char* getSMTLIBOptionString(ExprSMTLIBPrinter::SMTLIBboolOptions option); + /// If the passed vector is not empty then the values of those arrays will be + /// requested + /// via (get-value ()) SMTLIBv2 command in the output stream in the same order + /// as vector. + void setArrayValuesToGet(const std::vector<const Array *> &a); + + /// \return True if human readable mode is switched on + bool isHumanReadable(); + +protected: + /// Contains the arrays found during scans + std::set<const Array *> usedArrays; + + /// Output stream to write to + llvm::raw_ostream *o; + + /// The query to print + const Query *query; + + /// Determine the SMTLIBv2 sort of the expression + SMTLIB_SORT getSort(const ref<Expr> &e); + + /// Print an expression but cast it to a particular SMTLIBv2 sort first. + void printCastToSort(const ref<Expr> &e, ExprSMTLIBPrinter::SMTLIB_SORT sort); + + // Resets various internal objects for a new query + virtual void reset(); + + // Scan all constraints and the query + virtual void scanAll(); + + // Print an initial SMTLIBv2 comment before anything else is printed + virtual void printNotice(); + + // Print SMTLIBv2 options e.g. (set-option :option-name <value>) command + virtual void printOptions(); + + // Print SMTLIBv2 logic to use e.g. (set-logic QF_ABV) + virtual void printSetLogic(); + + // Print SMTLIBv2 assertions for constant arrays + virtual void printArrayDeclarations(); - //Pointer to a vector of Arrays. These will be used for the (get-value () ) call. - const std::vector<const Array*> * arraysToCallGetValueOn; + // Print SMTLIBv2 for all constraints in the query + virtual void printConstraints(); - ConstantDisplayMode cdm; + // Print SMTLIBv2 assert statement for the negated query expression + virtual void printQuery(); + + /// Print the SMTLIBv2 command to check satisfiability and also optionally + /// request for values + /// \sa setArrayValuesToGet() + virtual void printAction(); + + /// Print the SMTLIBv2 command to exit + virtual void printExit(); + + /// Print a Constant in the format specified by the current "Constant Display + /// Mode" + void printConstant(const ref<ConstantExpr> &e); + + /// Recursively print expression + /// \param e is the expression to print + /// \param expectedSort is the sort we want. If "e" is not of the right type a + /// cast will be performed. + virtual void printExpression(const ref<Expr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT expectedSort); + + /// Scan Expression recursively for Arrays in expressions. Found arrays are + /// added to + /// the usedArrays vector. + virtual void scan(const ref<Expr> &e); + + /* Rules of recursion for "Special Expression handlers" and + *printSortArgsExpr() + * + * 1. The parent of the recursion will have created an indent level for you so + *you don't need to add another initially. + * 2. You do not need to add a line break (via printSeperator() ) at the end, + *the parent caller will handle that. + * 3. The effect of a single recursive call should not affect the depth of the + *indent stack (nor the contents + * of the indent stack prior to the call). I.e. After executing a single + *recursive call the indent stack + * should have the same size and contents as before executing the recursive + *call. + */ + + // Special Expression handlers + virtual void printReadExpr(const ref<ReadExpr> &e); + virtual void printExtractExpr(const ref<ExtractExpr> &e); + virtual void printCastExpr(const ref<CastExpr> &e); + virtual void printNotEqualExpr(const ref<NeExpr> &e); + virtual void printSelectExpr(const ref<SelectExpr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT s); + + // For the set of operators that take sort "s" arguments + virtual void printSortArgsExpr(const ref<Expr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT s); + + /// For the set of operators that come in two sorts (e.g. (and () ()) (bvand + /// () ()) ) + /// These are and,xor,or,not + /// \param e the Expression to print + /// \param s the sort of the expression we want + virtual void printLogicalOrBitVectorExpr(const ref<Expr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT s); - }; + /// Recursively prints updatesNodes + virtual void printUpdatesAndArray(const UpdateNode *un, const Array *root); + /// This method does the translation between Expr classes and SMTLIBv2 + /// keywords + /// \return A C-string of the SMTLIBv2 keyword + virtual const char *getSMTLIBKeyword(const ref<Expr> &e); + virtual void printSeperator(); + /// Helper function for scan() that scans the expressions of an update node + virtual void scanUpdates(const UpdateNode *un); + + /// Helper printer class + PrintContext *p; + + /// This contains the query from the solver but negated for our purposes. + /// \sa negateQueryExpression() + ref<Expr> queryAssert; + + /// Indicates if there were any constant arrays founds during a scan() + bool haveConstantArray; + +private: + SMTLIBv2Logic logicToUse; + + volatile bool humanReadable; + + // Map of enabled SMTLIB Options + std::map<SMTLIBboolOptions, bool> smtlibBoolOptions; + + /// This sets queryAssert to be the boolean negation of the original Query + void negateQueryExpression(); + + // Print a SMTLIBv2 option as a C-string + const char * + getSMTLIBOptionString(ExprSMTLIBPrinter::SMTLIBboolOptions option); + + // Pointer to a vector of Arrays. These will be used for the (get-value () ) + // call. + const std::vector<const Array *> *arraysToCallGetValueOn; + + ConstantDisplayMode cdm; +}; } #endif diff --git a/include/klee/util/PrintContext.h b/include/klee/util/PrintContext.h index a9e91925..6b1ef77a 100644 --- a/include/klee/util/PrintContext.h +++ b/include/klee/util/PrintContext.h @@ -1,14 +1,14 @@ #ifndef PRINTCONTEXT_H_ #define PRINTCONTEXT_H_ -#include <ostream> +#include "klee/Expr.h" +#include "llvm/Support/raw_ostream.h" #include <sstream> #include <string> #include <stack> -#include <iomanip> /// PrintContext - Helper class for pretty printing. -/// It provides a basic wrapper around std::ostream that keeps track of +/// It provides a basic wrapper around llvm::raw_ostream that keeps track of /// how many characters have been used on the current line. /// /// It also provides an optional way keeping track of the various levels of indentation @@ -16,8 +16,7 @@ /// \sa breakLineI() , \sa pushIndent(), \sa popIndent() class PrintContext { private: - std::ostream &os; - std::stringstream ss; + llvm::raw_ostream &os; std::string newline; ///This is used to keep track of the stack of indentations used by @@ -30,7 +29,7 @@ public: /// Number of characters on the current line. unsigned pos; - PrintContext(std::ostream &_os) : os(_os), newline("\n"), indentStack(), pos() + PrintContext(llvm::raw_ostream &_os) : os(_os), newline("\n"), indentStack(), pos() { indentStack.push(pos); } @@ -42,7 +41,7 @@ public: void breakLine(unsigned indent=0) { os << newline; if (indent) - os << std::setw(indent) << ' '; + os.indent(indent) << ' '; pos = indent; } @@ -79,7 +78,8 @@ public: template <typename T> PrintContext &operator<<(T elt) { - ss.str(""); + std::string str; + llvm::raw_string_ostream ss(str); ss << elt; write(ss.str()); return *this; diff --git a/include/klee/util/Ref.h b/include/klee/util/Ref.h index d14de471..c77149aa 100644 --- a/include/klee/util/Ref.h +++ b/include/klee/util/Ref.h @@ -20,6 +20,10 @@ using llvm::dyn_cast_or_null; #include <assert.h> #include <iosfwd> // FIXME: Remove this!!! +namespace llvm { + class raw_ostream; +} + namespace klee { template<class T> @@ -107,7 +111,13 @@ public: }; template<class T> -inline std::ostream &operator<<(std::ostream &os, const ref<T> &e) { +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const ref<T> &e) { + os << *e; + return os; +} + +template<class T> +inline std::stringstream &operator<<(std::stringstream &os, const ref<T> &e) { os << *e; return os; } diff --git a/lib/Basic/ConstructSolverChain.cpp b/lib/Basic/ConstructSolverChain.cpp index c0d0ef61..59790551 100644 --- a/lib/Basic/ConstructSolverChain.cpp +++ b/lib/Basic/ConstructSolverChain.cpp @@ -10,9 +10,9 @@ /* * This file groups declarations that are common to both KLEE and Kleaver. */ -#include <iostream> #include "klee/Common.h" #include "klee/CommandLine.h" +#include "llvm/Support/raw_ostream.h" namespace klee { @@ -29,8 +29,8 @@ namespace klee solver = createPCLoggingSolver(solver, baseSolverQueryPCLogPath, MinQueryTimeToLog); - std::cerr << "Logging queries that reach solver in .pc format to " - << baseSolverQueryPCLogPath.c_str() << std::endl; + llvm::errs() << "Logging queries that reach solver in .pc format to " + << baseSolverQueryPCLogPath.c_str() << "\n"; } if (optionIsSet(queryLoggingOptions, SOLVER_SMTLIB)) @@ -38,8 +38,8 @@ namespace klee solver = createSMTLIBLoggingSolver(solver, baseSolverQuerySMT2LogPath, MinQueryTimeToLog); - std::cerr << "Logging queries that reach solver in .smt2 format to " - << baseSolverQuerySMT2LogPath.c_str() << std::endl; + llvm::errs() << "Logging queries that reach solver in .smt2 format to " + << baseSolverQuerySMT2LogPath.c_str() << "\n"; } if (UseFastCexSolver) @@ -62,16 +62,16 @@ namespace klee solver = createPCLoggingSolver(solver, queryPCLogPath, MinQueryTimeToLog); - std::cerr << "Logging all queries in .pc format to " - << queryPCLogPath.c_str() << std::endl; + llvm::errs() << "Logging all queries in .pc format to " + << queryPCLogPath.c_str() << "\n"; } if (optionIsSet(queryLoggingOptions, ALL_SMTLIB)) { solver = createSMTLIBLoggingSolver(solver,querySMT2LogPath, MinQueryTimeToLog); - std::cerr << "Logging all queries in .smt2 format to " - << querySMT2LogPath.c_str() << std::endl; + llvm::errs() << "Logging all queries in .smt2 format to " + << querySMT2LogPath.c_str() << "\n"; } return solver; diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile index d4481e7f..e72399a2 100644 --- a/lib/Basic/Makefile +++ b/lib/Basic/Makefile @@ -12,5 +12,6 @@ LEVEL=../.. LIBRARYNAME=kleeBasic DONT_BUILD_RELINKED=1 BUILD_ARCHIVE=1 +NO_INSTALL=1 include $(LEVEL)/Makefile.common diff --git a/lib/Core/ExecutionState.cpp b/lib/Core/ExecutionState.cpp index b2c2a737..e81c776c 100644 --- a/lib/Core/ExecutionState.cpp +++ b/lib/Core/ExecutionState.cpp @@ -23,9 +23,10 @@ #include "llvm/Function.h" #endif #include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" -#include <iostream> #include <iomanip> +#include <sstream> #include <cassert> #include <map> #include <set> @@ -177,7 +178,7 @@ void ExecutionState::removeFnAlias(std::string fn) { /**/ -std::ostream &klee::operator<<(std::ostream &os, const MemoryMap &mm) { +llvm::raw_ostream &klee::operator<<(llvm::raw_ostream &os, const MemoryMap &mm) { os << "{"; MemoryMap::iterator it = mm.begin(); MemoryMap::iterator ie = mm.end(); @@ -192,8 +193,8 @@ std::ostream &klee::operator<<(std::ostream &os, const MemoryMap &mm) { bool ExecutionState::merge(const ExecutionState &b) { if (DebugLogStateMerge) - std::cerr << "-- attempting merge of A:" - << this << " with B:" << &b << "--\n"; + llvm::errs() << "-- attempting merge of A:" << this << " with B:" << &b + << "--\n"; if (pc != b.pc) return false; @@ -230,21 +231,24 @@ bool ExecutionState::merge(const ExecutionState &b) { commonConstraints.begin(), commonConstraints.end(), std::inserter(bSuffix, bSuffix.end())); if (DebugLogStateMerge) { - std::cerr << "\tconstraint prefix: ["; - for (std::set< ref<Expr> >::iterator it = commonConstraints.begin(), - ie = commonConstraints.end(); it != ie; ++it) - std::cerr << *it << ", "; - std::cerr << "]\n"; - std::cerr << "\tA suffix: ["; - for (std::set< ref<Expr> >::iterator it = aSuffix.begin(), - ie = aSuffix.end(); it != ie; ++it) - std::cerr << *it << ", "; - std::cerr << "]\n"; - std::cerr << "\tB suffix: ["; - for (std::set< ref<Expr> >::iterator it = bSuffix.begin(), - ie = bSuffix.end(); it != ie; ++it) - std::cerr << *it << ", "; - std::cerr << "]\n"; + llvm::errs() << "\tconstraint prefix: ["; + for (std::set<ref<Expr> >::iterator it = commonConstraints.begin(), + ie = commonConstraints.end(); + it != ie; ++it) + llvm::errs() << *it << ", "; + llvm::errs() << "]\n"; + llvm::errs() << "\tA suffix: ["; + for (std::set<ref<Expr> >::iterator it = aSuffix.begin(), + ie = aSuffix.end(); + it != ie; ++it) + llvm::errs() << *it << ", "; + llvm::errs() << "]\n"; + llvm::errs() << "\tB suffix: ["; + for (std::set<ref<Expr> >::iterator it = bSuffix.begin(), + ie = bSuffix.end(); + it != ie; ++it) + llvm::errs() << *it << ", "; + llvm::errs() << "]\n"; } // We cannot merge if addresses would resolve differently in the @@ -257,9 +261,9 @@ bool ExecutionState::merge(const ExecutionState &b) { // and not the other if (DebugLogStateMerge) { - std::cerr << "\tchecking object states\n"; - std::cerr << "A: " << addressSpace.objects << "\n"; - std::cerr << "B: " << b.addressSpace.objects << "\n"; + llvm::errs() << "\tchecking object states\n"; + llvm::errs() << "A: " << addressSpace.objects << "\n"; + llvm::errs() << "B: " << b.addressSpace.objects << "\n"; } std::set<const MemoryObject*> mutated; @@ -271,22 +275,22 @@ bool ExecutionState::merge(const ExecutionState &b) { if (ai->first != bi->first) { if (DebugLogStateMerge) { if (ai->first < bi->first) { - std::cerr << "\t\tB misses binding for: " << ai->first->id << "\n"; + llvm::errs() << "\t\tB misses binding for: " << ai->first->id << "\n"; } else { - std::cerr << "\t\tA misses binding for: " << bi->first->id << "\n"; + llvm::errs() << "\t\tA misses binding for: " << bi->first->id << "\n"; } } return false; } if (ai->second != bi->second) { if (DebugLogStateMerge) - std::cerr << "\t\tmutated: " << ai->first->id << "\n"; + llvm::errs() << "\t\tmutated: " << ai->first->id << "\n"; mutated.insert(ai->first); } } if (ai!=ae || bi!=be) { if (DebugLogStateMerge) - std::cerr << "\t\tmappings differ\n"; + llvm::errs() << "\t\tmappings differ\n"; return false; } @@ -348,7 +352,7 @@ bool ExecutionState::merge(const ExecutionState &b) { return true; } -void ExecutionState::dumpStack(std::ostream &out) const { +void ExecutionState::dumpStack(llvm::raw_ostream &out) const { unsigned idx = 0; const KInstruction *target = prevPC; for (ExecutionState::stack_ty::const_reverse_iterator @@ -357,9 +361,11 @@ void ExecutionState::dumpStack(std::ostream &out) const { const StackFrame &sf = *it; Function *f = sf.kf->function; const InstructionInfo &ii = *target->info; - out << "\t#" << idx++ - << " " << std::setw(8) << std::setfill('0') << ii.assemblyLine - << " in " << f->getName().str() << " ("; + out << "\t#" << idx++; + std::stringstream AssStream; + AssStream << std::setw(8) << std::setfill('0') << ii.assemblyLine; + out << AssStream.str(); + out << " in " << f->getName().str() << " ("; // Yawn, we could go up and print varargs if we wanted to. unsigned index = 0; for (Function::arg_iterator ai = f->arg_begin(), ae = f->arg_end(); diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index ef55f21f..f31d6aeb 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -47,6 +47,7 @@ #include "klee/Internal/Module/KModule.h" #include "klee/Internal/Support/FloatEvaluation.h" #include "klee/Internal/System/Time.h" +#include "klee/Internal/System/MemoryUsage.h" #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) #include "llvm/IR/Function.h" @@ -85,8 +86,8 @@ #include <cassert> #include <algorithm> -#include <iostream> #include <iomanip> +#include <iosfwd> #include <fstream> #include <sstream> #include <vector> @@ -163,6 +164,11 @@ namespace { SimplifySymIndices("simplify-sym-indices", cl::init(false)); + cl::opt<bool> + EqualitySubstitution("equality-substitution", + cl::init(true), + cl::desc("Simplify equality expressions before querying the solver (default=on).")); + cl::opt<unsigned> MaxSymArraySize("max-sym-array-size", cl::init(0)); @@ -315,7 +321,7 @@ Executor::Executor(const InterpreterOptions &opts, assert(false); break; }; - std::cerr << "Starting MetaSMTSolver(" << backend << ") ...\n"; + llvm::errs() << "Starting MetaSMTSolver(" << backend << ") ...\n"; } else { coreSolver = new STPSolver(UseForkedCoreSolver, CoreSolverOptimizeDivides); @@ -332,7 +338,7 @@ Executor::Executor(const InterpreterOptions &opts, interpreterHandler->getOutputFilename(ALL_QUERIES_PC_FILE_NAME), interpreterHandler->getOutputFilename(SOLVER_QUERIES_PC_FILE_NAME)); - this->solver = new TimingSolver(solver); + this->solver = new TimingSolver(solver, EqualitySubstitution); memory = new MemoryManager(); } @@ -1104,12 +1110,13 @@ Executor::toConstant(ExecutionState &state, bool success = solver->getValue(state, e, value); assert(success && "FIXME: Unhandled solver failure"); (void) success; - - std::ostringstream os; - os << "silently concretizing (reason: " << reason << ") expression " << e - << " to value " << value - << " (" << (*(state.pc)).info->file << ":" << (*(state.pc)).info->line << ")"; - + + std::string str; + llvm::raw_string_ostream os(str); + os << "silently concretizing (reason: " << reason << ") expression " << e + << " to value " << value << " (" << (*(state.pc)).info->file << ":" + << (*(state.pc)).info->line << ")"; + if (AllExternalWarnings) klee_warning(reason, os.str().c_str()); else @@ -1166,7 +1173,7 @@ void Executor::executeGetValue(ExecutionState &state, void Executor::stepInstruction(ExecutionState &state) { if (DebugPrintInstructions) { printFileLine(state, state.pc); - std::cerr << std::setw(10) << stats::instructions << " "; + llvm::errs().indent(10) << stats::instructions << " "; llvm::errs() << *(state.pc->inst) << '\n'; } @@ -1350,10 +1357,10 @@ void Executor::transferToBasicBlock(BasicBlock *dst, BasicBlock *src, void Executor::printFileLine(ExecutionState &state, KInstruction *ki) { const InstructionInfo &ii = *ki->info; - if (ii.file != "") - std::cerr << " " << ii.file << ":" << ii.line << ":"; + if (ii.file != "") + llvm::errs() << " " << ii.file << ":" << ii.line << ":"; else - std::cerr << " [no debug info]:"; + llvm::errs() << " [no debug info]:"; } /// Compute the true target of a function call, resolving LLVM and KLEE aliases @@ -2584,11 +2591,7 @@ void Executor::run(ExecutionState &initialState) { // We need to avoid calling GetMallocUsage() often because it // is O(elts on freelist). This is really bad since we start // to pummel the freelist once we hit the memory cap. -#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) - unsigned mbs = sys::Process::GetMallocUsage() >> 20; -#else - unsigned mbs = sys::Process::GetTotalMemoryUsage() >> 20; -#endif + unsigned mbs = util::GetTotalMallocUsage() >> 20; if (mbs > MaxMemory) { if (mbs > MaxMemory + 100) { // just guess at how many to kill @@ -2627,7 +2630,7 @@ void Executor::run(ExecutionState &initialState) { dump: if (DumpStatesOnHalt && !states.empty()) { - std::cerr << "KLEE: halting execution, dumping remaining states\n"; + llvm::errs() << "KLEE: halting execution, dumping remaining states\n"; for (std::set<ExecutionState*>::iterator it = states.begin(), ie = states.end(); it != ie; ++it) { @@ -2641,7 +2644,8 @@ void Executor::run(ExecutionState &initialState) { std::string Executor::getAddressInfo(ExecutionState &state, ref<Expr> address) const{ - std::ostringstream info; + std::string Str; + llvm::raw_string_ostream info(Str); info << "\taddress: " << address << "\n"; uint64_t example; if (ConstantExpr *CE = dyn_cast<ConstantExpr>(address)) { @@ -2729,29 +2733,74 @@ void Executor::terminateStateOnExit(ExecutionState &state) { terminateState(state); } +const InstructionInfo & Executor::getLastNonKleeInternalInstruction(const ExecutionState &state, + Instruction ** lastInstruction) { + // unroll the stack of the applications state and find + // the last instruction which is not inside a KLEE internal function + ExecutionState::stack_ty::const_reverse_iterator it = state.stack.rbegin(), + itE = state.stack.rend(); + + // don't check beyond the outermost function (i.e. main()) + itE--; + + const InstructionInfo * ii = 0; + if (kmodule->internalFunctions.count(it->kf->function) == 0){ + ii = state.prevPC->info; + *lastInstruction = state.prevPC->inst; + // Cannot return yet because even though + // it->function is not an internal function it might of + // been called from an internal function. + } + + // Wind up the stack and check if we are in a KLEE internal function. + // We visit the entire stack because we want to return a CallInstruction + // that was not reached via any KLEE internal functions. + for (;it != itE; ++it) { + // check calling instruction and if it is contained in a KLEE internal function + const Function * f = (*it->caller).inst->getParent()->getParent(); + if (kmodule->internalFunctions.count(f)){ + ii = 0; + continue; + } + if (!ii){ + ii = (*it->caller).info; + *lastInstruction = (*it->caller).inst; + } + } + + if (!ii) { + // something went wrong, play safe and return the current instruction info + *lastInstruction = state.prevPC->inst; + return *state.prevPC->info; + } + return *ii; +} void Executor::terminateStateOnError(ExecutionState &state, const llvm::Twine &messaget, const char *suffix, const llvm::Twine &info) { std::string message = messaget.str(); static std::set< std::pair<Instruction*, std::string> > emittedErrors; - const InstructionInfo &ii = *state.prevPC->info; + Instruction * lastInst; + const InstructionInfo &ii = getLastNonKleeInternalInstruction(state, &lastInst); if (EmitAllErrors || - emittedErrors.insert(std::make_pair(state.prevPC->inst, message)).second) { + emittedErrors.insert(std::make_pair(lastInst, message)).second) { if (ii.file != "") { klee_message("ERROR: %s:%d: %s", ii.file.c_str(), ii.line, message.c_str()); } else { - klee_message("ERROR: %s", message.c_str()); + klee_message("ERROR: (location information missing) %s", message.c_str()); } if (!EmitAllErrors) klee_message("NOTE: now ignoring this error at this location"); - - std::ostringstream msg; + + std::string MsgString; + llvm::raw_string_ostream msg(MsgString); msg << "Error: " << message << "\n"; if (ii.file != "") { msg << "File: " << ii.file << "\n"; msg << "Line: " << ii.line << "\n"; + msg << "assembly.ll line: " << ii.assemblyLine << "\n"; } msg << "Stack: \n"; state.dumpStack(msg); @@ -2759,6 +2808,7 @@ void Executor::terminateStateOnError(ExecutionState &state, std::string info_str = info.str(); if (info_str != "") msg << "Info: \n" << info_str; + interpreterHandler->processTestCase(state, msg.str().c_str(), suffix); } @@ -2783,8 +2833,8 @@ void Executor::callExternalFunction(ExecutionState &state, return; if (NoExternals && !okExternals.count(function->getName())) { - std::cerr << "KLEE:ERROR: Calling not-OK external function : " - << function->getName().str() << "\n"; + llvm::errs() << "KLEE:ERROR: Calling not-OK external function : " + << function->getName().str() << "\n"; terminateStateOnError(state, "externals disallowed", "user.err"); return; } @@ -2823,7 +2873,9 @@ void Executor::callExternalFunction(ExecutionState &state, state.addressSpace.copyOutConcretes(); if (!SuppressExternalWarnings) { - std::ostringstream os; + + std::string TmpStr; + llvm::raw_string_ostream os(TmpStr); os << "calling external: " << function->getName().str() << "("; for (unsigned i=0; i<arguments.size(); i++) { os << arguments[i]; @@ -2867,11 +2919,11 @@ ref<Expr> Executor::replaceReadWithSymbolic(ExecutionState &state, if (!n || replayOut || replayPath) return e; - // right now, we don't replace symbolics (is there any reason too?) + // right now, we don't replace symbolics (is there any reason to?) if (!isa<ConstantExpr>(e)) return e; - if (n != 1 && random() % n) + if (n != 1 && random() % n) return e; // create a new fresh location, assert it is equal to concrete value in e @@ -2882,7 +2934,7 @@ ref<Expr> Executor::replaceReadWithSymbolic(ExecutionState &state, Expr::getMinBytesForWidth(e->getWidth())); ref<Expr> res = Expr::createTempRead(array, e->getWidth()); ref<Expr> eq = NotOptimizedExpr::create(EqExpr::create(e, res)); - std::cerr << "Making symbolic: " << eq << "\n"; + llvm::errs() << "Making symbolic: " << eq << "\n"; state.addConstraint(eq); return res; } @@ -2994,7 +3046,9 @@ void Executor::executeAlloc(ExecutionState &state, } if (hugeSize.second) { - std::ostringstream info; + + std::string Str; + llvm::raw_string_ostream info(Str); ExprPPrinter::printOne(info, " size expr", size); info << " concretization : " << example << "\n"; info << " unbound example: " << tmp << "\n"; @@ -3392,48 +3446,41 @@ unsigned Executor::getSymbolicPathStreamID(const ExecutionState &state) { return state.symPathOS.getID(); } -void Executor::getConstraintLog(const ExecutionState &state, - std::string &res, +void Executor::getConstraintLog(const ExecutionState &state, std::string &res, Interpreter::LogType logFormat) { std::ostringstream info; - switch(logFormat) - { - case STP: - { - Query query(state.constraints, ConstantExpr::alloc(0, Expr::Bool)); - char *log = solver->getConstraintLog(query); - res = std::string(log); - free(log); - } - break; - - case KQUERY: - { - std::ostringstream info; - ExprPPrinter::printConstraints(info, state.constraints); - res = info.str(); - } - break; - - case SMTLIB2: - { - std::ostringstream info; - ExprSMTLIBPrinter* printer = createSMTLIBPrinter(); - printer->setOutput(info); - Query query(state.constraints, ConstantExpr::alloc(0, Expr::Bool)); - printer->setQuery(query); - printer->generateOutput(); - res = info.str(); - delete printer; - } - break; + switch (logFormat) { + case STP: { + Query query(state.constraints, ConstantExpr::alloc(0, Expr::Bool)); + char *log = solver->getConstraintLog(query); + res = std::string(log); + free(log); + } break; + + case KQUERY: { + std::string Str; + llvm::raw_string_ostream info(Str); + ExprPPrinter::printConstraints(info, state.constraints); + res = info.str(); + } break; + + case SMTLIB2: { + std::string Str; + llvm::raw_string_ostream info(Str); + ExprSMTLIBPrinter *printer = createSMTLIBPrinter(); + printer->setOutput(info); + Query query(state.constraints, ConstantExpr::alloc(0, Expr::Bool)); + printer->setQuery(query); + printer->generateOutput(); + res = info.str(); + delete printer; + } break; default: - klee_warning("Executor::getConstraintLog() : Log format not supported!"); + klee_warning("Executor::getConstraintLog() : Log format not supported!"); } - } bool Executor::getSymbolicSolution(const ExecutionState &state, @@ -3468,8 +3515,7 @@ bool Executor::getSymbolicSolution(const ExecutionState &state, solver->setTimeout(0); if (!success) { klee_warning("unable to compute initial values (invalid constraints?)!"); - ExprPPrinter::printQuery(std::cerr, - state.constraints, + ExprPPrinter::printQuery(llvm::errs(), state.constraints, ConstantExpr::alloc(0, Expr::Bool)); return false; } diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index b7318a2c..7d82332c 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -340,6 +340,11 @@ private: /// Get textual information regarding a memory address. std::string getAddressInfo(ExecutionState &state, ref<Expr> address) const; + // Determines the \param lastInstruction of the \param state which is not KLEE + // internal and returns its InstructionInfo + const InstructionInfo & getLastNonKleeInternalInstruction(const ExecutionState &state, + llvm::Instruction** lastInstruction); + // remove state from queue and delete void terminateState(ExecutionState &state); // call exit handler and terminate state diff --git a/lib/Core/ExecutorTimers.cpp b/lib/Core/ExecutorTimers.cpp index 06fd4be7..e4622d85 100644 --- a/lib/Core/ExecutorTimers.cpp +++ b/lib/Core/ExecutorTimers.cpp @@ -53,7 +53,7 @@ public: ~HaltTimer() {} void run() { - std::cerr << "KLEE: HaltTimer invoked\n"; + llvm::errs() << "KLEE: HaltTimer invoked\n"; executor->setHaltExecution(true); } }; @@ -122,7 +122,7 @@ void Executor::processTimers(ExecutionState *current, if (dumpPTree) { char name[32]; sprintf(name, "ptree%08d.dot", (int) stats::instructions); - std::ostream *os = interpreterHandler->openOutputFile(name); + llvm::raw_ostream *os = interpreterHandler->openOutputFile(name); if (os) { processTree->dump(*os); delete os; @@ -132,7 +132,7 @@ void Executor::processTimers(ExecutionState *current, } if (dumpStates) { - std::ostream *os = interpreterHandler->openOutputFile("states.txt"); + llvm::raw_ostream *os = interpreterHandler->openOutputFile("states.txt"); if (os) { for (std::set<ExecutionState*>::const_iterator it = states.begin(), diff --git a/lib/Core/ExecutorUtil.cpp b/lib/Core/ExecutorUtil.cpp index 0d828ec4..f6b3dd5e 100644 --- a/lib/Core/ExecutorUtil.cpp +++ b/lib/Core/ExecutorUtil.cpp @@ -41,7 +41,6 @@ #include "llvm/Support/CallSite.h" -#include <iostream> #include <cassert> using namespace klee; @@ -62,7 +61,7 @@ namespace klee { switch (ce->getOpcode()) { default : ce->dump(); - std::cerr << "error: unknown ConstantExpr type\n" + llvm::errs() << "error: unknown ConstantExpr type\n" << "opcode: " << ce->getOpcode() << "\n"; abort(); diff --git a/lib/Core/ExternalDispatcher.cpp b/lib/Core/ExternalDispatcher.cpp index 2dc16767..4c1e2b86 100644 --- a/lib/Core/ExternalDispatcher.cpp +++ b/lib/Core/ExternalDispatcher.cpp @@ -42,7 +42,6 @@ #endif #include <setjmp.h> #include <signal.h> -#include <iostream> using namespace llvm; using namespace klee; @@ -92,7 +91,7 @@ ExternalDispatcher::ExternalDispatcher() { std::string error; executionEngine = ExecutionEngine::createJIT(dispatchModule, &error); if (!executionEngine) { - std::cerr << "unable to make jit: " << error << "\n"; + llvm::errs() << "unable to make jit: " << error << "\n"; abort(); } diff --git a/lib/Core/ImpliedValue.cpp b/lib/Core/ImpliedValue.cpp index 56c1d1a9..c8342df1 100644 --- a/lib/Core/ImpliedValue.cpp +++ b/lib/Core/ImpliedValue.cpp @@ -18,7 +18,6 @@ #include "klee/util/ExprUtil.h" -#include <iostream> #include <map> #include <set> @@ -246,7 +245,7 @@ void ImpliedValue::checkForImpliedValues(Solver *S, ref<Expr> e, } else { if (it!=found.end()) { ref<Expr> binding = it->second; - std::cerr << "checkForImpliedValues: " << e << " = " << value << "\n" + llvm::errs() << "checkForImpliedValues: " << e << " = " << value << "\n" << "\t\t implies " << var << " == " << binding << " (error)\n"; assert(0); diff --git a/lib/Core/Makefile b/lib/Core/Makefile index 4da3c7ea..f34f699d 100755 --- a/lib/Core/Makefile +++ b/lib/Core/Makefile @@ -12,5 +12,6 @@ LEVEL=../.. LIBRARYNAME=kleeCore DONT_BUILD_RELINKED=1 BUILD_ARCHIVE=1 +NO_INSTALL=1 include $(LEVEL)/Makefile.common diff --git a/lib/Core/Memory.cpp b/lib/Core/Memory.cpp index 4bcdd9f7..b6f225d1 100644 --- a/lib/Core/Memory.cpp +++ b/lib/Core/Memory.cpp @@ -32,7 +32,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" -#include <iostream> #include <cassert> #include <sstream> @@ -585,23 +584,23 @@ void ObjectState::write64(unsigned offset, uint64_t value) { } void ObjectState::print() { - std::cerr << "-- ObjectState --\n"; - std::cerr << "\tMemoryObject ID: " << object->id << "\n"; - std::cerr << "\tRoot Object: " << updates.root << "\n"; - std::cerr << "\tSize: " << size << "\n"; + llvm::errs() << "-- ObjectState --\n"; + llvm::errs() << "\tMemoryObject ID: " << object->id << "\n"; + llvm::errs() << "\tRoot Object: " << updates.root << "\n"; + llvm::errs() << "\tSize: " << size << "\n"; - std::cerr << "\tBytes:\n"; + llvm::errs() << "\tBytes:\n"; for (unsigned i=0; i<size; i++) { - std::cerr << "\t\t["<<i<<"]" + llvm::errs() << "\t\t["<<i<<"]" << " concrete? " << isByteConcrete(i) << " known-sym? " << isByteKnownSymbolic(i) << " flushed? " << isByteFlushed(i) << " = "; ref<Expr> e = read8(i); - std::cerr << e << "\n"; + llvm::errs() << e << "\n"; } - std::cerr << "\tUpdates:\n"; + llvm::errs() << "\tUpdates:\n"; for (const UpdateNode *un=updates.head; un; un=un->next) { - std::cerr << "\t\t[" << un->index << "] = " << un->value << "\n"; + llvm::errs() << "\t\t[" << un->index << "] = " << un->value << "\n"; } } diff --git a/lib/Core/PTree.cpp b/lib/Core/PTree.cpp index 349761cd..f0e7ab51 100644 --- a/lib/Core/PTree.cpp +++ b/lib/Core/PTree.cpp @@ -13,7 +13,6 @@ #include <klee/util/ExprPPrinter.h> #include <vector> -#include <iostream> using namespace klee; @@ -51,7 +50,7 @@ void PTree::remove(Node *n) { } while (n && !n->left && !n->right); } -void PTree::dump(std::ostream &os) { +void PTree::dump(llvm::raw_ostream &os) { ExprPPrinter *pp = ExprPPrinter::create(os); pp->setNewline("\\l"); os << "digraph G {\n"; diff --git a/lib/Core/PTree.h b/lib/Core/PTree.h index 6accc8e2..11d3f48c 100644 --- a/lib/Core/PTree.h +++ b/lib/Core/PTree.h @@ -12,10 +12,6 @@ #include <klee/Expr.h> -#include <utility> -#include <cassert> -#include <iostream> - namespace klee { class ExecutionState; @@ -34,7 +30,7 @@ namespace klee { const data_type &rightData); void remove(Node *n); - void dump(std::ostream &os); + void dump(llvm::raw_ostream &os); }; class PTreeNode { diff --git a/lib/Core/Searcher.cpp b/lib/Core/Searcher.cpp index 2dbabd01..2610f17e 100644 --- a/lib/Core/Searcher.cpp +++ b/lib/Core/Searcher.cpp @@ -157,10 +157,8 @@ void RandomSearcher::update(ExecutionState *current, /// -WeightedRandomSearcher::WeightedRandomSearcher(Executor &_executor, - WeightType _type) - : executor(_executor), - states(new DiscretePDF<ExecutionState*>()), +WeightedRandomSearcher::WeightedRandomSearcher(WeightType _type) + : states(new DiscretePDF<ExecutionState*>()), type(_type) { switch(type) { case Depth: @@ -413,17 +411,17 @@ ExecutionState &MergingSearcher::selectState() { } if (DebugLogMerge) - std::cerr << "-- all at merge --\n"; + llvm::errs() << "-- all at merge --\n"; for (std::map<Instruction*, std::vector<ExecutionState*> >::iterator it = merges.begin(), ie = merges.end(); it != ie; ++it) { if (DebugLogMerge) { - std::cerr << "\tmerge: " << it->first << " ["; + llvm::errs() << "\tmerge: " << it->first << " ["; for (std::vector<ExecutionState*>::iterator it2 = it->second.begin(), ie2 = it->second.end(); it2 != ie2; ++it2) { ExecutionState *state = *it2; - std::cerr << state << ", "; + llvm::errs() << state << ", "; } - std::cerr << "]\n"; + llvm::errs() << "]\n"; } // merge states @@ -442,13 +440,13 @@ ExecutionState &MergingSearcher::selectState() { } } if (DebugLogMerge && !toErase.empty()) { - std::cerr << "\t\tmerged: " << base << " with ["; + llvm::errs() << "\t\tmerged: " << base << " with ["; for (std::set<ExecutionState*>::iterator it = toErase.begin(), ie = toErase.end(); it != ie; ++it) { - if (it!=toErase.begin()) std::cerr << ", "; - std::cerr << *it; + if (it!=toErase.begin()) llvm::errs() << ", "; + llvm::errs() << *it; } - std::cerr << "]\n"; + llvm::errs() << "]\n"; } for (std::set<ExecutionState*>::iterator it = toErase.begin(), ie = toErase.end(); it != ie; ++it) { @@ -466,7 +464,7 @@ ExecutionState &MergingSearcher::selectState() { } if (DebugLogMerge) - std::cerr << "-- merge complete, continuing --\n"; + llvm::errs() << "-- merge complete, continuing --\n"; return selectState(); } @@ -514,7 +512,8 @@ ExecutionState &BatchingSearcher::selectState() { if (lastState) { double delta = util::getWallTime()-lastStartTime; if (delta>timeBudget*1.1) { - std::cerr << "KLEE: increased time budget from " << timeBudget << " to " << delta << "\n"; + llvm::errs() << "KLEE: increased time budget from " << timeBudget + << " to " << delta << "\n"; timeBudget = delta; } } @@ -580,7 +579,7 @@ void IterativeDeepeningTimeSearcher::update(ExecutionState *current, if (baseSearcher->empty()) { time *= 2; - std::cerr << "KLEE: increasing time budget to: " << time << "\n"; + llvm::errs() << "KLEE: increasing time budget to: " << time << "\n"; baseSearcher->update(0, pausedStates, std::set<ExecutionState*>()); pausedStates.clear(); } diff --git a/lib/Core/Searcher.h b/lib/Core/Searcher.h index 79c233c4..d866f521 100644 --- a/lib/Core/Searcher.h +++ b/lib/Core/Searcher.h @@ -10,18 +10,17 @@ #ifndef KLEE_SEARCHER_H #define KLEE_SEARCHER_H +#include "llvm/Support/raw_ostream.h" #include <vector> #include <set> #include <map> #include <queue> -// FIXME: Move out of header, use llvm streams. -#include <ostream> - namespace llvm { class BasicBlock; class Function; class Instruction; + class raw_ostream; } namespace klee { @@ -43,7 +42,7 @@ namespace klee { // prints name of searcher as a klee_message() // TODO: could probably make prettier or more flexible - virtual void printName(std::ostream &os) { + virtual void printName(llvm::raw_ostream &os) { os << "<unnamed searcher>\n"; } @@ -90,7 +89,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return states.empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "DFSSearcher\n"; } }; @@ -104,7 +103,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return states.empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "BFSSearcher\n"; } }; @@ -118,7 +117,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return states.empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "RandomSearcher\n"; } }; @@ -135,7 +134,6 @@ namespace klee { }; private: - Executor &executor; DiscretePDF<ExecutionState*> *states; WeightType type; bool updateWeights; @@ -143,7 +141,7 @@ namespace klee { double getWeight(ExecutionState*); public: - WeightedRandomSearcher(Executor &executor, WeightType type); + WeightedRandomSearcher(WeightType type); ~WeightedRandomSearcher(); ExecutionState &selectState(); @@ -151,7 +149,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty(); - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "WeightedRandomSearcher::"; switch(type) { case Depth : os << "Depth\n"; return; @@ -177,7 +175,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty(); - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "RandomPathSearcher\n"; } }; @@ -200,7 +198,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return baseSearcher->empty() && statesAtMerge.empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "MergingSearcher\n"; } }; @@ -223,7 +221,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return baseSearcher->empty() && statesAtMerge.empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "BumpMergingSearcher\n"; } }; @@ -248,7 +246,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return baseSearcher->empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "<BatchingSearcher> timeBudget: " << timeBudget << ", instructionBudget: " << instructionBudget << ", baseSearcher:\n"; @@ -271,7 +269,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return baseSearcher->empty() && pausedStates.empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "IterativeDeepeningTimeSearcher\n"; } }; @@ -291,7 +289,7 @@ namespace klee { const std::set<ExecutionState*> &addedStates, const std::set<ExecutionState*> &removedStates); bool empty() { return searchers[0]->empty(); } - void printName(std::ostream &os) { + void printName(llvm::raw_ostream &os) { os << "<InterleavedSearcher> containing " << searchers.size() << " searchers:\n"; for (searchers_ty::iterator it = searchers.begin(), ie = searchers.end(); diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp index 04f32780..a7a1b32e 100644 --- a/lib/Core/SpecialFunctionHandler.cpp +++ b/lib/Core/SpecialFunctionHandler.cpp @@ -27,6 +27,7 @@ #include "llvm/Module.h" #endif #include "llvm/ADT/Twine.h" +#include "llvm/Support/Debug.h" #include <errno.h> @@ -38,20 +39,14 @@ using namespace klee; /// -struct HandlerInfo { - const char *name; - SpecialFunctionHandler::Handler handler; - bool doesNotReturn; /// Intrinsic terminates the process - bool hasReturnValue; /// Intrinsic has a return value - bool doNotOverride; /// Intrinsic should not be used if already defined -}; + // FIXME: We are more or less committed to requiring an intrinsic // library these days. We can move some of this stuff there, // especially things like realloc which have complicated semantics // w.r.t. forking. Among other things this makes delayed query // dispatch easier to implement. -HandlerInfo handlerInfo[] = { +static SpecialFunctionHandler::HandlerInfo handlerInfo[] = { #define add(name, handler, ret) { name, \ &SpecialFunctionHandler::handler, \ false, ret, false } @@ -117,12 +112,37 @@ HandlerInfo handlerInfo[] = { #undef add }; +SpecialFunctionHandler::const_iterator SpecialFunctionHandler::begin() { + return SpecialFunctionHandler::const_iterator(handlerInfo); +} + +SpecialFunctionHandler::const_iterator SpecialFunctionHandler::end() { + // NULL pointer is sentinel + return SpecialFunctionHandler::const_iterator(0); +} + +SpecialFunctionHandler::const_iterator& SpecialFunctionHandler::const_iterator::operator++() { + ++index; + if ( index >= SpecialFunctionHandler::size()) + { + // Out of range, return .end() + base=0; // Sentinel + index=0; + } + + return *this; +} + +int SpecialFunctionHandler::size() { + return sizeof(handlerInfo)/sizeof(handlerInfo[0]); +} + SpecialFunctionHandler::SpecialFunctionHandler(Executor &_executor) : executor(_executor) {} void SpecialFunctionHandler::prepare() { - unsigned N = sizeof(handlerInfo)/sizeof(handlerInfo[0]); + unsigned N = size(); for (unsigned i=0; i<N; ++i) { HandlerInfo &hi = handlerInfo[i]; @@ -232,7 +252,7 @@ void SpecialFunctionHandler::handleAbort(ExecutionState &state, //XXX:DRE:TAINT if(state.underConstrained) { - std::cerr << "TAINT: skipping abort fail\n"; + llvm::errs() << "TAINT: skipping abort fail\n"; executor.terminateState(state); } else { executor.terminateStateOnError(state, "abort failure", "abort.err"); @@ -260,7 +280,8 @@ void SpecialFunctionHandler::handleAliasFunction(ExecutionState &state, "invalid number of arguments to klee_alias_function"); std::string old_fn = readStringAtAddress(state, arguments[0]); std::string new_fn = readStringAtAddress(state, arguments[1]); - //std::cerr << "Replacing " << old_fn << "() with " << new_fn << "()\n"; + DEBUG_WITH_TYPE("alias_handling", llvm::errs() << "Replacing " << old_fn + << "() with " << new_fn << "()\n"); if (old_fn == new_fn) state.removeFnAlias(old_fn); else state.addFnAlias(old_fn, new_fn); @@ -273,8 +294,8 @@ void SpecialFunctionHandler::handleAssert(ExecutionState &state, //XXX:DRE:TAINT if(state.underConstrained) { - std::cerr << "TAINT: skipping assertion:" - << readStringAtAddress(state, arguments[0]) << "\n"; + llvm::errs() << "TAINT: skipping assertion:" + << readStringAtAddress(state, arguments[0]) << "\n"; executor.terminateState(state); } else executor.terminateStateOnError(state, @@ -289,8 +310,8 @@ void SpecialFunctionHandler::handleAssertFail(ExecutionState &state, //XXX:DRE:TAINT if(state.underConstrained) { - std::cerr << "TAINT: skipping assertion:" - << readStringAtAddress(state, arguments[0]) << "\n"; + llvm::errs() << "TAINT: skipping assertion:" + << readStringAtAddress(state, arguments[0]) << "\n"; executor.terminateState(state); } else executor.terminateStateOnError(state, @@ -307,9 +328,9 @@ void SpecialFunctionHandler::handleReportError(ExecutionState &state, //XXX:DRE:TAINT if(state.underConstrained) { - std::cerr << "TAINT: skipping klee_report_error:" - << readStringAtAddress(state, arguments[2]) << ":" - << readStringAtAddress(state, arguments[3]) << "\n"; + llvm::errs() << "TAINT: skipping klee_report_error:" + << readStringAtAddress(state, arguments[2]) << ":" + << readStringAtAddress(state, arguments[3]) << "\n"; executor.terminateState(state); } else executor.terminateStateOnError(state, @@ -425,7 +446,7 @@ void SpecialFunctionHandler::handlePrintExpr(ExecutionState &state, "invalid number of arguments to klee_print_expr"); std::string msg_str = readStringAtAddress(state, arguments[0]); - std::cerr << msg_str << ":" << arguments[1] << "\n"; + llvm::errs() << msg_str << ":" << arguments[1] << "\n"; } void SpecialFunctionHandler::handleSetForking(ExecutionState &state, @@ -447,7 +468,7 @@ void SpecialFunctionHandler::handleSetForking(ExecutionState &state, void SpecialFunctionHandler::handleStackTrace(ExecutionState &state, KInstruction *target, std::vector<ref<Expr> > &arguments) { - state.dumpStack(std::cout); + state.dumpStack(outs()); } void SpecialFunctionHandler::handleWarning(ExecutionState &state, @@ -478,7 +499,7 @@ void SpecialFunctionHandler::handlePrintRange(ExecutionState &state, "invalid number of arguments to klee_print_range"); std::string msg_str = readStringAtAddress(state, arguments[0]); - std::cerr << msg_str << ":" << arguments[1]; + llvm::errs() << msg_str << ":" << arguments[1]; if (!isa<ConstantExpr>(arguments[1])) { // FIXME: Pull into a unique value method? ref<ConstantExpr> value; @@ -490,15 +511,15 @@ void SpecialFunctionHandler::handlePrintRange(ExecutionState &state, res); assert(success && "FIXME: Unhandled solver failure"); if (res) { - std::cerr << " == " << value; + llvm::errs() << " == " << value; } else { - std::cerr << " ~= " << value; + llvm::errs() << " ~= " << value; std::pair< ref<Expr>, ref<Expr> > res = executor.solver->getRange(state, arguments[1]); - std::cerr << " (in [" << res.first << ", " << res.second <<"])"; + llvm::errs() << " (in [" << res.first << ", " << res.second <<"])"; } } - std::cerr << "\n"; + llvm::errs() << "\n"; } void SpecialFunctionHandler::handleGetObjSize(ExecutionState &state, @@ -715,3 +736,5 @@ void SpecialFunctionHandler::handleMarkGlobal(ExecutionState &state, mo->isGlobal = true; } } + + diff --git a/lib/Core/SpecialFunctionHandler.h b/lib/Core/SpecialFunctionHandler.h index 02e70ed4..f68c6edb 100644 --- a/lib/Core/SpecialFunctionHandler.h +++ b/lib/Core/SpecialFunctionHandler.h @@ -10,6 +10,7 @@ #ifndef KLEE_SPECIALFUNCTIONHANDLER_H #define KLEE_SPECIALFUNCTIONHANDLER_H +#include <iterator> #include <map> #include <vector> #include <string> @@ -37,6 +38,38 @@ namespace klee { handlers_ty handlers; class Executor &executor; + struct HandlerInfo { + const char *name; + SpecialFunctionHandler::Handler handler; + bool doesNotReturn; /// Intrinsic terminates the process + bool hasReturnValue; /// Intrinsic has a return value + bool doNotOverride; /// Intrinsic should not be used if already defined + }; + + // const_iterator to iterate over stored HandlerInfo + // FIXME: Implement >, >=, <=, < operators + class const_iterator : public std::iterator<std::random_access_iterator_tag, HandlerInfo> + { + private: + value_type* base; + int index; + public: + const_iterator(value_type* hi) : base(hi), index(0) {}; + const_iterator& operator++(); // pre-fix + const_iterator operator++(int); // post-fix + const value_type& operator*() { return base[index];} + const value_type* operator->() { return &(base[index]);} + const value_type& operator[](int i) { return base[i];} + bool operator==(const_iterator& rhs) { return (rhs.base + rhs.index) == (this->base + this->index);} + bool operator!=(const_iterator& rhs) { return !(*this == rhs);} + }; + + static const_iterator begin(); + static const_iterator end(); + static int size(); + + + public: SpecialFunctionHandler(Executor &_executor); diff --git a/lib/Core/StatsTracker.cpp b/lib/Core/StatsTracker.cpp index 8161a52c..0946d2ba 100644 --- a/lib/Core/StatsTracker.cpp +++ b/lib/Core/StatsTracker.cpp @@ -46,15 +46,12 @@ #endif #include "llvm/Support/CommandLine.h" #include "llvm/Support/CFG.h" -#include "llvm/Support/raw_os_ostream.h" #include "llvm/Support/Process.h" #include "llvm/Support/Path.h" -#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 1) #include "llvm/Support/FileSystem.h" -#endif -#include <iostream> #include <fstream> +#include <unistd.h> using namespace klee; using namespace llvm; @@ -182,20 +179,15 @@ StatsTracker::StatsTracker(Executor &_executor, std::string _objectFilename, updateMinDistToUncovered(_updateMinDistToUncovered) { KModule *km = executor.kmodule; - sys::Path module(objectFilename); -#if LLVM_VERSION_CODE < LLVM_VERSION(3, 1) - if (!sys::Path(objectFilename).isAbsolute()) { -#else if (!sys::path::is_absolute(objectFilename)) { -#endif - sys::Path current = sys::Path::GetCurrentDirectory(); - current.appendComponent(objectFilename); -#if LLVM_VERSION_CODE < LLVM_VERSION(3, 1) - if (current.exists()) -#else - if (sys::fs::exists(current.c_str())) -#endif - objectFilename = current.c_str(); + SmallString<128> current(objectFilename); + if(sys::fs::make_absolute(current)) { + bool exists = false; + error_code ec = sys::fs::exists(current.str(), exists); + if (ec == errc::success && exists) { + objectFilename = current.c_str(); + } + } } if (OutputIStats) @@ -438,15 +430,16 @@ void StatsTracker::updateStateStatistics(uint64_t addend) { void StatsTracker::writeIStats() { Module *m = executor.kmodule->module; uint64_t istatsMask = 0; - std::ostream &of = *istatsFile; + llvm::raw_fd_ostream &of = *istatsFile; - of.seekp(0, std::ios::end); - unsigned istatsSize = of.tellp(); - of.seekp(0); + // We assume that we didn't move the file pointer + unsigned istatsSize = of.tell(); + + of.seek(0); of << "version: 1\n"; of << "creator: klee\n"; - of << "pid: " << sys::Process::GetCurrentUserId() << "\n"; + of << "pid: " << getpid() << "\n"; of << "cmd: " << m->getModuleIdentifier() << "\n\n"; of << "\n"; @@ -570,7 +563,7 @@ void StatsTracker::writeIStats() { updateStateStatistics((uint64_t)-1); // Clear then end of the file if necessary (no truncate op?). - unsigned pos = of.tellp(); + unsigned pos = of.tell(); for (unsigned i=pos; i<istatsSize; ++i) of << '\n'; diff --git a/lib/Core/StatsTracker.h b/lib/Core/StatsTracker.h index 8f3a01a2..629a723d 100644 --- a/lib/Core/StatsTracker.h +++ b/lib/Core/StatsTracker.h @@ -12,13 +12,13 @@ #include "CallPathManager.h" -#include <iostream> #include <set> namespace llvm { class BranchInst; class Function; class Instruction; + class raw_fd_ostream; } namespace klee { @@ -36,7 +36,7 @@ namespace klee { Executor &executor; std::string objectFilename; - std::ostream *statsFile, *istatsFile; + llvm::raw_fd_ostream *statsFile, *istatsFile; double startWallTime; unsigned numBranches; diff --git a/lib/Core/UserSearcher.cpp b/lib/Core/UserSearcher.cpp index a20ae968..72f3351f 100644 --- a/lib/Core/UserSearcher.cpp +++ b/lib/Core/UserSearcher.cpp @@ -81,12 +81,12 @@ Searcher *getNewSearcher(Searcher::CoreSearchType type, Executor &executor) { case Searcher::BFS: searcher = new BFSSearcher(); break; case Searcher::RandomState: searcher = new RandomSearcher(); break; case Searcher::RandomPath: searcher = new RandomPathSearcher(executor); break; - case Searcher::NURS_CovNew: searcher = new WeightedRandomSearcher(executor, WeightedRandomSearcher::CoveringNew); break; - case Searcher::NURS_MD2U: searcher = new WeightedRandomSearcher(executor, WeightedRandomSearcher::MinDistToUncovered); break; - case Searcher::NURS_Depth: searcher = new WeightedRandomSearcher(executor, WeightedRandomSearcher::Depth); break; - case Searcher::NURS_ICnt: searcher = new WeightedRandomSearcher(executor, WeightedRandomSearcher::InstCount); break; - case Searcher::NURS_CPICnt: searcher = new WeightedRandomSearcher(executor, WeightedRandomSearcher::CPInstCount); break; - case Searcher::NURS_QC: searcher = new WeightedRandomSearcher(executor, WeightedRandomSearcher::QueryCost); break; + case Searcher::NURS_CovNew: searcher = new WeightedRandomSearcher(WeightedRandomSearcher::CoveringNew); break; + case Searcher::NURS_MD2U: searcher = new WeightedRandomSearcher(WeightedRandomSearcher::MinDistToUncovered); break; + case Searcher::NURS_Depth: searcher = new WeightedRandomSearcher(WeightedRandomSearcher::Depth); break; + case Searcher::NURS_ICnt: searcher = new WeightedRandomSearcher(WeightedRandomSearcher::InstCount); break; + case Searcher::NURS_CPICnt: searcher = new WeightedRandomSearcher(WeightedRandomSearcher::CPInstCount); break; + case Searcher::NURS_QC: searcher = new WeightedRandomSearcher(WeightedRandomSearcher::QueryCost); break; } return searcher; @@ -129,7 +129,7 @@ Searcher *klee::constructUserSearcher(Executor &executor) { searcher = new IterativeDeepeningTimeSearcher(searcher); } - std::ostream &os = executor.getHandler().getInfoStream(); + llvm::raw_ostream &os = executor.getHandler().getInfoStream(); os << "BEGIN searcher description\n"; searcher->printName(os); diff --git a/lib/Expr/Constraints.cpp b/lib/Expr/Constraints.cpp index 90d9bcd4..ae4563f4 100644 --- a/lib/Expr/Constraints.cpp +++ b/lib/Expr/Constraints.cpp @@ -19,7 +19,6 @@ #include "llvm/Support/CommandLine.h" #include "klee/Internal/Module/KModule.h" -#include <iostream> #include <map> using namespace klee; diff --git a/lib/Expr/Expr.cpp b/lib/Expr/Expr.cpp index 82c60205..d54b8f4d 100644 --- a/lib/Expr/Expr.cpp +++ b/lib/Expr/Expr.cpp @@ -14,13 +14,13 @@ #include "llvm/ADT/Hashing.h" #endif #include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" // FIXME: We shouldn't need this once fast constant support moves into // Core. If we need to do arithmetic, we probably want to use APInt. #include "klee/Internal/Support/IntEvaluation.h" #include "klee/util/ExprPPrinter.h" -#include <iostream> #include <sstream> using namespace klee; @@ -116,7 +116,7 @@ int Expr::compare(const Expr &b, ExprEquivSet &equivs) const { return 0; } -void Expr::printKind(std::ostream &os, Kind k) { +void Expr::printKind(llvm::raw_ostream &os, Kind k) { switch(k) { #define X(C) case C: os << #C; break X(Constant); @@ -286,7 +286,7 @@ ref<Expr> Expr::createFromKind(Kind k, std::vector<CreateArg> args) { } -void Expr::printWidth(std::ostream &os, Width width) { +void Expr::printWidth(llvm::raw_ostream &os, Width width) { switch(width) { case Expr::Bool: os << "Expr::Bool"; break; case Expr::Int8: os << "Expr::Int8"; break; @@ -306,13 +306,13 @@ ref<Expr> Expr::createIsZero(ref<Expr> e) { return EqExpr::create(e, ConstantExpr::create(0, e->getWidth())); } -void Expr::print(std::ostream &os) const { +void Expr::print(llvm::raw_ostream &os) const { ExprPPrinter::printSingleExpr(os, const_cast<Expr*>(this)); } void Expr::dump() const { - this->print(std::cerr); - std::cerr << std::endl; + this->print(errs()); + errs() << "\n"; } /***/ diff --git a/lib/Expr/ExprPPrinter.cpp b/lib/Expr/ExprPPrinter.cpp index ac1d1d01..ddcc57a1 100644 --- a/lib/Expr/ExprPPrinter.cpp +++ b/lib/Expr/ExprPPrinter.cpp @@ -13,12 +13,10 @@ #include "klee/Constraints.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" #include <map> #include <vector> -#include <iostream> -#include <sstream> -#include <iomanip> using namespace klee; @@ -47,10 +45,11 @@ private: std::map<const UpdateNode*, unsigned> updateBindings; std::set< ref<Expr> > couldPrint, shouldPrint; std::set<const UpdateNode*> couldPrintUpdates, shouldPrintUpdates; - std::ostream &os; + llvm::raw_ostream &os; unsigned counter; unsigned updateCounter; bool hasScan; + bool forceNoLineBreaks; std::string newline; /// shouldPrintWidth - Predicate for whether this expression should @@ -299,7 +298,7 @@ private: } public: - PPrinter(std::ostream &_os) : os(_os), newline("\n") { + PPrinter(llvm::raw_ostream &_os) : os(_os), newline("\n") { reset(); } @@ -307,10 +306,15 @@ public: newline = _newline; } + void setForceNoLineBreaks(bool _forceNoLineBreaks) { + forceNoLineBreaks = _forceNoLineBreaks; + } + void reset() { counter = 0; updateCounter = 0; hasScan = false; + forceNoLineBreaks = false; bindings.clear(); updateBindings.clear(); couldPrint.clear(); @@ -412,7 +416,7 @@ public: /* Public utility functions */ void printSeparator(PrintContext &PC, bool simple, unsigned indent) { - if (simple) { + if (simple || forceNoLineBreaks) { PC << ' '; } else { PC.breakLine(indent); @@ -420,11 +424,11 @@ public: } }; -ExprPPrinter *klee::ExprPPrinter::create(std::ostream &os) { +ExprPPrinter *klee::ExprPPrinter::create(llvm::raw_ostream &os) { return new PPrinter(os); } -void ExprPPrinter::printOne(std::ostream &os, +void ExprPPrinter::printOne(llvm::raw_ostream &os, const char *message, const ref<Expr> &e) { PPrinter p(os); @@ -438,7 +442,7 @@ void ExprPPrinter::printOne(std::ostream &os, PC.breakLine(); } -void ExprPPrinter::printSingleExpr(std::ostream &os, const ref<Expr> &e) { +void ExprPPrinter::printSingleExpr(llvm::raw_ostream &os, const ref<Expr> &e) { PPrinter p(os); p.scan(e); @@ -448,13 +452,13 @@ void ExprPPrinter::printSingleExpr(std::ostream &os, const ref<Expr> &e) { p.print(e, PC); } -void ExprPPrinter::printConstraints(std::ostream &os, +void ExprPPrinter::printConstraints(llvm::raw_ostream &os, const ConstraintManager &constraints) { printQuery(os, constraints, ConstantExpr::alloc(false, Expr::Bool)); } -void ExprPPrinter::printQuery(std::ostream &os, +void ExprPPrinter::printQuery(llvm::raw_ostream &os, const ConstraintManager &constraints, const ref<Expr> &q, const ref<Expr> *evalExprsBegin, diff --git a/lib/Expr/ExprSMTLIBLetPrinter.cpp b/lib/Expr/ExprSMTLIBLetPrinter.cpp index 7225704e..d4243452 100644 --- a/lib/Expr/ExprSMTLIBLetPrinter.cpp +++ b/lib/Expr/ExprSMTLIBLetPrinter.cpp @@ -1,4 +1,5 @@ -//===-- ExprSMTLIBLetPrinter.cpp ------------------------------------------*- C++ -*-===// +//===-- ExprSMTLIBLetPrinter.cpp ------------------------------------------*- +//C++ -*-===// // // The KLEE Symbolic Virtual Machine // @@ -7,243 +8,225 @@ // //===----------------------------------------------------------------------===// -#include <iostream> +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/CommandLine.h" #include "klee/util/ExprSMTLIBLetPrinter.h" -using namespace std; +namespace ExprSMTLIBOptions { +llvm::cl::opt<bool> +useLetExpressions("smtlib-use-let-expressions", + llvm::cl::desc("Enables generated SMT-LIBv2 files to use " + "(let) expressions (default=on)"), + llvm::cl::init(true)); +} + +namespace klee { +const char ExprSMTLIBLetPrinter::BINDING_PREFIX[] = "?B"; -namespace ExprSMTLIBOptions -{ - llvm::cl::opt<bool> useLetExpressions("smtlib-use-let-expressions", - llvm::cl::desc("Enables generated SMT-LIBv2 files to use (let) expressions (default=on)"), - llvm::cl::init(true) - ); +ExprSMTLIBLetPrinter::ExprSMTLIBLetPrinter() + : bindings(), firstEO(), twoOrMoreEO(), disablePrintedAbbreviations(false) { } -namespace klee -{ - const char ExprSMTLIBLetPrinter::BINDING_PREFIX[] = "?B"; - - - ExprSMTLIBLetPrinter::ExprSMTLIBLetPrinter() : - bindings(), firstEO(), twoOrMoreEO(), - disablePrintedAbbreviations(false) - { - } - - void ExprSMTLIBLetPrinter::generateOutput() - { - if(p==NULL || query == NULL || o ==NULL) - { - std::cerr << "Can't print SMTLIBv2. Output or query bad!" << std::endl; - return; - } - - generateBindings(); - - if(isHumanReadable()) printNotice(); - printOptions(); - printSetLogic(); - printArrayDeclarations(); - printLetExpression(); - printAction(); - printExit(); - } - - void ExprSMTLIBLetPrinter::scan(const ref<Expr>& e) - { - if(isa<ConstantExpr>(e)) - return; //we don't need to scan simple constants - - if(firstEO.insert(e).second) - { - //We've not seen this expression before - - if(const ReadExpr* re = dyn_cast<ReadExpr>(e)) - { - - //Attempt to insert array and if array wasn't present before do more things - if(usedArrays.insert(re->updates.root).second) - { - - //check if the array is constant - if( re->updates.root->isConstantArray()) - haveConstantArray=true; - - //scan the update list - scanUpdates(re->updates.head); - - } - - } - - //recurse into the children - Expr* ep = e.get(); - for(unsigned int i=0; i < ep->getNumKids(); i++) - scan(ep->getKid(i)); - } - else - { - /* We must of seen the expression before. Add it to - * the set of twoOrMoreOccurances. We don't need to - * check if the insertion fails. - */ - twoOrMoreEO.insert(e); - } - } - - void ExprSMTLIBLetPrinter::generateBindings() - { - //Assign a number to each binding that will be used - unsigned int counter=0; - for(set<ref<Expr> >::const_iterator i=twoOrMoreEO.begin(); - i!= twoOrMoreEO.end(); ++i) - { - bindings.insert(std::make_pair(*i,counter)); - ++counter; - } - } - - void ExprSMTLIBLetPrinter::printExpression(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort) - { - map<const ref<Expr>,unsigned int>::const_iterator i= bindings.find(e); - - if(disablePrintedAbbreviations || i == bindings.end()) - { - /*There is no abbreviation for this expression so print it normally. - * Do this by using the parent method. - */ - ExprSMTLIBPrinter::printExpression(e,expectedSort); - } - else - { - //Use binding name e.g. "?B1" - - /* Handle the corner case where the expectedSort - * doesn't match the sort of the abbreviation. Not really very efficient (calls bindings.find() twice), - * we'll cast and call ourself again but with the correct expectedSort. - */ - if(getSort(e) != expectedSort) - { - printCastToSort(e,expectedSort); - return; - } - - // No casting is needed in this depth of recursion, just print the abbreviation - *p << BINDING_PREFIX << i->second; - } - } - - void ExprSMTLIBLetPrinter::reset() - { - //Let parent clean up first - ExprSMTLIBPrinter::reset(); - - firstEO.clear(); - twoOrMoreEO.clear(); - bindings.clear(); - } - - void ExprSMTLIBLetPrinter::printLetExpression() - { - *p << "(assert"; p->pushIndent(); printSeperator(); - - if(bindings.size() !=0 ) - { - //Only print let expression if we have bindings to use. - *p << "(let"; p->pushIndent(); printSeperator(); - *p << "( "; p->pushIndent(); - - //Print each binding - for(map<const ref<Expr>, unsigned int>::const_iterator i= bindings.begin(); - i!=bindings.end(); ++i) - { - printSeperator(); - *p << "(" << BINDING_PREFIX << i->second << " "; - p->pushIndent(); - - //Disable abbreviations so none are used here. - disablePrintedAbbreviations=true; - - //We can abbreviate SORT_BOOL or SORT_BITVECTOR in let expressions - printExpression(i->first,getSort(i->first)); - - p->popIndent(); - printSeperator(); - *p << ")"; - } - - - p->popIndent(); printSeperator(); - *p << ")"; - printSeperator(); - - //Re-enable printing abbreviations. - disablePrintedAbbreviations=false; - - } - - //print out Expressions with abbreviations. - unsigned int numberOfItems= query->constraints.size() +1; //+1 for query - unsigned int itemsLeft=numberOfItems; - vector<ref<Expr> >::const_iterator constraint=query->constraints.begin(); - - /* Produce nested (and () () statements. If the constraint set - * is empty then we will only print the "queryAssert". - */ - for(; itemsLeft !=0; --itemsLeft) - { - if(itemsLeft >=2) - { - *p << "(and"; p->pushIndent(); printSeperator(); - printExpression(*constraint,SORT_BOOL); //We must and together bool expressions - printSeperator(); - ++constraint; - continue; - } - else - { - // must have 1 item left (i.e. the "queryAssert") - if(isHumanReadable()) { *p << "; query"; p->breakLineI();} - printExpression(queryAssert,SORT_BOOL); //The query must be a bool expression - - } - } - - /* Produce closing brackets for nested "and statements". - * Number of "nested ands" = numberOfItems -1 - */ - itemsLeft= numberOfItems -1; - for(; itemsLeft!=0; --itemsLeft) - { - p->popIndent(); printSeperator(); - *p << ")"; - } - - - - if(bindings.size() !=0) - { - //end let expression - p->popIndent(); printSeperator(); - *p << ")"; printSeperator(); - } - - //end assert - p->popIndent(); printSeperator(); - *p << ")"; - p->breakLineI(); - } - - ExprSMTLIBPrinter* createSMTLIBPrinter() - { - if(ExprSMTLIBOptions::useLetExpressions) - return new ExprSMTLIBLetPrinter(); - else - return new ExprSMTLIBPrinter(); - } +void ExprSMTLIBLetPrinter::generateOutput() { + if (p == NULL || query == NULL || o == NULL) { + llvm::errs() << "Can't print SMTLIBv2. Output or query bad!\n"; + return; + } + + generateBindings(); + + if (isHumanReadable()) + printNotice(); + printOptions(); + printSetLogic(); + printArrayDeclarations(); + printLetExpression(); + printAction(); + printExit(); +} +void ExprSMTLIBLetPrinter::scan(const ref<Expr> &e) { + if (isa<ConstantExpr>(e)) + return; // we don't need to scan simple constants + + if (firstEO.insert(e).second) { + // We've not seen this expression before + + if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) { + + // Attempt to insert array and if array wasn't present before do more + // things + if (usedArrays.insert(re->updates.root).second) { + + // check if the array is constant + if (re->updates.root->isConstantArray()) + haveConstantArray = true; + + // scan the update list + scanUpdates(re->updates.head); + } + } + + // recurse into the children + Expr *ep = e.get(); + for (unsigned int i = 0; i < ep->getNumKids(); i++) + scan(ep->getKid(i)); + } else { + /* We must of seen the expression before. Add it to + * the set of twoOrMoreOccurances. We don't need to + * check if the insertion fails. + */ + twoOrMoreEO.insert(e); + } +} +void ExprSMTLIBLetPrinter::generateBindings() { + // Assign a number to each binding that will be used + unsigned int counter = 0; + for (std::set<ref<Expr> >::const_iterator i = twoOrMoreEO.begin(); + i != twoOrMoreEO.end(); ++i) { + bindings.insert(std::make_pair(*i, counter)); + ++counter; + } } +void ExprSMTLIBLetPrinter::printExpression( + const ref<Expr> &e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort) { + std::map<const ref<Expr>, unsigned int>::const_iterator i = bindings.find(e); + + if (disablePrintedAbbreviations || i == bindings.end()) { + /*There is no abbreviation for this expression so print it normally. + * Do this by using the parent method. + */ + ExprSMTLIBPrinter::printExpression(e, expectedSort); + } else { + // Use binding name e.g. "?B1" + + /* Handle the corner case where the expectedSort + * doesn't match the sort of the abbreviation. Not really very efficient + * (calls bindings.find() twice), + * we'll cast and call ourself again but with the correct expectedSort. + */ + if (getSort(e) != expectedSort) { + printCastToSort(e, expectedSort); + return; + } + + // No casting is needed in this depth of recursion, just print the + // abbreviation + *p << BINDING_PREFIX << i->second; + } +} + +void ExprSMTLIBLetPrinter::reset() { + // Let parent clean up first + ExprSMTLIBPrinter::reset(); + + firstEO.clear(); + twoOrMoreEO.clear(); + bindings.clear(); +} + +void ExprSMTLIBLetPrinter::printLetExpression() { + *p << "(assert"; + p->pushIndent(); + printSeperator(); + + if (bindings.size() != 0) { + // Only print let expression if we have bindings to use. + *p << "(let"; + p->pushIndent(); + printSeperator(); + *p << "( "; + p->pushIndent(); + + // Print each binding + for (std::map<const ref<Expr>, unsigned int>::const_iterator i = + bindings.begin(); + i != bindings.end(); ++i) { + printSeperator(); + *p << "(" << BINDING_PREFIX << i->second << " "; + p->pushIndent(); + + // Disable abbreviations so none are used here. + disablePrintedAbbreviations = true; + + // We can abbreviate SORT_BOOL or SORT_BITVECTOR in let expressions + printExpression(i->first, getSort(i->first)); + + p->popIndent(); + printSeperator(); + *p << ")"; + } + + p->popIndent(); + printSeperator(); + *p << ")"; + printSeperator(); + + // Re-enable printing abbreviations. + disablePrintedAbbreviations = false; + } + + // print out Expressions with abbreviations. + unsigned int numberOfItems = query->constraints.size() + 1; //+1 for query + unsigned int itemsLeft = numberOfItems; + std::vector<ref<Expr> >::const_iterator constraint = + query->constraints.begin(); + + /* Produce nested (and () () statements. If the constraint set + * is empty then we will only print the "queryAssert". + */ + for (; itemsLeft != 0; --itemsLeft) { + if (itemsLeft >= 2) { + *p << "(and"; + p->pushIndent(); + printSeperator(); + printExpression(*constraint, + SORT_BOOL); // We must and together bool expressions + printSeperator(); + ++constraint; + continue; + } else { + // must have 1 item left (i.e. the "queryAssert") + if (isHumanReadable()) { + *p << "; query"; + p->breakLineI(); + } + printExpression(queryAssert, + SORT_BOOL); // The query must be a bool expression + } + } + + /* Produce closing brackets for nested "and statements". + * Number of "nested ands" = numberOfItems -1 + */ + itemsLeft = numberOfItems - 1; + for (; itemsLeft != 0; --itemsLeft) { + p->popIndent(); + printSeperator(); + *p << ")"; + } + + if (bindings.size() != 0) { + // end let expression + p->popIndent(); + printSeperator(); + *p << ")"; + printSeperator(); + } + + // end assert + p->popIndent(); + printSeperator(); + *p << ")"; + p->breakLineI(); +} + +ExprSMTLIBPrinter *createSMTLIBPrinter() { + if (ExprSMTLIBOptions::useLetExpressions) + return new ExprSMTLIBLetPrinter(); + else + return new ExprSMTLIBPrinter(); +} +} diff --git a/lib/Expr/ExprSMTLIBPrinter.cpp b/lib/Expr/ExprSMTLIBPrinter.cpp index 9e97a4e0..bbb82d0d 100644 --- a/lib/Expr/ExprSMTLIBPrinter.cpp +++ b/lib/Expr/ExprSMTLIBPrinter.cpp @@ -1,4 +1,4 @@ -//===-- ExprSMTLIBPrinter.cpp ------------------------------------------*- C++ -*-===// +//===-- ExprSMTLIBPrinter.cpp -----------------------------------*- C++ -*-===// // // The KLEE Symbolic Virtual Machine // @@ -6,901 +6,896 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -#include <iostream> - #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "klee/util/ExprSMTLIBPrinter.h" -using namespace std; +namespace ExprSMTLIBOptions { +// Command line options +llvm::cl::opt<klee::ExprSMTLIBPrinter::ConstantDisplayMode> +argConstantDisplayMode( + "smtlib-display-constants", + llvm::cl::desc("Sets how bitvector constants are written in generated " + "SMT-LIBv2 files (default=dec)"), + llvm::cl::values(clEnumValN(klee::ExprSMTLIBPrinter::BINARY, "bin", + "Use binary form (e.g. #b00101101)"), + clEnumValN(klee::ExprSMTLIBPrinter::HEX, "hex", + "Use Hexadecimal form (e.g. #x2D)"), + clEnumValN(klee::ExprSMTLIBPrinter::DECIMAL, "dec", + "Use decimal form (e.g. (_ bv45 8) )"), + clEnumValEnd), + llvm::cl::init(klee::ExprSMTLIBPrinter::DECIMAL)); + +llvm::cl::opt<bool> humanReadableSMTLIB( + "smtlib-human-readable", + llvm::cl::desc( + "Enables generated SMT-LIBv2 files to be human readable (default=off)"), + llvm::cl::init(false)); +} + +namespace klee { + +ExprSMTLIBPrinter::ExprSMTLIBPrinter() + : usedArrays(), o(NULL), query(NULL), p(NULL), haveConstantArray(false), + logicToUse(QF_AUFBV), + humanReadable(ExprSMTLIBOptions::humanReadableSMTLIB), + smtlibBoolOptions(), arraysToCallGetValueOn(NULL) { + setConstantDisplayMode(ExprSMTLIBOptions::argConstantDisplayMode); +} + +ExprSMTLIBPrinter::~ExprSMTLIBPrinter() { + if (p != NULL) + delete p; +} + +void ExprSMTLIBPrinter::setOutput(llvm::raw_ostream &output) { + o = &output; + if (p != NULL) + delete p; + + p = new PrintContext(output); +} + +void ExprSMTLIBPrinter::setQuery(const Query &q) { + query = &q; + reset(); // clear the data structures + scanAll(); + negateQueryExpression(); +} + +void ExprSMTLIBPrinter::reset() { + usedArrays.clear(); + haveConstantArray = false; + + /* Clear the PRODUCE_MODELS option if it was automatically set. + * We need to do this because the next query might not need the + * (get-value) SMT-LIBv2 command. + */ + if (arraysToCallGetValueOn != NULL) + setSMTLIBboolOption(PRODUCE_MODELS, OPTION_DEFAULT); + + arraysToCallGetValueOn = NULL; +} + +bool ExprSMTLIBPrinter::isHumanReadable() { return humanReadable; } + +bool ExprSMTLIBPrinter::setConstantDisplayMode(ConstantDisplayMode cdm) { + if (cdm > DECIMAL) + return false; + + this->cdm = cdm; + return true; +} + +void ExprSMTLIBPrinter::printConstant(const ref<ConstantExpr> &e) { + /* Handle simple boolean constants */ + + if (e->isTrue()) { + *p << "true"; + return; + } + + if (e->isFalse()) { + *p << "false"; + return; + } + + /* Handle bitvector constants */ + + std::string value; + + /* SMTLIBv2 deduces the bit-width (should be 8-bits in our case) + * from the length of the string (e.g. zero is #b00000000). LLVM + * doesn't know about this so we need to pad the printed output + * with the appropriate number of zeros (zeroPad) + */ + unsigned int zeroPad = 0; -namespace ExprSMTLIBOptions -{ - //Command line options - llvm::cl::opt<klee::ExprSMTLIBPrinter::ConstantDisplayMode> argConstantDisplayMode - ("smtlib-display-constants", llvm::cl::desc("Sets how bitvector constants are written in generated SMT-LIBv2 files (default=dec)"), - llvm::cl::values( clEnumValN(klee::ExprSMTLIBPrinter::BINARY, "bin","Use binary form (e.g. #b00101101)"), - clEnumValN(klee::ExprSMTLIBPrinter::HEX, "hex","Use Hexadecimal form (e.g. #x2D)"), - clEnumValN(klee::ExprSMTLIBPrinter::DECIMAL, "dec","Use decimal form (e.g. (_ bv45 8) )"), - clEnumValEnd - ), - llvm::cl::init(klee::ExprSMTLIBPrinter::DECIMAL) + switch (cdm) { + case BINARY: + e->toString(value, 2); + *p << "#b"; + zeroPad = e->getWidth() - value.length(); - ); + for (unsigned int count = 0; count < zeroPad; count++) + *p << "0"; - llvm::cl::opt<bool> humanReadableSMTLIB("smtlib-human-readable", - llvm::cl::desc("Enables generated SMT-LIBv2 files to be human readable (default=off)"), - llvm::cl::init(false) + *p << value; + break; + case HEX: + e->toString(value, 16); + *p << "#x"; - ); + zeroPad = (e->getWidth() / 4) - value.length(); + for (unsigned int count = 0; count < zeroPad; count++) + *p << "0"; + *p << value; + break; + + case DECIMAL: + e->toString(value, 10); + *p << "(_ bv" << value << " " << e->getWidth() << ")"; + break; + + default: + llvm::errs() << "ExprSMTLIBPrinter::printConstant() : Unexpected Constant " + "display mode\n"; + } +} + +void ExprSMTLIBPrinter::printExpression( + const ref<Expr> &e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort) { + // check if casting might be necessary + if (getSort(e) != expectedSort) { + printCastToSort(e, expectedSort); + return; + } + + switch (e->getKind()) { + case Expr::Constant: + printConstant(cast<ConstantExpr>(e)); + return; // base case + + case Expr::NotOptimized: + // skip to child + printExpression(e->getKid(0), expectedSort); + return; + + case Expr::Read: + printReadExpr(cast<ReadExpr>(e)); + return; + + case Expr::Extract: + printExtractExpr(cast<ExtractExpr>(e)); + return; + + case Expr::SExt: + case Expr::ZExt: + printCastExpr(cast<CastExpr>(e)); + return; + + case Expr::Ne: + printNotEqualExpr(cast<NeExpr>(e)); + return; + + case Expr::Select: + // the if-then-else expression. + printSelectExpr(cast<SelectExpr>(e), expectedSort); + return; + + case Expr::Eq: + /* The "=" operator is special in that it can take any sort but we must + * enforce that both arguments are the same type. We do this a lazy way + * by enforcing the second argument is of the same type as the first. + */ + printSortArgsExpr(e, getSort(e->getKid(0))); + + return; + + case Expr::And: + case Expr::Or: + case Expr::Xor: + case Expr::Not: + /* These operators have a bitvector version and a bool version. + * For these operators only (e.g. wouldn't apply to bvult) if the expected + * sort the + * expression is T then that implies the arguments are also of type T. + */ + printLogicalOrBitVectorExpr(e, expectedSort); + + return; + + default: + /* The remaining operators (Add,Sub...,Ult,Ule,..) + * Expect SORT_BITVECTOR arguments + */ + printSortArgsExpr(e, SORT_BITVECTOR); + return; + } +} + +void ExprSMTLIBPrinter::printReadExpr(const ref<ReadExpr> &e) { + *p << "(" << getSMTLIBKeyword(e) << " "; + p->pushIndent(); + + printSeperator(); + + // print array with updates recursively + printUpdatesAndArray(e->updates.head, e->updates.root); + + // print index + printSeperator(); + printExpression(e->index, SORT_BITVECTOR); + + p->popIndent(); + printSeperator(); + *p << ")"; +} + +void ExprSMTLIBPrinter::printExtractExpr(const ref<ExtractExpr> &e) { + unsigned int lowIndex = e->offset; + unsigned int highIndex = lowIndex + e->width - 1; + + *p << "((_ " << getSMTLIBKeyword(e) << " " << highIndex << " " << lowIndex + << ") "; + + p->pushIndent(); // add indent for recursive call + printSeperator(); + + // recurse + printExpression(e->getKid(0), SORT_BITVECTOR); + + p->popIndent(); // pop indent added for the recursive call + printSeperator(); + *p << ")"; } +void ExprSMTLIBPrinter::printCastExpr(const ref<CastExpr> &e) { + /* sign_extend and zero_extend behave slightly unusually in SMTLIBv2 + * instead of specifying of what bit-width we would like to extend to + * we specify how many bits to add to the child expression + * + * e.g + * ((_ sign_extend 64) (_ bv5 32)) + * + * gives a (_ BitVec 96) instead of (_ BitVec 64) + * + * So we must work out how many bits we need to add. + * + * (e->width) is the desired number of bits + * (e->src->getWidth()) is the number of bits in the child + */ + unsigned int numExtraBits = (e->width) - (e->src->getWidth()); + + *p << "((_ " << getSMTLIBKeyword(e) << " " << numExtraBits << ") "; + + p->pushIndent(); // add indent for recursive call + printSeperator(); + + // recurse + printExpression(e->src, SORT_BITVECTOR); + + p->popIndent(); // pop indent added for recursive call + printSeperator(); + + *p << ")"; +} -namespace klee -{ +void ExprSMTLIBPrinter::printNotEqualExpr(const ref<NeExpr> &e) { + *p << "(not ("; + p->pushIndent(); + *p << "=" + << " "; + p->pushIndent(); + printSeperator(); + + /* The "=" operators allows both sorts. We assume + * that the second argument sort should be forced to be the same sort as the + * first argument + */ + SMTLIB_SORT s = getSort(e->getKid(0)); + + printExpression(e->getKid(0), s); + printSeperator(); + printExpression(e->getKid(1), s); + p->popIndent(); + printSeperator(); + + *p << ")"; + p->popIndent(); + printSeperator(); + *p << ")"; +} - ExprSMTLIBPrinter::ExprSMTLIBPrinter() : - usedArrays(), o(NULL), query(NULL), p(NULL), haveConstantArray(false), logicToUse(QF_AUFBV), - humanReadable(ExprSMTLIBOptions::humanReadableSMTLIB), smtlibBoolOptions(), arraysToCallGetValueOn(NULL) - { - setConstantDisplayMode(ExprSMTLIBOptions::argConstantDisplayMode); - } +const char *ExprSMTLIBPrinter::getSMTLIBKeyword(const ref<Expr> &e) { + + switch (e->getKind()) { + case Expr::Read: + return "select"; + case Expr::Select: + return "ite"; + case Expr::Concat: + return "concat"; + case Expr::Extract: + return "extract"; + case Expr::ZExt: + return "zero_extend"; + case Expr::SExt: + return "sign_extend"; + + case Expr::Add: + return "bvadd"; + case Expr::Sub: + return "bvsub"; + case Expr::Mul: + return "bvmul"; + case Expr::UDiv: + return "bvudiv"; + case Expr::SDiv: + return "bvsdiv"; + case Expr::URem: + return "bvurem"; + case Expr::SRem: + return "bvsrem"; + + /* And, Xor, Not and Or are not handled here because there different versions + * for different sorts. See printLogicalOrBitVectorExpr() + */ + + case Expr::Shl: + return "bvshl"; + case Expr::LShr: + return "bvlshr"; + case Expr::AShr: + return "bvashr"; + + case Expr::Eq: + return "="; + + // Not Equal does not exist directly in SMTLIBv2 + + case Expr::Ult: + return "bvult"; + case Expr::Ule: + return "bvule"; + case Expr::Ugt: + return "bvugt"; + case Expr::Uge: + return "bvuge"; + + case Expr::Slt: + return "bvslt"; + case Expr::Sle: + return "bvsle"; + case Expr::Sgt: + return "bvsgt"; + case Expr::Sge: + return "bvsge"; + + default: + return "<error>"; + } +} - ExprSMTLIBPrinter::~ExprSMTLIBPrinter() - { - if(p!=NULL) - delete p; - } +void ExprSMTLIBPrinter::printUpdatesAndArray(const UpdateNode *un, + const Array *root) { + if (un != NULL) { + *p << "(store "; + p->pushIndent(); + printSeperator(); - void ExprSMTLIBPrinter::setOutput(std::ostream& output) - { - o = &output; - if(p!=NULL) - delete p; + // recurse to get the array or update that this store operations applies to + printUpdatesAndArray(un->next, root); - p = new PrintContext(output); - } + printSeperator(); - void ExprSMTLIBPrinter::setQuery(const Query& q) - { - query = &q; - reset(); // clear the data structures - scanAll(); - negateQueryExpression(); - } + // print index + printExpression(un->index, SORT_BITVECTOR); + printSeperator(); - void ExprSMTLIBPrinter::reset() - { - usedArrays.clear(); - haveConstantArray=false; + // print value that is assigned to this index of the array + printExpression(un->value, SORT_BITVECTOR); - /* Clear the PRODUCE_MODELS option if it was automatically set. - * We need to do this because the next query might not need the - * (get-value) SMT-LIBv2 command. - */ - if(arraysToCallGetValueOn !=NULL) - setSMTLIBboolOption(PRODUCE_MODELS,OPTION_DEFAULT); + p->popIndent(); + printSeperator(); + *p << ")"; + } else { + // The base case of the recursion + *p << root->name; + } +} - arraysToCallGetValueOn=NULL; +void ExprSMTLIBPrinter::scanAll() { + // perform scan of all expressions + for (ConstraintManager::const_iterator i = query->constraints.begin(); + i != query->constraints.end(); i++) + scan(*i); + // Scan the query too + scan(query->expr); +} + +void ExprSMTLIBPrinter::generateOutput() { + if (p == NULL || query == NULL || o == NULL) { + llvm::errs() << "ExprSMTLIBPrinter::generateOutput() Can't print SMTLIBv2. " + "Output or query bad!\n"; + return; + } + + if (humanReadable) + printNotice(); + printOptions(); + printSetLogic(); + printArrayDeclarations(); + printConstraints(); + printQuery(); + printAction(); + printExit(); +} - } +void ExprSMTLIBPrinter::printSetLogic() { + *o << "(set-logic "; + switch (logicToUse) { + case QF_ABV: + *o << "QF_ABV"; + break; + case QF_AUFBV: + *o << "QF_AUFBV"; + break; + } + *o << " )\n"; +} - bool ExprSMTLIBPrinter::isHumanReadable() - { - return humanReadable; - } +namespace { - bool ExprSMTLIBPrinter::setConstantDisplayMode(ConstantDisplayMode cdm) - { - if(cdm > DECIMAL) - return false; +struct ArrayPtrsByName { + bool operator()(const Array *a1, const Array *a2) const { + return a1->name < a2->name; + } +}; - this->cdm = cdm; - return true; - } +} - void ExprSMTLIBPrinter::printConstant(const ref<ConstantExpr>& e) - { - /* Handle simple boolean constants */ - - if(e->isTrue()) - { - *p << "true"; - return; - } - - if(e->isFalse()) - { - *p << "false"; - return; - } - - /* Handle bitvector constants */ - - std::string value; - - /* SMTLIBv2 deduces the bit-width (should be 8-bits in our case) - * from the length of the string (e.g. zero is #b00000000). LLVM - * doesn't know about this so we need to pad the printed output - * with the appropriate number of zeros (zeroPad) - */ - unsigned int zeroPad=0; - - switch(cdm) - { - case BINARY: - e->toString(value,2); - *p << "#b"; - - zeroPad = e->getWidth() - value.length(); - - for(unsigned int count=0; count < zeroPad; count++) - *p << "0"; - - *p << value ; - break; - - case HEX: - e->toString(value,16); - *p << "#x"; - - zeroPad = (e->getWidth() / 4) - value.length(); - for(unsigned int count=0; count < zeroPad; count++) - *p << "0"; - - *p << value ; - break; - - case DECIMAL: - e->toString(value,10); - *p << "(_ bv" << value<< " " << e->getWidth() << ")"; - break; - - default: - std::cerr << "ExprSMTLIBPrinter::printConstant() : Unexpected Constant display mode" << std::endl; - } - } - - void ExprSMTLIBPrinter::printExpression(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort) - { - //check if casting might be necessary - if(getSort(e) != expectedSort) - { - printCastToSort(e,expectedSort); - return; - } - - - switch(e->getKind()) - { - case Expr::Constant: - printConstant(cast<ConstantExpr>(e)); - return; //base case - - case Expr::NotOptimized: - //skip to child - printExpression(e->getKid(0),expectedSort); - return; - - case Expr::Read: - printReadExpr(cast<ReadExpr>(e)); - return; - - case Expr::Extract: - printExtractExpr(cast<ExtractExpr>(e)); - return; - - case Expr::SExt: - case Expr::ZExt: - printCastExpr(cast<CastExpr>(e)); - return; - - case Expr::Ne: - printNotEqualExpr(cast<NeExpr>(e)); - return; - - case Expr::Select: - //the if-then-else expression. - printSelectExpr(cast<SelectExpr>(e),expectedSort); - return; - - case Expr::Eq: - /* The "=" operator is special in that it can take any sort but we must - * enforce that both arguments are the same type. We do this a lazy way - * by enforcing the second argument is of the same type as the first. - */ - printSortArgsExpr(e,getSort(e->getKid(0))); - - return; - - case Expr::And: - case Expr::Or: - case Expr::Xor: - case Expr::Not: - /* These operators have a bitvector version and a bool version. - * For these operators only (e.g. wouldn't apply to bvult) if the expected sort the - * expression is T then that implies the arguments are also of type T. - */ - printLogicalOrBitVectorExpr(e,expectedSort); - - return; - - - default: - /* The remaining operators (Add,Sub...,Ult,Ule,..) - * Expect SORT_BITVECTOR arguments - */ - printSortArgsExpr(e,SORT_BITVECTOR); - return; - } - } - - void ExprSMTLIBPrinter::printReadExpr(const ref<ReadExpr>& e) - { - *p << "(" << getSMTLIBKeyword(e) << " "; - p->pushIndent(); - - printSeperator(); - - //print array with updates recursively - printUpdatesAndArray(e->updates.head,e->updates.root); - - //print index - printSeperator(); - printExpression(e->index,SORT_BITVECTOR); - - p->popIndent(); - printSeperator(); - *p << ")"; - } - - void ExprSMTLIBPrinter::printExtractExpr(const ref<ExtractExpr>& e) - { - unsigned int lowIndex= e->offset; - unsigned int highIndex= lowIndex + e->width -1; - - *p << "((_ " << getSMTLIBKeyword(e) << " " << highIndex << " " << lowIndex << ") "; - - p->pushIndent(); //add indent for recursive call - printSeperator(); - - //recurse - printExpression(e->getKid(0),SORT_BITVECTOR); - - p->popIndent(); //pop indent added for the recursive call - printSeperator(); - *p << ")"; - } - - void ExprSMTLIBPrinter::printCastExpr(const ref<CastExpr>& e) - { - /* sign_extend and zero_extend behave slightly unusually in SMTLIBv2 - * instead of specifying of what bit-width we would like to extend to - * we specify how many bits to add to the child expression - * - * e.g - * ((_ sign_extend 64) (_ bv5 32)) - * - * gives a (_ BitVec 96) instead of (_ BitVec 64) - * - * So we must work out how many bits we need to add. - * - * (e->width) is the desired number of bits - * (e->src->getWidth()) is the number of bits in the child - */ - unsigned int numExtraBits= (e->width) - (e->src->getWidth()); - - *p << "((_ " << getSMTLIBKeyword(e) << " " << - numExtraBits << ") "; - - p->pushIndent(); //add indent for recursive call - printSeperator(); - - //recurse - printExpression(e->src,SORT_BITVECTOR); - - p->popIndent(); //pop indent added for recursive call - printSeperator(); - - *p << ")"; - } - - void ExprSMTLIBPrinter::printNotEqualExpr(const ref<NeExpr>& e) - { - *p << "(not ("; - p->pushIndent(); - *p << "=" << " "; - p->pushIndent(); - printSeperator(); - - /* The "=" operators allows both sorts. We assume - * that the second argument sort should be forced to be the same sort as the - * first argument - */ - SMTLIB_SORT s = getSort(e->getKid(0)); - - printExpression(e->getKid(0),s); - printSeperator(); - printExpression(e->getKid(1),s); - p->popIndent(); - printSeperator(); - - *p << ")"; - p->popIndent(); - printSeperator(); - *p << ")"; - } - - - const char* ExprSMTLIBPrinter::getSMTLIBKeyword(const ref<Expr>& e) - { - - switch(e->getKind()) - { - case Expr::Read: return "select"; - case Expr::Select: return "ite"; - case Expr::Concat: return "concat"; - case Expr::Extract: return "extract"; - case Expr::ZExt: return "zero_extend"; - case Expr::SExt: return "sign_extend"; - - case Expr::Add: return "bvadd"; - case Expr::Sub: return "bvsub"; - case Expr::Mul: return "bvmul"; - case Expr::UDiv: return "bvudiv"; - case Expr::SDiv: return "bvsdiv"; - case Expr::URem: return "bvurem"; - case Expr::SRem: return "bvsrem"; - - - /* And, Xor, Not and Or are not handled here because there different versions - * for different sorts. See printLogicalOrBitVectorExpr() - */ - - - case Expr::Shl: return "bvshl"; - case Expr::LShr: return "bvlshr"; - case Expr::AShr: return "bvashr"; - - case Expr::Eq: return "="; - - //Not Equal does not exist directly in SMTLIBv2 - - case Expr::Ult: return "bvult"; - case Expr::Ule: return "bvule"; - case Expr::Ugt: return "bvugt"; - case Expr::Uge: return "bvuge"; - - case Expr::Slt: return "bvslt"; - case Expr::Sle: return "bvsle"; - case Expr::Sgt: return "bvsgt"; - case Expr::Sge: return "bvsge"; - - default: - return "<error>"; - - } - } - - void ExprSMTLIBPrinter::printUpdatesAndArray(const UpdateNode* un, const Array* root) - { - if(un!=NULL) - { - *p << "(store "; - p->pushIndent(); - printSeperator(); - - //recurse to get the array or update that this store operations applies to - printUpdatesAndArray(un->next,root); - - printSeperator(); - - //print index - printExpression(un->index,SORT_BITVECTOR); - printSeperator(); - - //print value that is assigned to this index of the array - printExpression(un->value,SORT_BITVECTOR); - - p->popIndent(); - printSeperator(); - *p << ")"; - } - else - { - //The base case of the recursion - *p << root->name; - } - - } - - void ExprSMTLIBPrinter::scanAll() - { - //perform scan of all expressions - for(ConstraintManager::const_iterator i= query->constraints.begin(); i != query->constraints.end(); i++) - scan(*i); - - //Scan the query too - scan(query->expr); - } - - void ExprSMTLIBPrinter::generateOutput() - { - if(p==NULL || query == NULL || o ==NULL) - { - std::cerr << "ExprSMTLIBPrinter::generateOutput() Can't print SMTLIBv2. Output or query bad!" << std::endl; - return; - } - - if(humanReadable) printNotice(); - printOptions(); - printSetLogic(); - printArrayDeclarations(); - printConstraints(); - printQuery(); - printAction(); - printExit(); - } - - void ExprSMTLIBPrinter::printSetLogic() - { - *o << "(set-logic "; - switch(logicToUse) - { - case QF_ABV: *o << "QF_ABV"; break; - case QF_AUFBV: *o << "QF_AUFBV" ; break; - } - *o << " )" << std::endl; - } - - - void ExprSMTLIBPrinter::printArrayDeclarations() - { - //Assume scan() has been called - if(humanReadable) - *o << "; Array declarations" << endl; - - //declare arrays - for(set<const Array*>::iterator it = usedArrays.begin(); it != usedArrays.end(); it++) - { - *o << "(declare-fun " << (*it)->name << " () " - "(Array (_ BitVec " << (*it)->getDomain() << ") " - "(_ BitVec " << (*it)->getRange() << ") ) )" << endl; - } - - //Set array values for constant values - if(haveConstantArray) - { - if(humanReadable) - *o << "; Constant Array Definitions" << endl; - - const Array* array; - - //loop over found arrays - for(set<const Array*>::iterator it = usedArrays.begin(); it != usedArrays.end(); it++) - { - array= *it; - int byteIndex=0; - if(array->isConstantArray()) - { - /*loop over elements in the array and generate an assert statement - for each one - */ - for(vector< ref<ConstantExpr> >::const_iterator ce= array->constantValues.begin(); - ce != array->constantValues.end(); ce++, byteIndex++) - { - *p << "(assert ("; - p->pushIndent(); - *p << "= "; - p->pushIndent(); - printSeperator(); - - *p << "(select " << array->name << " (_ bv" << byteIndex << " " << array->getDomain() << ") )"; - printSeperator(); - printConstant((*ce)); - - p->popIndent(); - printSeperator(); - *p << ")"; - p->popIndent(); - printSeperator(); - *p << ")"; - - p->breakLineI(); - - } - } - } - } - } - - void ExprSMTLIBPrinter::printConstraints() - { - if(humanReadable) - *o << "; Constraints" << endl; - - //Generate assert statements for each constraint - for(ConstraintManager::const_iterator i= query->constraints.begin(); i != query->constraints.end(); i++) - { - *p << "(assert "; - p->pushIndent(); - printSeperator(); - - //recurse into Expression - printExpression(*i,SORT_BOOL); - - p->popIndent(); - printSeperator(); - *p << ")"; p->breakLineI(); - } - - } - - void ExprSMTLIBPrinter::printAction() - { - //Ask solver to check for satisfiability - *o << "(check-sat)" << endl; - - /* If we has arrays to find the values of then we'll - * ask the solver for the value of each bitvector in each array - */ - if(arraysToCallGetValueOn!=NULL && !arraysToCallGetValueOn->empty()) - { - - const Array* theArray=0; - - //loop over the array names - for(vector<const Array*>::const_iterator it = arraysToCallGetValueOn->begin(); it != arraysToCallGetValueOn->end(); it++) - { - theArray=*it; - //Loop over the array indices - for(unsigned int index=0; index < theArray->size; ++index) - { - *o << "(get-value ( (select " << (**it).name << - " (_ bv" << index << " " << theArray->getDomain() << ") ) ) )" << endl; - } - - } - - - } - } - - void ExprSMTLIBPrinter::scan(const ref<Expr>& e) - { - if(e.isNull()) - { - std::cerr << "ExprSMTLIBPrinter::scan() : Found NULL expression!" << std::endl; - return; - } - - if(isa<ConstantExpr>(e)) - return; //we don't need to scan simple constants - - if(const ReadExpr* re = dyn_cast<ReadExpr>(e)) - { - - //Attempt to insert array and if array wasn't present before do more things - if(usedArrays.insert(re->updates.root).second) - { - - //check if the array is constant - if( re->updates.root->isConstantArray()) - haveConstantArray=true; - - //scan the update list - scanUpdates(re->updates.head); - - } - - } - - //recurse into the children - Expr* ep = e.get(); - for(unsigned int i=0; i < ep->getNumKids(); i++) - scan(ep->getKid(i)); - } - - - void ExprSMTLIBPrinter::scanUpdates(const UpdateNode* un) - { - while(un != NULL) - { - scan(un->index); - scan(un->value); - un= un->next; - } - } - - - void ExprSMTLIBPrinter::printExit() - { - *o << "(exit)" << endl; - } - - bool ExprSMTLIBPrinter::setLogic(SMTLIBv2Logic l) - { - if(l > QF_AUFBV) - return false; - - logicToUse=l; - return true; - } - - void ExprSMTLIBPrinter::printSeperator() - { - if(humanReadable) - p->breakLineI(); - else - p->write(" "); - } - - void ExprSMTLIBPrinter::printNotice() - { - *o << "; This file conforms to SMTLIBv2 and was generated by KLEE" << endl; - } - - void ExprSMTLIBPrinter::setHumanReadable(bool hr) - { - humanReadable=hr; - } - - void ExprSMTLIBPrinter::printOptions() - { - //Print out SMTLIBv2 boolean options - for(std::map<SMTLIBboolOptions,bool>::const_iterator i= smtlibBoolOptions.begin(); i!= smtlibBoolOptions.end(); i++) - { - *o << "(set-option :" << getSMTLIBOptionString(i->first) << - " " << ((i->second)?"true":"false") << ")" << endl; - } - } - - void ExprSMTLIBPrinter::printQuery() - { - if(humanReadable) - { - *p << "; Query from solver turned into an assert"; - p->breakLineI(); - } - - p->pushIndent(); - *p << "(assert"; - p->pushIndent(); - printSeperator(); - - printExpression(queryAssert,SORT_BOOL); - - p->popIndent(); - printSeperator(); - *p << ")"; - p->popIndent(); - p->breakLineI(); - } - - ExprSMTLIBPrinter::SMTLIB_SORT ExprSMTLIBPrinter::getSort(const ref<Expr>& e) - { - /* We could handle every operator in a large switch statement, - * but this seems more elegant. - */ - - if(e->getKind() == Expr::Extract) - { - /* This is a special corner case. In most cases if a node in the expression tree - * is of width 1 it should be considered as SORT_BOOL. However it is possible to - * perform an extract operation on a SORT_BITVECTOR and produce a SORT_BITVECTOR of length 1. - * The ((_ extract i j) () ) operation in SMTLIBv2 always produces SORT_BITVECTOR - */ - return SORT_BITVECTOR; - } - else - return (e->getWidth() == Expr::Bool)?(SORT_BOOL):(SORT_BITVECTOR); - } - - void ExprSMTLIBPrinter::printCastToSort(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT sort) - { - switch(sort) - { - case SORT_BITVECTOR: - if(humanReadable) - { - p->breakLineI(); *p << ";Performing implicit bool to bitvector cast"; p->breakLine(); - } - //We assume the e is a bool that we need to cast to a bitvector sort. - *p << "(ite"; p->pushIndent(); printSeperator(); - printExpression(e,SORT_BOOL); printSeperator(); - *p << "(_ bv1 1)" ; printSeperator(); //printing the "true" bitvector - *p << "(_ bv0 1)" ; p->popIndent(); printSeperator(); //printing the "false" bitvector - *p << ")"; - break; - case SORT_BOOL: - { - /* We make the assumption (might be wrong) that any bitvector whos unsigned decimal value is - * is zero is interpreted as "false", otherwise it is true. - * - * This may not be the interpretation we actually want! - */ - Expr::Width bitWidth=e->getWidth(); - if(humanReadable) - { - p->breakLineI(); *p << ";Performing implicit bitvector to bool cast"; p->breakLine(); - } - *p << "(bvugt"; p->pushIndent(); printSeperator(); - // We assume is e is a bitvector - printExpression(e,SORT_BITVECTOR); printSeperator(); - *p << "(_ bv0 " << bitWidth << ")"; p->popIndent(); printSeperator(); //Zero bitvector of required width - *p << ")"; - - if(bitWidth!=Expr::Bool) - std::cerr << "ExprSMTLIBPrinter : Warning. Casting a bitvector (length " << bitWidth << ") to bool!" << std::endl; - - } - break; - default: - assert(0 && "Unsupported cast!"); - } - } - - void ExprSMTLIBPrinter::printSelectExpr(const ref<SelectExpr>& e, ExprSMTLIBPrinter::SMTLIB_SORT s) - { - //This is the if-then-else expression - - *p << "(" << getSMTLIBKeyword(e) << " "; - p->pushIndent(); //add indent for recursive call - - //The condition - printSeperator(); - printExpression(e->getKid(0),SORT_BOOL); - - /* This operator is special in that the remaining children - * can be of any sort. - */ - - //if true - printSeperator(); - printExpression(e->getKid(1),s); - - //if false - printSeperator(); - printExpression(e->getKid(2),s); - - - p->popIndent(); //pop indent added for recursive call - printSeperator(); - *p << ")"; - } - - void ExprSMTLIBPrinter::printSortArgsExpr(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT s) - { - *p << "(" << getSMTLIBKeyword(e) << " "; - p->pushIndent(); //add indent for recursive call - - //loop over children and recurse into each expecting they are of sort "s" - for(unsigned int i=0; i < e->getNumKids(); i++) - { - printSeperator(); - printExpression(e->getKid(i),s); - } - - p->popIndent(); //pop indent added for recursive call - printSeperator(); - *p << ")"; - } - - void ExprSMTLIBPrinter::printLogicalOrBitVectorExpr(const ref<Expr>& e, ExprSMTLIBPrinter::SMTLIB_SORT s) - { - /* For these operators it is the case that the expected sort is the same as the sorts - * of the arguments. - */ - - *p << "("; - switch(e->getKind()) - { - case Expr::And: - *p << ((s==SORT_BITVECTOR)?"bvand":"and"); - break; - case Expr::Not: - *p << ((s==SORT_BITVECTOR)?"bvnot":"not"); - break; - case Expr::Or: - *p << ((s==SORT_BITVECTOR)?"bvor":"or"); - break; - - case Expr::Xor: - *p << ((s==SORT_BITVECTOR)?"bvxor":"xor"); - break; - default: - *p << "ERROR"; // this shouldn't happen - } - *p << " "; - - p->pushIndent(); //add indent for recursive call - - //loop over children and recurse into each expecting they are of sort "s" - for(unsigned int i=0; i < e->getNumKids(); i++) - { - printSeperator(); - printExpression(e->getKid(i),s); - } - - p->popIndent(); //pop indent added for recursive call - printSeperator(); - *p << ")"; - } - - void ExprSMTLIBPrinter::negateQueryExpression() - { - //Negating the query - queryAssert = Expr::createIsZero(query->expr); - } - - bool ExprSMTLIBPrinter::setSMTLIBboolOption(SMTLIBboolOptions option, SMTLIBboolValues value) - { - std::pair< std::map<SMTLIBboolOptions,bool>::iterator, bool> thePair; - bool theValue= (value==OPTION_TRUE)?true:false; - - switch(option) - { - case PRINT_SUCCESS: - case PRODUCE_MODELS: - case INTERACTIVE_MODE: - thePair=smtlibBoolOptions.insert(std::pair<SMTLIBboolOptions,bool>(option,theValue)); - - if(value== OPTION_DEFAULT) - { - //we should unset (by removing from map) this option so the solver uses its default - smtlibBoolOptions.erase(thePair.first); - return true; - } - - if(!thePair.second) - { - //option was already present so modify instead. - thePair.first->second=value; - } - return true; - default: - return false; - - } - } - - void ExprSMTLIBPrinter::setArrayValuesToGet(const std::vector<const Array*>& a) - { - arraysToCallGetValueOn = &a; - - //This option must be set in order to use the SMTLIBv2 command (get-value () ) - if(!a.empty()) - setSMTLIBboolOption(PRODUCE_MODELS,OPTION_TRUE); - - /* There is a risk that users will ask about array values that aren't - * even in the query. We should add them to the usedArrays list and hope - * that the solver knows what to do when we ask for the values of arrays - * that don't feature in our query! - */ - for(vector<const Array*>::const_iterator i = a.begin(); i!= a.end() ; ++i) - { - usedArrays.insert(*i); - } - - } - -const char* ExprSMTLIBPrinter::getSMTLIBOptionString(ExprSMTLIBPrinter::SMTLIBboolOptions option) -{ - switch(option) - { - case PRINT_SUCCESS: return "print-success"; - case PRODUCE_MODELS: return "produce-models"; - case INTERACTIVE_MODE: return "interactive-mode"; - default: - return "unknown-option"; - } +void ExprSMTLIBPrinter::printArrayDeclarations() { + // Assume scan() has been called + if (humanReadable) + *o << "; Array declarations\n"; + + // Declare arrays in a deterministic order. + std::vector<const Array *> sortedArrays(usedArrays.begin(), usedArrays.end()); + std::sort(sortedArrays.begin(), sortedArrays.end(), ArrayPtrsByName()); + for (std::vector<const Array *>::iterator it = sortedArrays.begin(); + it != sortedArrays.end(); it++) { + *o << "(declare-fun " << (*it)->name << " () " + "(Array (_ BitVec " + << (*it)->getDomain() << ") " + "(_ BitVec " << (*it)->getRange() << ") ) )" + << "\n"; + } + + // Set array values for constant values + if (haveConstantArray) { + if (humanReadable) + *o << "; Constant Array Definitions\n"; + + const Array *array; + + // loop over found arrays + for (std::vector<const Array *>::iterator it = sortedArrays.begin(); + it != sortedArrays.end(); it++) { + array = *it; + int byteIndex = 0; + if (array->isConstantArray()) { + /*loop over elements in the array and generate an assert statement + for each one + */ + for (std::vector<ref<ConstantExpr> >::const_iterator + ce = array->constantValues.begin(); + ce != array->constantValues.end(); ce++, byteIndex++) { + *p << "(assert ("; + p->pushIndent(); + *p << "= "; + p->pushIndent(); + printSeperator(); + + *p << "(select " << array->name << " (_ bv" << byteIndex << " " + << array->getDomain() << ") )"; + printSeperator(); + printConstant((*ce)); + + p->popIndent(); + printSeperator(); + *p << ")"; + p->popIndent(); + printSeperator(); + *p << ")"; + + p->breakLineI(); + } + } + } + } } +void ExprSMTLIBPrinter::printConstraints() { + if (humanReadable) + *o << "; Constraints\n"; + + // Generate assert statements for each constraint + for (ConstraintManager::const_iterator i = query->constraints.begin(); + i != query->constraints.end(); i++) { + *p << "(assert "; + p->pushIndent(); + printSeperator(); + + // recurse into Expression + printExpression(*i, SORT_BOOL); + + p->popIndent(); + printSeperator(); + *p << ")"; + p->breakLineI(); + } } +void ExprSMTLIBPrinter::printAction() { + // Ask solver to check for satisfiability + *o << "(check-sat)\n"; + + /* If we has arrays to find the values of then we'll + * ask the solver for the value of each bitvector in each array + */ + if (arraysToCallGetValueOn != NULL && !arraysToCallGetValueOn->empty()) { + + const Array *theArray = 0; + + // loop over the array names + for (std::vector<const Array *>::const_iterator it = + arraysToCallGetValueOn->begin(); + it != arraysToCallGetValueOn->end(); it++) { + theArray = *it; + // Loop over the array indices + for (unsigned int index = 0; index < theArray->size; ++index) { + *o << "(get-value ( (select " << (**it).name << " (_ bv" << index << " " + << theArray->getDomain() << ") ) ) )\n"; + } + } + } +} +void ExprSMTLIBPrinter::scan(const ref<Expr> &e) { + if (e.isNull()) { + llvm::errs() << "ExprSMTLIBPrinter::scan() : Found NULL expression!" + << "\n"; + return; + } + if (isa<ConstantExpr>(e)) + return; // we don't need to scan simple constants + + if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) { + + // Attempt to insert array and if array wasn't present before do more things + if (usedArrays.insert(re->updates.root).second) { + + // check if the array is constant + if (re->updates.root->isConstantArray()) + haveConstantArray = true; + + // scan the update list + scanUpdates(re->updates.head); + } + } + + // recurse into the children + Expr *ep = e.get(); + for (unsigned int i = 0; i < ep->getNumKids(); i++) + scan(ep->getKid(i)); +} + +void ExprSMTLIBPrinter::scanUpdates(const UpdateNode *un) { + while (un != NULL) { + scan(un->index); + scan(un->value); + un = un->next; + } +} + +void ExprSMTLIBPrinter::printExit() { *o << "(exit)\n"; } + +bool ExprSMTLIBPrinter::setLogic(SMTLIBv2Logic l) { + if (l > QF_AUFBV) + return false; + + logicToUse = l; + return true; +} + +void ExprSMTLIBPrinter::printSeperator() { + if (humanReadable) + p->breakLineI(); + else + p->write(" "); +} + +void ExprSMTLIBPrinter::printNotice() { + *o << "; This file conforms to SMTLIBv2 and was generated by KLEE\n"; +} + +void ExprSMTLIBPrinter::setHumanReadable(bool hr) { humanReadable = hr; } + +void ExprSMTLIBPrinter::printOptions() { + // Print out SMTLIBv2 boolean options + for (std::map<SMTLIBboolOptions, bool>::const_iterator i = + smtlibBoolOptions.begin(); + i != smtlibBoolOptions.end(); i++) { + *o << "(set-option :" << getSMTLIBOptionString(i->first) << " " + << ((i->second) ? "true" : "false") << ")\n"; + } +} + +void ExprSMTLIBPrinter::printQuery() { + if (humanReadable) { + *p << "; Query from solver turned into an assert"; + p->breakLineI(); + } + + p->pushIndent(); + *p << "(assert"; + p->pushIndent(); + printSeperator(); + + printExpression(queryAssert, SORT_BOOL); + + p->popIndent(); + printSeperator(); + *p << ")"; + p->popIndent(); + p->breakLineI(); +} + +ExprSMTLIBPrinter::SMTLIB_SORT ExprSMTLIBPrinter::getSort(const ref<Expr> &e) { + switch (e->getKind()) { + case Expr::NotOptimized: + return getSort(e->getKid(0)); + + // The relational operators are bools. + case Expr::Eq: + case Expr::Ne: + case Expr::Slt: + case Expr::Sle: + case Expr::Sgt: + case Expr::Sge: + case Expr::Ult: + case Expr::Ule: + case Expr::Ugt: + case Expr::Uge: + return SORT_BOOL; + + // These may be bitvectors or bools depending on their width (see + // printConstant and printLogicalOrBitVectorExpr). + case Expr::Constant: + case Expr::And: + case Expr::Not: + case Expr::Or: + case Expr::Xor: + return e->getWidth() == Expr::Bool ? SORT_BOOL : SORT_BITVECTOR; + + // Everything else is a bitvector. + default: + return SORT_BITVECTOR; + } +} + +void ExprSMTLIBPrinter::printCastToSort(const ref<Expr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT sort) { + switch (sort) { + case SORT_BITVECTOR: + if (humanReadable) { + p->breakLineI(); + *p << ";Performing implicit bool to bitvector cast"; + p->breakLine(); + } + // We assume the e is a bool that we need to cast to a bitvector sort. + *p << "(ite"; + p->pushIndent(); + printSeperator(); + printExpression(e, SORT_BOOL); + printSeperator(); + *p << "(_ bv1 1)"; + printSeperator(); // printing the "true" bitvector + *p << "(_ bv0 1)"; + p->popIndent(); + printSeperator(); // printing the "false" bitvector + *p << ")"; + break; + case SORT_BOOL: { + /* We make the assumption (might be wrong) that any bitvector whos unsigned + *decimal value is + * is zero is interpreted as "false", otherwise it is true. + * + * This may not be the interpretation we actually want! + */ + Expr::Width bitWidth = e->getWidth(); + if (humanReadable) { + p->breakLineI(); + *p << ";Performing implicit bitvector to bool cast"; + p->breakLine(); + } + *p << "(bvugt"; + p->pushIndent(); + printSeperator(); + // We assume is e is a bitvector + printExpression(e, SORT_BITVECTOR); + printSeperator(); + *p << "(_ bv0 " << bitWidth << ")"; + p->popIndent(); + printSeperator(); // Zero bitvector of required width + *p << ")"; + + if (bitWidth != Expr::Bool) + llvm::errs() + << "ExprSMTLIBPrinter : Warning. Casting a bitvector (length " + << bitWidth << ") to bool!\n"; + + } break; + default: + assert(0 && "Unsupported cast!"); + } +} + +void ExprSMTLIBPrinter::printSelectExpr(const ref<SelectExpr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT s) { + // This is the if-then-else expression + + *p << "(" << getSMTLIBKeyword(e) << " "; + p->pushIndent(); // add indent for recursive call + + // The condition + printSeperator(); + printExpression(e->getKid(0), SORT_BOOL); + + /* This operator is special in that the remaining children + * can be of any sort. + */ + + // if true + printSeperator(); + printExpression(e->getKid(1), s); + + // if false + printSeperator(); + printExpression(e->getKid(2), s); + + p->popIndent(); // pop indent added for recursive call + printSeperator(); + *p << ")"; +} + +void ExprSMTLIBPrinter::printSortArgsExpr(const ref<Expr> &e, + ExprSMTLIBPrinter::SMTLIB_SORT s) { + *p << "(" << getSMTLIBKeyword(e) << " "; + p->pushIndent(); // add indent for recursive call + + // loop over children and recurse into each expecting they are of sort "s" + for (unsigned int i = 0; i < e->getNumKids(); i++) { + printSeperator(); + printExpression(e->getKid(i), s); + } + + p->popIndent(); // pop indent added for recursive call + printSeperator(); + *p << ")"; +} + +void ExprSMTLIBPrinter::printLogicalOrBitVectorExpr( + const ref<Expr> &e, ExprSMTLIBPrinter::SMTLIB_SORT s) { + /* For these operators it is the case that the expected sort is the same as + * the sorts + * of the arguments. + */ + + *p << "("; + switch (e->getKind()) { + case Expr::And: + *p << ((s == SORT_BITVECTOR) ? "bvand" : "and"); + break; + case Expr::Not: + *p << ((s == SORT_BITVECTOR) ? "bvnot" : "not"); + break; + case Expr::Or: + *p << ((s == SORT_BITVECTOR) ? "bvor" : "or"); + break; + + case Expr::Xor: + *p << ((s == SORT_BITVECTOR) ? "bvxor" : "xor"); + break; + default: + *p << "ERROR"; // this shouldn't happen + } + *p << " "; + + p->pushIndent(); // add indent for recursive call + + // loop over children and recurse into each expecting they are of sort "s" + for (unsigned int i = 0; i < e->getNumKids(); i++) { + printSeperator(); + printExpression(e->getKid(i), s); + } + + p->popIndent(); // pop indent added for recursive call + printSeperator(); + *p << ")"; +} + +void ExprSMTLIBPrinter::negateQueryExpression() { + // Negating the query + queryAssert = Expr::createIsZero(query->expr); +} + +bool ExprSMTLIBPrinter::setSMTLIBboolOption(SMTLIBboolOptions option, + SMTLIBboolValues value) { + std::pair<std::map<SMTLIBboolOptions, bool>::iterator, bool> thePair; + bool theValue = (value == OPTION_TRUE) ? true : false; + + switch (option) { + case PRINT_SUCCESS: + case PRODUCE_MODELS: + case INTERACTIVE_MODE: + thePair = smtlibBoolOptions.insert( + std::pair<SMTLIBboolOptions, bool>(option, theValue)); + + if (value == OPTION_DEFAULT) { + // we should unset (by removing from map) this option so the solver uses + // its default + smtlibBoolOptions.erase(thePair.first); + return true; + } + + if (!thePair.second) { + // option was already present so modify instead. + thePair.first->second = value; + } + return true; + default: + return false; + } +} + +void +ExprSMTLIBPrinter::setArrayValuesToGet(const std::vector<const Array *> &a) { + arraysToCallGetValueOn = &a; + + // This option must be set in order to use the SMTLIBv2 command (get-value () + // ) + if (!a.empty()) + setSMTLIBboolOption(PRODUCE_MODELS, OPTION_TRUE); + + /* There is a risk that users will ask about array values that aren't + * even in the query. We should add them to the usedArrays list and hope + * that the solver knows what to do when we ask for the values of arrays + * that don't feature in our query! + */ + for (std::vector<const Array *>::const_iterator i = a.begin(); i != a.end(); + ++i) { + usedArrays.insert(*i); + } +} + +const char *ExprSMTLIBPrinter::getSMTLIBOptionString( + ExprSMTLIBPrinter::SMTLIBboolOptions option) { + switch (option) { + case PRINT_SUCCESS: + return "print-success"; + case PRODUCE_MODELS: + return "produce-models"; + case INTERACTIVE_MODE: + return "interactive-mode"; + default: + return "unknown-option"; + } +} +} diff --git a/lib/Expr/Lexer.cpp b/lib/Expr/Lexer.cpp index 9859ff36..e250a968 100644 --- a/lib/Expr/Lexer.cpp +++ b/lib/Expr/Lexer.cpp @@ -13,7 +13,6 @@ #include "llvm/Support/raw_ostream.h" #include <iomanip> -#include <iostream> #include <string.h> using namespace llvm; diff --git a/lib/Expr/Makefile b/lib/Expr/Makefile index b80569b3..25557600 100644 --- a/lib/Expr/Makefile +++ b/lib/Expr/Makefile @@ -12,5 +12,6 @@ LEVEL=../.. LIBRARYNAME=kleaverExpr DONT_BUILD_RELINKED=1 BUILD_ARCHIVE=1 +NO_INSTALL=1 include $(LEVEL)/Makefile.common diff --git a/lib/Expr/Parser.cpp b/lib/Expr/Parser.cpp index 5b3e96b7..aebce666 100644 --- a/lib/Expr/Parser.cpp +++ b/lib/Expr/Parser.cpp @@ -22,7 +22,6 @@ #include "llvm/Support/raw_ostream.h" #include <cassert> -#include <iostream> #include <map> #include <cstring> @@ -1522,7 +1521,7 @@ void ParserImpl::Error(const char *Message, const Token &At) { if (MaxErrors && NumErrors >= MaxErrors) return; - std::cerr << Filename + llvm::errs() << Filename << ":" << At.line << ":" << At.column << ": error: " << Message << "\n"; @@ -1544,18 +1543,18 @@ void ParserImpl::Error(const char *Message, const Token &At) { ++LineEnd; // Show the line. - std::cerr << std::string(LineBegin, LineEnd) << "\n"; + llvm::errs() << std::string(LineBegin, LineEnd) << "\n"; // Show the caret or squiggly, making sure to print back spaces the // same. for (const char *S=LineBegin; S != At.start; ++S) - std::cerr << (isspace(*S) ? *S : ' '); + llvm::errs() << (isspace(*S) ? *S : ' '); if (At.length > 1) { for (unsigned i=0; i<At.length; ++i) - std::cerr << '~'; + llvm::errs() << '~'; } else - std::cerr << '^'; - std::cerr << '\n'; + llvm::errs() << '^'; + llvm::errs() << '\n'; } // AST API @@ -1564,20 +1563,20 @@ void ParserImpl::Error(const char *Message, const Token &At) { Decl::Decl(DeclKind _Kind) : Kind(_Kind) {} void ArrayDecl::dump() { - std::cout << "array " << Root->name + llvm::outs() << "array " << Root->name << "[" << Root->size << "]" << " : " << 'w' << Domain << " -> " << 'w' << Range << " = "; if (Root->isSymbolicArray()) { - std::cout << "symbolic\n"; + llvm::outs() << "symbolic\n"; } else { - std::cout << '['; + llvm::outs() << '['; for (unsigned i = 0, e = Root->size; i != e; ++i) { if (i) - std::cout << " "; - std::cout << Root->constantValues[i]; + llvm::outs() << " "; + llvm::outs() << Root->constantValues[i]; } - std::cout << "]\n"; + llvm::outs() << "]\n"; } } @@ -1592,7 +1591,7 @@ void QueryCommand::dump() { ObjectsBegin = &Objects[0]; ObjectsEnd = ObjectsBegin + Objects.size(); } - ExprPPrinter::printQuery(std::cout, ConstraintManager(Constraints), + ExprPPrinter::printQuery(llvm::outs(), ConstraintManager(Constraints), Query, ValuesBegin, ValuesEnd, ObjectsBegin, ObjectsEnd, false); diff --git a/lib/Expr/Updates.cpp b/lib/Expr/Updates.cpp index 14fd8308..bf7049ba 100644 --- a/lib/Expr/Updates.cpp +++ b/lib/Expr/Updates.cpp @@ -22,8 +22,12 @@ UpdateNode::UpdateNode(const UpdateNode *_next, next(_next), index(_index), value(_value) { + // FIXME: What we need to check here instead is that _value is of the same width + // as the range of the array that the update node is part of. + /* assert(_value->getWidth() == Expr::Int8 && "Update value should be 8-bit wide."); + */ computeHash(); if (next) { ++next->refCount; @@ -84,6 +88,12 @@ UpdateList &UpdateList::operator=(const UpdateList &b) { } void UpdateList::extend(const ref<Expr> &index, const ref<Expr> &value) { + + if (root) { + assert(root->getDomain() == index->getWidth()); + assert(root->getRange() == value->getWidth()); + } + if (head) --head->refCount; head = new UpdateNode(head, index, value); ++head->refCount; diff --git a/lib/Module/Checks.cpp b/lib/Module/Checks.cpp index 79fd4afc..e1076d43 100644 --- a/lib/Module/Checks.cpp +++ b/lib/Module/Checks.cpp @@ -46,7 +46,6 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Support/CallSite.h" -#include <iostream> using namespace llvm; using namespace klee; @@ -83,7 +82,12 @@ bool DivCheckPass::runOnModule(Module &M) { divZeroCheckFunction = cast<Function>(fc); } - CallInst::Create(divZeroCheckFunction, denominator, "", &*i); + CallInst * ci = CallInst::Create(divZeroCheckFunction, denominator, "", &*i); + + // Set debug location of checking call to that of the div/rem + // operation so error locations are reported in the correct + // location. + ci->setDebugLoc(binOp->getDebugLoc()); moduleChanged = true; } } @@ -138,11 +142,14 @@ bool OvershiftCheckPass::runOnModule(Module &M) { } // Inject CallInstr to check if overshifting possible + CallInst* ci = #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 0) CallInst::Create(overshiftCheckFunction, args, "", &*i); #else CallInst::Create(overshiftCheckFunction, args.begin(), args.end(), "", &*i); #endif + // set debug information from binary operand to preserve it + ci->setDebugLoc(binOp->getDebugLoc()); moduleChanged = true; } } diff --git a/lib/Module/InstructionInfoTable.cpp b/lib/Module/InstructionInfoTable.cpp index 301db1ff..19d7e511 100644 --- a/lib/Module/InstructionInfoTable.cpp +++ b/lib/Module/InstructionInfoTable.cpp @@ -33,6 +33,7 @@ #include "llvm/Analysis/DebugInfo.h" #endif #include "llvm/Analysis/ValueTracking.h" +#include "llvm/Support/Debug.h" #include <map> #include <string> @@ -108,64 +109,35 @@ InstructionInfoTable::InstructionInfoTable(Module *m) for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); fnIt != fn_ie; ++fnIt) { - const std::string *initialFile = &dummyString; - unsigned initialLine = 0; - - // It may be better to look for the closest stoppoint to the entry - // following the CFG, but it is not clear that it ever matters in - // practice. - for (inst_iterator it = inst_begin(fnIt), ie = inst_end(fnIt); - it != ie; ++it) - if (getInstructionDebugInfo(&*it, initialFile, initialLine)) - break; - - typedef std::map<BasicBlock*, std::pair<const std::string*,unsigned> > - sourceinfo_ty; - sourceinfo_ty sourceInfo; - for (llvm::Function::iterator bbIt = fnIt->begin(), bbie = fnIt->end(); - bbIt != bbie; ++bbIt) { - std::pair<sourceinfo_ty::iterator, bool> - res = sourceInfo.insert(std::make_pair(bbIt, - std::make_pair(initialFile, - initialLine))); - if (!res.second) - continue; - - std::vector<BasicBlock*> worklist; - worklist.push_back(bbIt); - - do { - BasicBlock *bb = worklist.back(); - worklist.pop_back(); - - sourceinfo_ty::iterator si = sourceInfo.find(bb); - assert(si != sourceInfo.end()); - const std::string *file = si->second.first; - unsigned line = si->second.second; - - for (BasicBlock::iterator it = bb->begin(), ie = bb->end(); - it != ie; ++it) { - Instruction *instr = it; - unsigned assemblyLine = 0; - std::map<const Instruction*, unsigned>::const_iterator ltit = - lineTable.find(instr); - if (ltit!=lineTable.end()) - assemblyLine = ltit->second; - getInstructionDebugInfo(instr, file, line); - infos.insert(std::make_pair(instr, - InstructionInfo(id++, - *file, - line, - assemblyLine))); - } - - for (succ_iterator it = succ_begin(bb), ie = succ_end(bb); - it != ie; ++it) { - if (sourceInfo.insert(std::make_pair(*it, - std::make_pair(file, line))).second) - worklist.push_back(*it); - } - } while (!worklist.empty()); + + for (inst_iterator it = inst_begin(fnIt), ie = inst_end(fnIt); it != ie; + ++it) { + const std::string *initialFile = &dummyString; + unsigned initialLine = 0; + Instruction *instr = &*it; + unsigned assemblyLine = 0; + + std::map<const Instruction*, unsigned>::const_iterator ltit = + lineTable.find(instr); + if (ltit!=lineTable.end()) + assemblyLine = ltit->second; + if (getInstructionDebugInfo(instr, initialFile, initialLine)) + { + infos.insert(std::make_pair(instr, + InstructionInfo(id++, + *initialFile, + initialLine, + assemblyLine))); + DEBUG_WITH_TYPE("klee_obtained_debug", dbgs() << + "Instruction: \"" << *instr << "\" (assembly line " << assemblyLine << + ") has debug location " << *initialFile << ":" << initialLine << "\n"); + } + else + { + DEBUG_WITH_TYPE("klee_missing_debug", dbgs() << + "Instruction: \"" << *instr << "\" (assembly line " << assemblyLine << + ") is missing debug info.\n"); + } } } } diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index d889b51f..697b6ea9 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -182,7 +182,8 @@ static void injectStaticConstructorsAndDestructors(Module *m) { if (ctors || dtors) { Function *mainFn = m->getFunction("main"); - assert(mainFn && "unable to find main function"); + if (!mainFn) + klee_error("Could not find main() function."); if (ctors) CallInst::Create(getStubFunctionForCtorList(m, ctors, "klee.ctor_stub"), @@ -229,7 +230,7 @@ static void forceImport(Module *m, const char *name, LLVM_TYPE_Q Type *retType, /// It is intended that this function be used for inling calls to /// check functions like <tt>klee_div_zero_check()</tt> static void inlineChecks(Module *module, const char * functionName) { - std::vector<CallInst*> checkCalls; + std::vector<CallSite> checkCalls; Function* runtimeCheckCall = module->getFunction(functionName); if (runtimeCheckCall == 0) { @@ -237,22 +238,19 @@ static void inlineChecks(Module *module, const char * functionName) { return; } - // Iterate through instructions in module and collect all - // call instructions to "functionName" that we care about. - for (Module::iterator f = module->begin(), fe = module->end(); f != fe; ++f) { - for (inst_iterator i=inst_begin(f), ie = inst_end(f); i != ie; ++i) { - if ( CallInst* ci = dyn_cast<CallInst>(&*i) ) - { - if ( ci->getCalledFunction() == runtimeCheckCall) - checkCalls.push_back(ci); - } + for (Value::use_iterator i = runtimeCheckCall->use_begin(), + e = runtimeCheckCall->use_end(); i != e; ++i) + if (isa<InvokeInst>(*i) || isa<CallInst>(*i)) { + CallSite cs(*i); + if (!cs.getCalledFunction()) + continue; + checkCalls.push_back(cs); } - } unsigned int successCount=0; unsigned int failCount=0; InlineFunctionInfo IFI(0,0); - for ( std::vector<CallInst*>::iterator ci = checkCalls.begin(), + for ( std::vector<CallSite>::iterator ci = checkCalls.begin(), cie = checkCalls.end(); ci != cie; ++ci) { @@ -269,6 +267,17 @@ static void inlineChecks(Module *module, const char * functionName) { DEBUG( klee_message("Tried to inline calls to %s. %u successes, %u failures",functionName, successCount, failCount) ); } +void KModule::addInternalFunction(const char* functionName){ + Function* internalFunction = module->getFunction(functionName); + if (!internalFunction) { + DEBUG_WITH_TYPE("KModule", klee_warning( + "Failed to add internal function %s. Not found.", functionName)); + return ; + } + DEBUG( klee_message("Added function %s.",functionName)); + internalFunctions.insert(internalFunction); +} + void KModule::prepare(const Interpreter::ModuleOptions &opts, InterpreterHandler *ih) { if (!MergeAtExit.empty()) { @@ -366,25 +375,23 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, // FIXME: Find a way that we can test programs without requiring // this to be linked in, it makes low level debugging much more // annoying. - llvm::sys::Path path(opts.LibraryDir); -#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) - path.appendComponent("kleeRuntimeIntrinsic.bc"); + + SmallString<128> LibPath(opts.LibraryDir); + llvm::sys::path::append(LibPath, +#if LLVM_VERSION_CODE >= LLVM_VERSION(3,3) + "kleeRuntimeIntrinsic.bc" #else - path.appendComponent("libkleeRuntimeIntrinsic.bca"); + "libkleeRuntimeIntrinsic.bca" #endif - module = linkWithLibrary(module, path.c_str()); - - /* In order for KLEE to report ALL errors at instrumented - * locations the instrumentation call (e.g. "klee_div_zero_check") - * must be inlined. Otherwise one of the instructions in the - * instrumentation function will be used as the the location of - * the error which means that the error cannot be recorded again - * ( unless -emit-all-errors is used). - */ + ); + module = linkWithLibrary(module, LibPath.str()); + + // Add internal functions which are not used to check if instructions + // have been already visited if (opts.CheckDivZero) - inlineChecks(module, "klee_div_zero_check"); + addInternalFunction("klee_div_zero_check"); if (opts.CheckOvershift) - inlineChecks(module, "klee_overshift_check"); + addInternalFunction("klee_overshift_check"); // Needs to happen after linking (since ctors/dtors can be modified) @@ -423,15 +430,13 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, // around a kcachegrind parsing bug (it puts them on new lines), so // that source browsing works. if (OutputSource) { - std::ostream *os = ih->openOutputFile("assembly.ll"); - assert(os && os->good() && "unable to open source output"); - - llvm::raw_os_ostream *ros = new llvm::raw_os_ostream(*os); + llvm::raw_fd_ostream *os = ih->openOutputFile("assembly.ll"); + assert(os && !os->has_error() && "unable to open source output"); // We have an option for this in case the user wants a .ll they // can compile. if (NoTruncateSourceLines) { - *ros << *module; + *os << *module; } else { std::string string; llvm::raw_string_ostream rss(string); @@ -442,30 +447,26 @@ void KModule::prepare(const Interpreter::ModuleOptions &opts, for (;;) { const char *end = index(position, '\n'); if (!end) { - *ros << position; + *os << position; break; } else { unsigned count = (end - position) + 1; if (count<255) { - ros->write(position, count); + os->write(position, count); } else { - ros->write(position, 254); - *ros << "\n"; + os->write(position, 254); + *os << "\n"; } position = end+1; } } } - delete ros; - delete os; } if (OutputModule) { - std::ostream *f = ih->openOutputFile("final.bc"); - llvm::raw_os_ostream* rfs = new llvm::raw_os_ostream(*f); - WriteBitcodeToFile(module, *rfs); - delete rfs; + llvm::raw_fd_ostream *f = ih->openOutputFile("final.bc"); + WriteBitcodeToFile(module, *f); delete f; } diff --git a/lib/Module/Makefile b/lib/Module/Makefile index bfd7c469..091a7d45 100755 --- a/lib/Module/Makefile +++ b/lib/Module/Makefile @@ -12,5 +12,6 @@ LEVEL=../.. LIBRARYNAME=kleeModule DONT_BUILD_RELINKED=1 BUILD_ARCHIVE=1 +NO_INSTALL=1 include $(LEVEL)/Makefile.common diff --git a/lib/Module/ModuleUtil.cpp b/lib/Module/ModuleUtil.cpp index fcdfa35a..d00cf574 100644 --- a/lib/Module/ModuleUtil.cpp +++ b/lib/Module/ModuleUtil.cpp @@ -9,6 +9,13 @@ #include "klee/Internal/Support/ModuleUtil.h" #include "klee/Config/Version.h" +// FIXME: This does not belong here. +#include "../Core/Common.h" +#include "../Core/SpecialFunctionHandler.h" + +#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 4) +#include "llvm/IR/LLVMContext.h" +#endif #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) #include "llvm/Bitcode/ReaderWriter.h" @@ -17,6 +24,11 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IRReader/IRReader.h" #include "llvm/IR/Module.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/IR/ValueSymbolTable.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/DataStream.h" #else @@ -30,13 +42,14 @@ #include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/Support/CFG.h" #include "llvm/Support/CallSite.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/InstIterator.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Support/Path.h" #include <map> -#include <iostream> +#include <set> #include <fstream> #include <sstream> #include <string> @@ -44,18 +57,349 @@ using namespace llvm; using namespace klee; +#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) +/// Based on GetAllUndefinedSymbols() from LLVM3.2 +/// +/// GetAllUndefinedSymbols - calculates the set of undefined symbols that still +/// exist in an LLVM module. This is a bit tricky because there may be two +/// symbols with the same name but different LLVM types that will be resolved to +/// each other but aren't currently (thus we need to treat it as resolved). +/// +/// Inputs: +/// M - The module in which to find undefined symbols. +/// +/// Outputs: +/// UndefinedSymbols - A set of C++ strings containing the name of all +/// undefined symbols. +/// +static void +GetAllUndefinedSymbols(Module *M, std::set<std::string> &UndefinedSymbols) { + static const std::string llvmIntrinsicPrefix="llvm."; + std::set<std::string> DefinedSymbols; + UndefinedSymbols.clear(); + DEBUG_WITH_TYPE("klee_linker", dbgs() << "*** Computing undefined symbols ***\n"); + + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (I->hasName()) { + if (I->isDeclaration()) + UndefinedSymbols.insert(I->getName()); + else if (!I->hasLocalLinkage()) { + assert(!I->hasDLLImportLinkage() + && "Found dllimported non-external symbol!"); + DefinedSymbols.insert(I->getName()); + } + } + + for (Module::global_iterator I = M->global_begin(), E = M->global_end(); + I != E; ++I) + if (I->hasName()) { + if (I->isDeclaration()) + UndefinedSymbols.insert(I->getName()); + else if (!I->hasLocalLinkage()) { + assert(!I->hasDLLImportLinkage() + && "Found dllimported non-external symbol!"); + DefinedSymbols.insert(I->getName()); + } + } + + for (Module::alias_iterator I = M->alias_begin(), E = M->alias_end(); + I != E; ++I) + if (I->hasName()) + DefinedSymbols.insert(I->getName()); + + + // Prune out any defined symbols from the undefined symbols set + // and other symbols we don't want to treat as an undefined symbol + std::vector<std::string> SymbolsToRemove; + for (std::set<std::string>::iterator I = UndefinedSymbols.begin(); + I != UndefinedSymbols.end(); ++I ) + { + if (DefinedSymbols.count(*I)) + { + SymbolsToRemove.push_back(*I); + continue; + } + + // Strip out llvm intrinsics + if ( (I->size() >= llvmIntrinsicPrefix.size() ) && + (I->compare(0, llvmIntrinsicPrefix.size(), llvmIntrinsicPrefix) == 0) ) + { + DEBUG_WITH_TYPE("klee_linker", dbgs() << "LLVM intrinsic " << *I << + " has will be removed from undefined symbols"<< "\n"); + SymbolsToRemove.push_back(*I); + continue; + } + + // Symbol really is undefined + DEBUG_WITH_TYPE("klee_linker", dbgs() << "Symbol " << *I << " is undefined.\n"); + } + + // Remove KLEE intrinsics from set of undefined symbols + for (SpecialFunctionHandler::const_iterator sf = SpecialFunctionHandler::begin(), + se = SpecialFunctionHandler::end(); sf != se; ++sf) + { + if (UndefinedSymbols.find(sf->name) == UndefinedSymbols.end()) + continue; + + SymbolsToRemove.push_back(sf->name); + DEBUG_WITH_TYPE("klee_linker", dbgs() << "KLEE intrinsic " << sf->name << + " has will be removed from undefined symbols"<< "\n"); + } + + // Now remove the symbols from undefined set. + for (size_t i = 0, j = SymbolsToRemove.size(); i < j; ++i ) + UndefinedSymbols.erase(SymbolsToRemove[i]); + + DEBUG_WITH_TYPE("klee_linker", dbgs() << "*** Finished computing undefined symbols ***\n"); +} + + +/*! A helper function for linkBCA() which cleans up + * memory allocated by that function. + */ +static void CleanUpLinkBCA(std::vector<Module*> &archiveModules) +{ + for (std::vector<Module*>::iterator I = archiveModules.begin(), E = archiveModules.end(); + I != E; ++I) + { + delete (*I); + } +} + +/*! A helper function for klee::linkWithLibrary() that links in an archive of bitcode + * modules into a composite bitcode module + * + * \param[in] archive Archive of bitcode modules + * \param[in,out] composite The bitcode module to link against the archive + * \param[out] errorMessage Set to an error message if linking fails + * + * \return True if linking succeeds otherwise false + */ +static bool linkBCA(object::Archive* archive, Module* composite, std::string& errorMessage) +{ + llvm::raw_string_ostream SS(errorMessage); + std::vector<Module*> archiveModules; + + // Is this efficient? Could we use StringRef instead? + std::set<std::string> undefinedSymbols; + GetAllUndefinedSymbols(composite, undefinedSymbols); + + if (undefinedSymbols.size() == 0) + { + // Nothing to do + DEBUG_WITH_TYPE("klee_linker", dbgs() << "No undefined symbols. Not linking anything in!\n"); + return true; + } + + DEBUG_WITH_TYPE("klee_linker", dbgs() << "Loading modules\n"); + // Load all bitcode files in to memory so we can examine their symbols + for (object::Archive::child_iterator AI = archive->begin_children(), + AE = archive->end_children(); AI != AE; ++AI) + { + + StringRef memberName; + error_code ec = AI->getName(memberName); + + if ( ec == errc::success ) + { + DEBUG_WITH_TYPE("klee_linker", dbgs() << "Loading archive member " << memberName << "\n"); + } + else + { + errorMessage="Archive member does not have a name!\n"; + return false; + } + + OwningPtr<object::Binary> child; + ec = AI->getAsBinary(child); + if (ec != object::object_error::success) + { + // If we can't open as a binary object file its hopefully a bitcode file + + OwningPtr<MemoryBuffer> buff; // Once this is destroyed will Module still be valid?? + Module *Result = 0; + + if (error_code ec = AI->getMemoryBuffer(buff)) + { + SS << "Failed to get MemoryBuffer: " <<ec.message(); + SS.flush(); + return false; + } + + if (buff) + { + // FIXME: Maybe load bitcode file lazily? Then if we need to link, materialise the module + Result = ParseBitcodeFile(buff.get(), getGlobalContext(), &errorMessage); + + if(!Result) + { + SS << "Loading module failed : " << errorMessage << "\n"; + SS.flush(); + return false; + } + archiveModules.push_back(Result); + } + else + { + errorMessage="Buffer was NULL!"; + return false; + } + + } + else if (object::ObjectFile *o = dyn_cast<object::ObjectFile>(child.get())) + { + SS << "Object file " << o->getFileName().data() << + " in archive is not supported"; + SS.flush(); + return false; + } + else + { + SS << "Loading archive child with error "<< ec.message(); + SS.flush(); + return false; + } + + } + + DEBUG_WITH_TYPE("klee_linker", dbgs() << "Loaded " << archiveModules.size() << " modules\n"); + + + std::set<std::string> previouslyUndefinedSymbols; + + // Walk through the modules looking for definitions of undefined symbols + // if we find a match we should link that module in. + unsigned int passCounter=0; + do + { + unsigned int modulesLoadedOnPass=0; + previouslyUndefinedSymbols = undefinedSymbols; + + for (size_t i = 0, j = archiveModules.size(); i < j; ++i) + { + // skip empty archives + if (archiveModules[i] == 0) + continue; + Module * M = archiveModules[i]; + // Look for the undefined symbols in the composite module + for (std::set<std::string>::iterator S = undefinedSymbols.begin(), SE = undefinedSymbols.end(); + S != SE; ++S) + { + + // FIXME: We aren't handling weak symbols here! + // However the algorithm used in LLVM3.2 didn't seem to either + // so maybe it doesn't matter? + + if ( GlobalValue* GV = dyn_cast_or_null<GlobalValue>(M->getValueSymbolTable().lookup(*S))) + { + if (GV->isDeclaration()) continue; // Not a definition + + DEBUG_WITH_TYPE("klee_linker", dbgs() << "Found " << GV->getName() << + " in " << M->getModuleIdentifier() << "\n"); + + + if (Linker::LinkModules(composite, M, Linker::DestroySource, &errorMessage)) + { + // Linking failed + SS << "Linking archive module with composite failed:" << errorMessage; + SS.flush(); + CleanUpLinkBCA(archiveModules); + return false; + } + else + { + // Link succeed, now clean up + modulesLoadedOnPass++; + DEBUG_WITH_TYPE("klee_linker", dbgs() << "Linking succeeded.\n"); + + delete M; + archiveModules[i] = 0; + + // We need to recompute the undefined symbols in the composite module + // after linking + GetAllUndefinedSymbols(composite, undefinedSymbols); + + break; // Look for symbols in next module + } + + } + } + } + + passCounter++; + DEBUG_WITH_TYPE("klee_linker", dbgs() << "Completed " << passCounter << + " linker passes.\n" << modulesLoadedOnPass << + " modules loaded on the last pass\n"); + } while (undefinedSymbols != previouslyUndefinedSymbols); // Iterate until we reach a fixed point + + + // What's left in archiveModules we don't want to link in so free it + CleanUpLinkBCA(archiveModules); + + return true; + +} +#endif + + Module *klee::linkWithLibrary(Module *module, const std::string &libraryName) { +DEBUG_WITH_TYPE("klee_linker", dbgs() << "Linking file " << libraryName << "\n"); #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) - SMDiagnostic err; - std::string err_str; - sys::Path libraryPath(libraryName); - Module *new_mod = ParseIRFile(libraryPath.str(), err, -module->getContext()); - - if (Linker::LinkModules(module, new_mod, Linker::DestroySource, -&err_str)) { - assert(0 && "linked in library failed!"); + if (!sys::fs::exists(libraryName)) { + klee_error("Link with library %s failed. No such file.", + libraryName.c_str()); + } + + OwningPtr<MemoryBuffer> Buffer; + if (error_code ec = MemoryBuffer::getFile(libraryName,Buffer)) { + klee_error("Link with library %s failed: %s", libraryName.c_str(), + ec.message().c_str()); + } + + sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); + + LLVMContext &Context = getGlobalContext(); + std::string ErrorMessage; + + if (magic == sys::fs::file_magic::bitcode) { + Module *Result = 0; + Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); + + + if (!Result || Linker::LinkModules(module, Result, Linker::DestroySource, + &ErrorMessage)) + klee_error("Link with library %s failed: %s", libraryName.c_str(), + ErrorMessage.c_str()); + + delete Result; + + } else if (magic == sys::fs::file_magic::archive) { + OwningPtr<object::Binary> arch; + if (error_code ec = object::createBinary(Buffer.take(), arch)) + klee_error("Link with library %s failed: %s", libraryName.c_str(), + ec.message().c_str()); + + if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { + // Handle in helper + if (!linkBCA(a, module, ErrorMessage)) + klee_error("Link with library %s failed: %s", libraryName.c_str(), + ErrorMessage.c_str()); + } + else { + klee_error("Link with library %s failed: Cast to archive failed", libraryName.c_str()); + } + + } else if (magic.is_object()) { + OwningPtr<object::Binary> obj; + if (object::ObjectFile *o = dyn_cast<object::ObjectFile>(obj.get())) { + klee_warning("Link with library: Object file %s in archive %s found. " + "Currently not supported.", + o->getFileName().data(), libraryName.c_str()); + } + } else { + klee_error("Link with library %s failed: Unrecognized file type.", + libraryName.c_str()); } return module; @@ -66,13 +410,15 @@ module->getContext()); bool native = false; if (linker.LinkInFile(libraryPath, native)) { - assert(0 && "linking in library failed!"); + klee_error("Linking library %s failed", libraryName.c_str()); } return linker.releaseModule(); #endif } + + Function *klee::getDirectCallTarget(CallSite cs) { Value *v = cs.getCalledValue(); if (Function *f = dyn_cast<Function>(v)) { diff --git a/lib/Module/Optimize.cpp b/lib/Module/Optimize.cpp index 41a106f1..ed1e0e34 100644 --- a/lib/Module/Optimize.cpp +++ b/lib/Module/Optimize.cpp @@ -40,7 +40,6 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" -#include <iostream> using namespace llvm; #if 0 @@ -124,7 +123,9 @@ static void AddStandardCompilePasses(PassManager &PM) { addPass(PM, createFunctionInliningPass()); // Inline small functions addPass(PM, createArgumentPromotionPass()); // Scalarize uninlined fn args +#if LLVM_VERSION_CODE < LLVM_VERSION(3, 4) addPass(PM, createSimplifyLibCallsPass()); // Library Call Optimizations +#endif addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl. addPass(PM, createJumpThreadingPass()); // Thread jumps. addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs @@ -270,7 +271,7 @@ void Optimize(Module* M) { if (Opt->getNormalCtor()) addPass(Passes, Opt->getNormalCtor()()); else - std::cerr << "llvm-ld: cannot create pass: " << Opt->getPassName() + llvm::errs() << "llvm-ld: cannot create pass: " << Opt->getPassName() << "\n"; } #endif diff --git a/lib/SMT/SMTParser.cpp b/lib/SMT/SMTParser.cpp index 22578f46..03042fdd 100644 --- a/lib/SMT/SMTParser.cpp +++ b/lib/SMT/SMTParser.cpp @@ -14,7 +14,6 @@ #include "klee/Constraints.h" #include "expr/Parser.h" -#include <iostream> #include <fstream> #include <string> #include <sstream> @@ -23,7 +22,6 @@ //#define DEBUG -using namespace std; using namespace klee; using namespace klee::expr; @@ -103,9 +101,8 @@ bool SMTParser::Solve() { // XXX: give more info int SMTParser::Error(const string& msg) { - std::cerr << SMTParser::parserTemp->fileName << ":" - << SMTParser::parserTemp->lineNum - << ": " << msg << "\n"; + llvm::errs() << SMTParser::parserTemp->fileName << ":" + << SMTParser::parserTemp->lineNum << ": " << msg << "\n"; exit(1); return 0; } @@ -213,7 +210,7 @@ void SMTParser::AddVar(std::string name, ExprHandle val) { ExprHandle SMTParser::GetVar(std::string name) { VarEnv top = varEnvs.top(); if (top.find(name) == top.end()) { - std::cerr << "Cannot find variable ?" << name << "\n"; + llvm::errs() << "Cannot find variable ?" << name << "\n"; exit(1); } return top[name]; @@ -241,7 +238,7 @@ void SMTParser::AddFVar(std::string name, ExprHandle val) { ExprHandle SMTParser::GetFVar(std::string name) { FVarEnv top = fvarEnvs.top(); if (top.find(name) == top.end()) { - std::cerr << "Cannot find fvar $" << name << "\n"; + llvm::errs() << "Cannot find fvar $" << name << "\n"; exit(1); } return top[name]; diff --git a/lib/SMT/SMTParser.h b/lib/SMT/SMTParser.h index fd1ec044..ac84e74c 100644 --- a/lib/SMT/SMTParser.h +++ b/lib/SMT/SMTParser.h @@ -13,8 +13,6 @@ #include "expr/Parser.h" -#include <cassert> -#include <iostream> #include <map> #include <stack> #include <string> diff --git a/lib/SMT/main.cpp b/lib/SMT/main.cpp index 034c4ce4..31fa311d 100644 --- a/lib/SMT/main.cpp +++ b/lib/SMT/main.cpp @@ -2,9 +2,6 @@ #include "klee/ExprBuilder.h" -#include <iostream> - -using namespace std; using namespace klee; int main(int argc, char** argv) { diff --git a/lib/SMT/smtlib.y b/lib/SMT/smtlib.y index 01d3539d..eb3b3890 100644 --- a/lib/SMT/smtlib.y +++ b/lib/SMT/smtlib.y @@ -254,7 +254,7 @@ bench_attribute: | COLON_TOK LOGIC_TOK logic_name { if (*$3 != "QF_BV" && *$3 != "QF_AUFBV" && *$3 != "QF_UFBV") { - std::cerr << "ERROR: Logic " << *$3 << " not supported."; + llvm::errs() << "ERROR: Logic " << *$3 << " not supported."; exit(1); } diff --git a/lib/Solver/FastCexSolver.cpp b/lib/Solver/FastCexSolver.cpp index 08a9ef7c..57e44806 100644 --- a/lib/Solver/FastCexSolver.cpp +++ b/lib/Solver/FastCexSolver.cpp @@ -18,7 +18,9 @@ // FIXME: Use APInt. #include "klee/Internal/Support/IntEvaluation.h" -#include <iostream> +#define DEBUG_TYPE "cex-solver" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include <sstream> #include <cassert> #include <map> @@ -109,7 +111,7 @@ public: ValueRange(uint64_t _min, uint64_t _max) : m_min(_min), m_max(_max) {} ValueRange(const ValueRange &b) : m_min(b.m_min), m_max(b.m_max) {} - void print(std::ostream &os) const { + void print(llvm::raw_ostream &os) const { if (isFixed()) { os << m_min; } else { @@ -283,7 +285,8 @@ public: } }; -inline std::ostream &operator<<(std::ostream &os, const ValueRange &vr) { +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + const ValueRange &vr) { vr.print(os); return os; } @@ -363,12 +366,12 @@ protected: // value cannot be part of the assignment. if (index >= array.size) return ReadExpr::create(UpdateList(&array, 0), - ConstantExpr::alloc(index, Expr::Int32)); + ConstantExpr::alloc(index, array.getDomain())); std::map<const Array*, CexObjectData*>::iterator it = objects.find(&array); return ConstantExpr::alloc((it == objects.end() ? 127 : it->second->getPossibleValue(index)), - Expr::Int8); + array.getRange()); } public: @@ -384,19 +387,19 @@ protected: // value cannot be part of the assignment. if (index >= array.size) return ReadExpr::create(UpdateList(&array, 0), - ConstantExpr::alloc(index, Expr::Int32)); + ConstantExpr::alloc(index, array.getDomain())); std::map<const Array*, CexObjectData*>::iterator it = objects.find(&array); if (it == objects.end()) return ReadExpr::create(UpdateList(&array, 0), - ConstantExpr::alloc(index, Expr::Int32)); + ConstantExpr::alloc(index, array.getDomain())); CexValueData cvd = it->second->getExactValues(index); if (!cvd.isFixed()) return ReadExpr::create(UpdateList(&array, 0), - ConstantExpr::alloc(index, Expr::Int32)); + ConstantExpr::alloc(index, array.getDomain())); - return ConstantExpr::alloc(cvd.min(), Expr::Int8); + return ConstantExpr::alloc(cvd.min(), array.getRange()); } public: @@ -405,10 +408,6 @@ public: : objects(_objects) {} }; -#if 0 -#define DEBUG -#endif - class CexData { public: std::map<const Array*, CexObjectData*> objects; @@ -442,9 +441,7 @@ public: } void propogatePossibleValues(ref<Expr> e, CexValueData range) { - #ifdef DEBUG - std::cerr << "propogate: " << range << " for\n" << e << "\n"; - #endif + DEBUG(llvm::errs() << "propogate: " << range << " for\n" << e << "\n";); switch (e->getKind()) { case Expr::Constant: @@ -938,27 +935,29 @@ public: } void dump() { - std::cerr << "-- propogated values --\n"; - for (std::map<const Array*, CexObjectData*>::iterator - it = objects.begin(), ie = objects.end(); it != ie; ++it) { + llvm::errs() << "-- propogated values --\n"; + for (std::map<const Array *, CexObjectData *>::iterator + it = objects.begin(), + ie = objects.end(); + it != ie; ++it) { const Array *A = it->first; CexObjectData *COD = it->second; - - std::cerr << A->name << "\n"; - std::cerr << "possible: ["; + + llvm::errs() << A->name << "\n"; + llvm::errs() << "possible: ["; for (unsigned i = 0; i < A->size; ++i) { if (i) - std::cerr << ", "; - std::cerr << COD->getPossibleValues(i); + llvm::errs() << ", "; + llvm::errs() << COD->getPossibleValues(i); } - std::cerr << "]\n"; - std::cerr << "exact : ["; + llvm::errs() << "]\n"; + llvm::errs() << "exact : ["; for (unsigned i = 0; i < A->size; ++i) { if (i) - std::cerr << ", "; - std::cerr << COD->getExactValues(i); + llvm::errs() << ", "; + llvm::errs() << COD->getExactValues(i); } - std::cerr << "]\n"; + llvm::errs() << "]\n"; } } }; @@ -1009,9 +1008,7 @@ static bool propogateValues(const Query& query, CexData &cd, cd.propogateExactValue(query.expr, 0); } -#ifdef DEBUG - cd.dump(); -#endif + DEBUG(cd.dump();); // Check the result. bool hasSatisfyingAssignment = true; @@ -1109,13 +1106,14 @@ FastCexSolver::computeInitialValues(const Query& query, // Propogation found a satisfying assignment, compute the initial values. for (unsigned i = 0; i != objects.size(); ++i) { const Array *array = objects[i]; + assert(array); std::vector<unsigned char> data; data.reserve(array->size); for (unsigned i=0; i < array->size; i++) { ref<Expr> read = ReadExpr::create(UpdateList(array, 0), - ConstantExpr::create(i, Expr::Int32)); + ConstantExpr::create(i, array->getDomain())); ref<Expr> value = cd.evaluatePossible(read); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(value)) { diff --git a/lib/Solver/IndependentSolver.cpp b/lib/Solver/IndependentSolver.cpp index d9fc77dc..46b4ee56 100644 --- a/lib/Solver/IndependentSolver.cpp +++ b/lib/Solver/IndependentSolver.cpp @@ -15,10 +15,12 @@ #include "klee/util/ExprUtil.h" +#define DEBUG_TYPE "independent-solver" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include <map> #include <vector> #include <ostream> -#include <iostream> using namespace klee; using namespace llvm; @@ -60,7 +62,7 @@ public: return false; } - void print(std::ostream &os) const { + void print(llvm::raw_ostream &os) const { bool first = true; os << "{"; for (typename set_ty::iterator it = s.begin(), ie = s.end(); @@ -76,8 +78,9 @@ public: } }; -template<class T> -inline std::ostream &operator<<(std::ostream &os, const ::DenseSet<T> &dis) { +template <class T> +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + const ::DenseSet<T> &dis) { dis.print(os); return os; } @@ -124,7 +127,7 @@ public: return *this; } - void print(std::ostream &os) const { + void print(llvm::raw_ostream &os) const { os << "{"; bool first = true; for (std::set<const Array*>::iterator it = wholeObjects.begin(), @@ -214,7 +217,8 @@ public: } }; -inline std::ostream &operator<<(std::ostream &os, const IndependentElementSet &ies) { +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + const IndependentElementSet &ies) { ies.print(os); return os; } @@ -247,20 +251,21 @@ IndependentElementSet getIndependentConstraints(const Query& query, worklist.swap(newWorklist); } while (!done); - if (0) { +DEBUG( std::set< ref<Expr> > reqset(result.begin(), result.end()); - std::cerr << "--\n"; - std::cerr << "Q: " << query.expr << "\n"; - std::cerr << "\telts: " << IndependentElementSet(query.expr) << "\n"; + errs() << "--\n"; + errs() << "Q: " << query.expr << "\n"; + errs() << "\telts: " << IndependentElementSet(query.expr) << "\n"; int i = 0; - for (ConstraintManager::const_iterator it = query.constraints.begin(), - ie = query.constraints.end(); it != ie; ++it) { - std::cerr << "C" << i++ << ": " << *it; - std::cerr << " " << (reqset.count(*it) ? "(required)" : "(independent)") << "\n"; - std::cerr << "\telts: " << IndependentElementSet(*it) << "\n"; + for (ConstraintManager::const_iterator it = query.constraints.begin(), + ie = query.constraints.end(); it != ie; ++it) { + errs() << "C" << i++ << ": " << *it; + errs() << " " << (reqset.count(*it) ? "(required)" : "(independent)") << "\n"; + errs() << "\telts: " << IndependentElementSet(*it) << "\n"; } - std::cerr << "elts closure: " << eltsClosure << "\n"; - } + errs() << "elts closure: " << eltsClosure << "\n"; + ); + return eltsClosure; } diff --git a/lib/Solver/Makefile b/lib/Solver/Makefile index 2be74c01..a44b4f6e 100755 --- a/lib/Solver/Makefile +++ b/lib/Solver/Makefile @@ -12,6 +12,7 @@ LEVEL=../.. LIBRARYNAME=kleaverSolver DONT_BUILD_RELINKED=1 BUILD_ARCHIVE=1 +NO_INSTALL=1 include $(LEVEL)/Makefile.common @@ -22,4 +23,4 @@ ifeq ($(ENABLE_METASMT),1) CXX.Flags := $(filter-out -fno-rtti,$(CXX.Flags)) CXX.Flags += $(metaSMT_CXXFLAGS) CXX.Flags += $(metaSMT_INCLUDES) -endif \ No newline at end of file +endif diff --git a/lib/Solver/MetaSMTBuilder.h b/lib/Solver/MetaSMTBuilder.h index 2b084ac7..b5c99907 100644 --- a/lib/Solver/MetaSMTBuilder.h +++ b/lib/Solver/MetaSMTBuilder.h @@ -187,7 +187,7 @@ typename SolverContext::result_type MetaSMTBuilder<SolverContext>::getInitialArr if (!hashed) { - array_expr = evaluate(_solver, buildArray(8, 32)); + array_expr = evaluate(_solver, buildArray(root->getRange(), root->getDomain())); if (root->isConstantArray()) { for (unsigned i = 0, e = root->size; i != e; ++i) { @@ -599,11 +599,11 @@ typename SolverContext::result_type MetaSMTBuilder<SolverContext>::constructActu ++stats::queryConstructs; -// std::cerr << "Constructing expression "; -// ExprPPrinter::printSingleExpr(std::cerr, e); -// std::cerr << "\n"; +// llvm::errs() << "Constructing expression "; +// ExprPPrinter::printSingleExpr(llvm::errs(), e); +// llvm::errs() << "\n"; - switch (e->getKind()) { + switch (e->getKind()) { case Expr::Constant: { @@ -614,7 +614,7 @@ typename SolverContext::result_type MetaSMTBuilder<SolverContext>::constructActu // Coerce to bool if necessary. if (coe_width == 1) { - res = (coe->isTrue()) ? getTrue() : getFalse(); + res = (coe->isTrue()) ? getTrue() : getFalse(); } else if (coe_width <= 32) { res = bvConst32(coe_width, coe->getZExtValue(32)); @@ -624,7 +624,7 @@ typename SolverContext::result_type MetaSMTBuilder<SolverContext>::constructActu } else { ref<ConstantExpr> tmp = coe; - res = bvConst64(64, tmp->Extract(0, 64)->getZExtValue()); + res = bvConst64(64, tmp->Extract(0, 64)->getZExtValue()); while (tmp->getWidth() > 64) { tmp = tmp->Extract(64, tmp->getWidth() - 64); unsigned min_width = std::min(64U, tmp->getWidth()); @@ -658,9 +658,9 @@ typename SolverContext::result_type MetaSMTBuilder<SolverContext>::constructActu case Expr::Read: { ReadExpr *re = cast<ReadExpr>(e); - assert(re); + assert(re && re->updates.root); + *width_out = re->updates.root->getRange(); // FixMe call method of Array - *width_out = 8; res = evaluate(_solver, metaSMT::logic::Array::select( getArrayForUpdate(re->updates.root, re->updates.head), diff --git a/lib/Solver/QueryLoggingSolver.cpp b/lib/Solver/QueryLoggingSolver.cpp index f2e38182..d5598d1d 100644 --- a/lib/Solver/QueryLoggingSolver.cpp +++ b/lib/Solver/QueryLoggingSolver.cpp @@ -18,9 +18,10 @@ QueryLoggingSolver::QueryLoggingSolver(Solver *_solver, std::string path, const std::string& commentSign, int queryTimeToLog) - : solver(_solver), - os(path.c_str(), std::ios::trunc), - logBuffer(""), + : solver(_solver), + os(path.c_str(), ErrorInfo), + BufferString(""), + logBuffer(BufferString), queryCount(0), minQueryTimeToLog(queryTimeToLog), startTime(0.0f), @@ -79,8 +80,7 @@ void QueryLoggingSolver::flushBuffer() { } // prepare the buffer for reuse - logBuffer.clear(); - logBuffer.str(""); + BufferString = ""; } bool QueryLoggingSolver::computeTruth(const Query& query, bool& isValid) { diff --git a/lib/Solver/QueryLoggingSolver.h b/lib/Solver/QueryLoggingSolver.h index 2c7d80e8..ad1722ca 100644 --- a/lib/Solver/QueryLoggingSolver.h +++ b/lib/Solver/QueryLoggingSolver.h @@ -12,6 +12,7 @@ #include "klee/Solver.h" #include "klee/SolverImpl.h" +#include "llvm/Support/raw_ostream.h" #include <fstream> #include <sstream> @@ -25,9 +26,12 @@ class QueryLoggingSolver : public SolverImpl { protected: Solver *solver; - std::ofstream os; - std::ostringstream logBuffer; // buffer to store logs before flushing to - // file + std::string ErrorInfo; + llvm::raw_fd_ostream os; + // @brief Buffer used by logBuffer + std::string BufferString; + // @brief buffer to store logs before flushing to file + llvm::raw_string_ostream logBuffer; unsigned queryCount; int minQueryTimeToLog; // we log to file only those queries // which take longer than the specified time (ms); diff --git a/lib/Solver/STPBuilder.cpp b/lib/Solver/STPBuilder.cpp index 90252656..34ce0ede 100644 --- a/lib/Solver/STPBuilder.cpp +++ b/lib/Solver/STPBuilder.cpp @@ -34,7 +34,6 @@ #include <algorithm> // max, min #include <cassert> -#include <iostream> #include <map> #include <sstream> #include <vector> @@ -174,14 +173,13 @@ ExprHandle STPBuilder::eqExpr(ExprHandle a, ExprHandle b) { } // logical right shift -ExprHandle STPBuilder::bvRightShift(ExprHandle expr, unsigned amount, unsigned shiftBits) { +ExprHandle STPBuilder::bvRightShift(ExprHandle expr, unsigned shift) { unsigned width = vc_getBVLength(vc, expr); - unsigned shift = amount & ((1<<shiftBits) - 1); if (shift==0) { return expr; } else if (shift>=width) { - return bvZero(width); + return bvZero(width); // Overshift to zero } else { return vc_bvConcatExpr(vc, bvZero(shift), @@ -190,14 +188,13 @@ ExprHandle STPBuilder::bvRightShift(ExprHandle expr, unsigned amount, unsigned s } // logical left shift -ExprHandle STPBuilder::bvLeftShift(ExprHandle expr, unsigned amount, unsigned shiftBits) { +ExprHandle STPBuilder::bvLeftShift(ExprHandle expr, unsigned shift) { unsigned width = vc_getBVLength(vc, expr); - unsigned shift = amount & ((1<<shiftBits) - 1); if (shift==0) { return expr; } else if (shift>=width) { - return bvZero(width); + return bvZero(width); // Overshift to zero } else { // stp shift does "expr @ [0 x s]" which we then have to extract, // rolling our own gives slightly smaller exprs @@ -208,96 +205,97 @@ ExprHandle STPBuilder::bvLeftShift(ExprHandle expr, unsigned amount, unsigned sh } // left shift by a variable amount on an expression of the specified width -ExprHandle STPBuilder::bvVarLeftShift(ExprHandle expr, ExprHandle amount, unsigned width) { +ExprHandle STPBuilder::bvVarLeftShift(ExprHandle expr, ExprHandle shift) { + unsigned width = vc_getBVLength(vc, expr); ExprHandle res = bvZero(width); - int shiftBits = getShiftBits( width ); - - //get the shift amount (looking only at the bits appropriate for the given width) - ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 ); - //construct a big if-then-elif-elif-... with one case per possible shift amount for( int i=width-1; i>=0; i-- ) { res = vc_iteExpr(vc, - eqExpr(shift, bvConst32(shiftBits, i)), - bvLeftShift(expr, i, shiftBits), + eqExpr(shift, bvConst32(width, i)), + bvLeftShift(expr, i), res); } + + // If overshifting, shift to zero + res = vc_iteExpr(vc, + vc_bvLtExpr(vc, shift, bvConst32(vc_getBVLength(vc,shift), width)), + res, + bvZero(width)); return res; } // logical right shift by a variable amount on an expression of the specified width -ExprHandle STPBuilder::bvVarRightShift(ExprHandle expr, ExprHandle amount, unsigned width) { +ExprHandle STPBuilder::bvVarRightShift(ExprHandle expr, ExprHandle shift) { + unsigned width = vc_getBVLength(vc, expr); ExprHandle res = bvZero(width); - int shiftBits = getShiftBits( width ); - - //get the shift amount (looking only at the bits appropriate for the given width) - ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 ); - //construct a big if-then-elif-elif-... with one case per possible shift amount for( int i=width-1; i>=0; i-- ) { res = vc_iteExpr(vc, - eqExpr(shift, bvConst32(shiftBits, i)), - bvRightShift(expr, i, shiftBits), + eqExpr(shift, bvConst32(width, i)), + bvRightShift(expr, i), res); } + // If overshifting, shift to zero + res = vc_iteExpr(vc, + vc_bvLtExpr(vc, shift, bvConst32(vc_getBVLength(vc,shift), width)), + res, + bvZero(width)); return res; } // arithmetic right shift by a variable amount on an expression of the specified width -ExprHandle STPBuilder::bvVarArithRightShift(ExprHandle expr, ExprHandle amount, unsigned width) { - int shiftBits = getShiftBits( width ); - - //get the shift amount (looking only at the bits appropriate for the given width) - ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 ); +ExprHandle STPBuilder::bvVarArithRightShift(ExprHandle expr, ExprHandle shift) { + unsigned width = vc_getBVLength(vc, expr); //get the sign bit to fill with ExprHandle signedBool = bvBoolExtract(expr, width-1); //start with the result if shifting by width-1 - ExprHandle res = constructAShrByConstant(expr, width-1, signedBool, shiftBits); + ExprHandle res = constructAShrByConstant(expr, width-1, signedBool); //construct a big if-then-elif-elif-... with one case per possible shift amount // XXX more efficient to move the ite on the sign outside all exprs? // XXX more efficient to sign extend, right shift, then extract lower bits? for( int i=width-2; i>=0; i-- ) { res = vc_iteExpr(vc, - eqExpr(shift, bvConst32(shiftBits,i)), + eqExpr(shift, bvConst32(width,i)), constructAShrByConstant(expr, i, - signedBool, - shiftBits), + signedBool), res); } + // If overshifting, shift to zero + res = vc_iteExpr(vc, + vc_bvLtExpr(vc, shift, bvConst32(vc_getBVLength(vc,shift), width)), + res, + bvZero(width)); return res; } ExprHandle STPBuilder::constructAShrByConstant(ExprHandle expr, - unsigned amount, - ExprHandle isSigned, - unsigned shiftBits) { + unsigned shift, + ExprHandle isSigned) { unsigned width = vc_getBVLength(vc, expr); - unsigned shift = amount & ((1<<shiftBits) - 1); if (shift==0) { return expr; } else if (shift>=width-1) { - return vc_iteExpr(vc, isSigned, bvMinusOne(width), bvZero(width)); + return bvZero(width); // Overshift to zero } else { return vc_iteExpr(vc, isSigned, ExprHandle(vc_bvConcatExpr(vc, bvMinusOne(shift), bvExtract(expr, width - 1, shift))), - bvRightShift(expr, shift, shiftBits)); + bvRightShift(expr, shift)); } } ExprHandle STPBuilder::constructMulByConstant(ExprHandle expr, unsigned width, uint64_t x) { - unsigned shiftBits = getShiftBits(width); uint64_t add, sub; ExprHandle res = 0; @@ -313,7 +311,7 @@ ExprHandle STPBuilder::constructMulByConstant(ExprHandle expr, unsigned width, u if ((add&bit) || (sub&bit)) { assert(!((add&bit) && (sub&bit)) && "invalid mult constants"); - ExprHandle op = bvLeftShift(expr, j, shiftBits); + ExprHandle op = bvLeftShift(expr, j); if (add&bit) { if (res) { @@ -367,9 +365,9 @@ ExprHandle STPBuilder::constructUDivByConstant(ExprHandle expr_n, unsigned width // n/d = (((n - t1) >> sh1) + t1) >> sh2; ExprHandle n_minus_t1 = vc_bvMinusExpr( vc, width, expr_n, t1 ); - ExprHandle shift_sh1 = bvVarRightShift( n_minus_t1, expr_sh1, 32 ); + ExprHandle shift_sh1 = bvVarRightShift( n_minus_t1, expr_sh1); ExprHandle plus_t1 = vc_bvPlusExpr( vc, width, shift_sh1, t1 ); - ExprHandle res = bvVarRightShift( plus_t1, expr_sh2, 32 ); + ExprHandle res = bvVarRightShift( plus_t1, expr_sh2); return res; } @@ -407,7 +405,7 @@ ExprHandle STPBuilder::constructSDivByConstant(ExprHandle expr_n, unsigned width // Improved variable arithmetic right shift: sign extend, shift, // extract. ExprHandle extend_npm = vc_bvSignExtend( vc, n_plus_mulsh, 64 ); - ExprHandle shift_npm = bvVarRightShift( extend_npm, expr_shpost, 64 ); + ExprHandle shift_npm = bvVarRightShift( extend_npm, expr_shpost); ExprHandle shift_shpost = vc_bvExtract( vc, shift_npm, 31, 0 ); //lower 32-bits // XSIGN(n) is -1 if n is negative, positive one otherwise @@ -440,7 +438,7 @@ ExprHandle STPBuilder::constructSDivByConstant(ExprHandle expr_n, unsigned width memmove(buf + space, buf, addrlen); // moving the address part to the end memcpy(buf, root->name.c_str(), space); // filling out the name part - array_expr = buildArray(buf, 32, 8); + array_expr = buildArray(buf, root->getDomain(), root->getRange()); if (root->isConstantArray()) { // FIXME: Flush the concrete values into STP. Ideally we would do this @@ -554,7 +552,8 @@ ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out) { case Expr::Read: { ReadExpr *re = cast<ReadExpr>(e); - *width_out = 8; + assert(re && re->updates.root); + *width_out = re->updates.root->getRange(); return vc_readExpr(vc, getArrayForUpdate(re->updates.root, re->updates.head), construct(re->index, 0)); @@ -659,8 +658,7 @@ ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out) { if (bits64::isPowerOfTwo(divisor)) { return bvRightShift(left, - bits64::indexOfSingleBit(divisor), - getShiftBits(*width_out)); + bits64::indexOfSingleBit(divisor)); } else if (optimizeDivides) { if (*width_out == 32) //only works for 32-bit division return constructUDivByConstant( left, *width_out, @@ -810,28 +808,25 @@ ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out) { assert(*width_out!=1 && "uncanonicalized shl"); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(se->right)) { - return bvLeftShift(left, (unsigned) CE->getLimitedValue(), - getShiftBits(*width_out)); + return bvLeftShift(left, (unsigned) CE->getLimitedValue()); } else { int shiftWidth; ExprHandle amount = construct(se->right, &shiftWidth); - return bvVarLeftShift( left, amount, *width_out ); + return bvVarLeftShift( left, amount); } } case Expr::LShr: { LShrExpr *lse = cast<LShrExpr>(e); ExprHandle left = construct(lse->left, width_out); - unsigned shiftBits = getShiftBits(*width_out); assert(*width_out!=1 && "uncanonicalized lshr"); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(lse->right)) { - return bvRightShift(left, (unsigned) CE->getLimitedValue(), - shiftBits); + return bvRightShift(left, (unsigned) CE->getLimitedValue()); } else { int shiftWidth; ExprHandle amount = construct(lse->right, &shiftWidth); - return bvVarRightShift( left, amount, *width_out ); + return bvVarRightShift( left, amount); } } @@ -843,12 +838,11 @@ ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out) { if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ase->right)) { unsigned shift = (unsigned) CE->getLimitedValue(); ExprHandle signedBool = bvBoolExtract(left, *width_out-1); - return constructAShrByConstant(left, shift, signedBool, - getShiftBits(*width_out)); + return constructAShrByConstant(left, shift, signedBool); } else { int shiftWidth; ExprHandle amount = construct(ase->right, &shiftWidth); - return bvVarArithRightShift( left, amount, *width_out ); + return bvVarArithRightShift( left, amount); } } diff --git a/lib/Solver/STPBuilder.h b/lib/Solver/STPBuilder.h index 0a99b753..ef1cd8b3 100644 --- a/lib/Solver/STPBuilder.h +++ b/lib/Solver/STPBuilder.h @@ -79,13 +79,6 @@ class STPBuilder { STPArrayExprHash _arr_hash; private: - unsigned getShiftBits(unsigned amount) { - unsigned bits = 1; - amount--; - while (amount >>= 1) - bits++; - return bits; - } ExprHandle bvOne(unsigned width); ExprHandle bvZero(unsigned width); @@ -100,14 +93,14 @@ private: ExprHandle eqExpr(ExprHandle a, ExprHandle b); //logical left and right shift (not arithmetic) - ExprHandle bvLeftShift(ExprHandle expr, unsigned shift, unsigned shiftBits); - ExprHandle bvRightShift(ExprHandle expr, unsigned amount, unsigned shiftBits); - ExprHandle bvVarLeftShift(ExprHandle expr, ExprHandle amount, unsigned width); - ExprHandle bvVarRightShift(ExprHandle expr, ExprHandle amount, unsigned width); - ExprHandle bvVarArithRightShift(ExprHandle expr, ExprHandle amount, unsigned width); + ExprHandle bvLeftShift(ExprHandle expr, unsigned shift); + ExprHandle bvRightShift(ExprHandle expr, unsigned shift); + ExprHandle bvVarLeftShift(ExprHandle expr, ExprHandle shift); + ExprHandle bvVarRightShift(ExprHandle expr, ExprHandle shift); + ExprHandle bvVarArithRightShift(ExprHandle expr, ExprHandle shift); ExprHandle constructAShrByConstant(ExprHandle expr, unsigned shift, - ExprHandle isSigned, unsigned shiftBits); + ExprHandle isSigned); ExprHandle constructMulByConstant(ExprHandle expr, unsigned width, uint64_t x); ExprHandle constructUDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d); ExprHandle constructSDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d); diff --git a/lib/Solver/Solver.cpp b/lib/Solver/Solver.cpp index 22b1545f..229fa234 100644 --- a/lib/Solver/Solver.cpp +++ b/lib/Solver/Solver.cpp @@ -407,11 +407,12 @@ ValidatingSolver::computeInitialValues(const Query& query, std::vector< ref<Expr> > bindings; for (unsigned i = 0; i != values.size(); ++i) { const Array *array = objects[i]; + assert(array); for (unsigned j=0; j<array->size; j++) { unsigned char value = values[i][j]; bindings.push_back(EqExpr::create(ReadExpr::create(UpdateList(array, 0), - ConstantExpr::alloc(j, Expr::Int32)), - ConstantExpr::alloc(value, Expr::Int8))); + ConstantExpr::alloc(j, array->getDomain())), + ConstantExpr::alloc(value, array->getRange()))); } } ConstraintManager tmp(bindings); @@ -493,8 +494,6 @@ Solver *klee::createDummySolver() { class STPSolverImpl : public SolverImpl { private: - /// The solver we are part of, for access to public information. - STPSolver *solver; VC vc; STPBuilder *builder; double timeout; @@ -502,7 +501,7 @@ private: SolverRunStatus runStatusCode; public: - STPSolverImpl(STPSolver *_solver, bool _useForkedSTP, bool _optimizeDivides = true); + STPSolverImpl(bool _useForkedSTP, bool _optimizeDivides = true); ~STPSolverImpl(); char *getConstraintLog(const Query&); @@ -526,9 +525,8 @@ static void stp_error_handler(const char* err_msg) { abort(); } -STPSolverImpl::STPSolverImpl(STPSolver *_solver, bool _useForkedSTP, bool _optimizeDivides) - : solver(_solver), - vc(vc_createValidityChecker()), +STPSolverImpl::STPSolverImpl(bool _useForkedSTP, bool _optimizeDivides) + : vc(vc_createValidityChecker()), builder(new STPBuilder(vc, _optimizeDivides)), timeout(0.0), useForkedSTP(_useForkedSTP), @@ -565,7 +563,7 @@ STPSolverImpl::~STPSolverImpl() { /***/ STPSolver::STPSolver(bool useForkedSTP, bool optimizeDivides) - : Solver(new STPSolverImpl(this, useForkedSTP, optimizeDivides)) + : Solver(new STPSolverImpl(useForkedSTP, optimizeDivides)) { } @@ -773,7 +771,6 @@ static SolverImpl::SolverRunStatus runAndGetCexForked(::VC vc, } } } -#include <iostream> bool STPSolverImpl::computeInitialValues(const Query &query, const std::vector<const Array*> diff --git a/lib/Support/Makefile b/lib/Support/Makefile index a1b46f3c..67272908 100644 --- a/lib/Support/Makefile +++ b/lib/Support/Makefile @@ -12,5 +12,6 @@ LEVEL=../.. LIBRARYNAME=kleeSupport DONT_BUILD_RELINKED=1 BUILD_ARCHIVE=1 +NO_INSTALL=1 include $(LEVEL)/Makefile.common diff --git a/lib/Support/MemoryUsage.cpp b/lib/Support/MemoryUsage.cpp new file mode 100644 index 00000000..676ce307 --- /dev/null +++ b/lib/Support/MemoryUsage.cpp @@ -0,0 +1,25 @@ +//===-- MemoryUsage.cpp ---------------------------------------------------===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "klee/Internal/System/MemoryUsage.h" +#include <malloc.h> + +using namespace klee; + +size_t util::GetTotalMallocUsage() { + struct mallinfo mi = ::mallinfo(); + // The malloc implementation in glibc (pmalloc2) + // does not include mmap()'ed memory in mi.uordblks + // but other implementations (e.g. tcmalloc) do. +#if defined(__GLIBC__) + return mi.uordblks + mi.hblkhd; +#else + return mi.uordblks; +#endif +} diff --git a/lib/Support/TreeStream.cpp b/lib/Support/TreeStream.cpp index 0e8b86dd..0d5e4568 100644 --- a/lib/Support/TreeStream.cpp +++ b/lib/Support/TreeStream.cpp @@ -10,12 +10,13 @@ #include "klee/Internal/ADT/TreeStream.h" #include <cassert> -#include <iostream> #include <iomanip> #include <fstream> #include <iterator> #include <map> +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include <string.h> using namespace klee; @@ -105,10 +106,9 @@ void TreeStreamWriter::readStream(TreeStreamID streamID, std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); assert(is.good()); -#if 0 - std::cout << "finding chain for: " << streamID << "\n"; -#endif - + DEBUG_WITH_TYPE("TreeStreamWriter", + llvm::errs() << "finding chain for: " << streamID << "\n"); + std::map<unsigned,unsigned> parents; std::vector<unsigned> roots; for (;;) { @@ -137,11 +137,11 @@ void TreeStreamWriter::readStream(TreeStreamID streamID, while (size--) is.get(); } } -#if 0 - std::cout << "roots: "; - std::copy(roots.begin(), roots.end(), std::ostream_iterator<unsigned>(std::cout, " ")); - std::cout << "\n"; -#endif + DEBUG(llvm::errs() << "roots: "; + for (size_t i = 0, e = roots.size(); i < e; ++i) { + llvm::errs() << roots[i] << " "; + } + llvm::errs() << "\n";); is.seekg(0, std::ios::beg); for (;;) { unsigned id; diff --git a/runtime/Makefile b/runtime/Makefile index 24824d08..7eb02d3f 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -23,4 +23,8 @@ ifeq ($(ENABLE_POSIX_RUNTIME),1) PARALLEL_DIRS += POSIX endif +ifeq ($(ENABLE_UCLIBC),1) +PARALLEL_DIRS += klee-uclibc +endif + include $(LEVEL)/Makefile.common diff --git a/runtime/klee-uclibc/Makefile b/runtime/klee-uclibc/Makefile new file mode 100644 index 00000000..e166cfbc --- /dev/null +++ b/runtime/klee-uclibc/Makefile @@ -0,0 +1,54 @@ +#===-- runtime/klee-uclibc/Makefile --------------------------*- Makefile -*--===# +# +# The KLEE Symbolic Virtual Machine +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +# Note klee-uclibc does not really live here. This makefile just manages the +# location of the klee-uclibc bitcode archive when building and when installing +# KLEE. + +LEVEL=../.. + +# We're not really building a bytecode library here +# but we need to set this so that $(BuildMode) is +# set appropriately +BYTECODE_LIBRARY=1 + +include $(LEVEL)/Makefile.common + +# The purpose of setting up this symbolic link is +# so that KLEE can always look for klee-uclibc +# in the same place it looks for all the other +# run time libraries +uclibc_symlink:=$(PROJ_OBJ_ROOT)/$(BuildMode)/lib/$(KLEE_UCLIBC_BCA_NAME) +# +# Force our extra rules to run +all-local:: $(uclibc_symlink) + +$(uclibc_symlink): + @echo "Setting up symbolic link to klee-uclibc" + -$(Verb) $(MKDIR) $(PROJ_OBJ_ROOT)/$(BuildMode)/lib + $(Verb) ln -s -f $(KLEE_UCLIBC_BCA) $(uclibc_symlink) + +# The reasons for copying over klee-uclibc on install are +# +# * KLEE can look for klee-uclibc in the same place it looks for all other run +# time libraries. +# * KLEE can be more easily distributed with klee-uclibc + +install:: copy_klee_uclibc +uninstall:: remove_klee_uclibc + +.PHONY: copy_klee_uclibc remove_klee_uclibc + +copy_klee_uclibc: + @echo "Installing klee-uclibc archive" + $(Verb) $(CP) $(KLEE_UCLIBC_BCA) $(DESTDIR)$(PROJ_libdir)/$(KLEE_UCLIBC_BCA_NAME) + +remove_klee_uclibc: + @echo "Removing klee-uclibc archive" + $(Verb) $(RM) $(DESTDIR)$(PROJ_libdir)/$(KLEE_UCLIBC_BCA_NAME) diff --git a/test/CXX/StaticDestructor.cpp b/test/CXX/StaticDestructor.cpp index 68fb122e..60390c2d 100644 --- a/test/CXX/StaticDestructor.cpp +++ b/test/CXX/StaticDestructor.cpp @@ -1,7 +1,7 @@ // don't optimize this, llvm likes to turn the *p into unreachable // RUN: %llvmgxx %s -emit-llvm -g -O0 -c -o %t1.bc -// RUN: %klee --libc=klee --no-output %t1.bc 2> %t1.log +// RUN: %klee --optimize=false --libc=uclibc --no-output %t1.bc 2> %t1.log // RUN: grep ":16: memory error" %t1.log #include <cassert> @@ -19,6 +19,6 @@ public: Test t; -int main() { +int main(int argc, char** argv) { return 0; } diff --git a/test/CXX/dg.exp b/test/CXX/dg.exp deleted file mode 100644 index 879685ca..00000000 --- a/test/CXX/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Concrete/lit.local.cfg b/test/Concrete/lit.local.cfg new file mode 100644 index 00000000..b882827d --- /dev/null +++ b/test/Concrete/lit.local.cfg @@ -0,0 +1,3 @@ +# FIXME: Why are these here +# Disable all tests in this directory +config.suffixes = [ ] diff --git a/test/Coverage/ReadArgs.c b/test/Coverage/ReadArgs.c index 7ebf056e..ddfb1747 100644 --- a/test/Coverage/ReadArgs.c +++ b/test/Coverage/ReadArgs.c @@ -1,8 +1,8 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: rm -rf xxx -// RUN: echo " --output-dir=xxx " > %t1.args +// RUN: rm -rf %T/xxx +// RUN: echo " --output-dir=%T/xxx " > %t1.args // RUN: %klee --read-args %t1.args %t1.bc -// RUN: test -d xxx +// RUN: test -d %T/xxx int main() { return 0; diff --git a/test/Coverage/dg.exp b/test/Coverage/dg.exp deleted file mode 100644 index 879685ca..00000000 --- a/test/Coverage/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Dogfood/dg.exp b/test/Dogfood/dg.exp deleted file mode 100644 index 879685ca..00000000 --- a/test/Dogfood/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Expr/Lexer/dg.exp b/test/Expr/Lexer/dg.exp deleted file mode 100644 index 94fc4df8..00000000 --- a/test/Expr/Lexer/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{pc}]] diff --git a/test/Expr/Parser/ConstantFolding.pc b/test/Expr/Parser/ConstantFolding.pc index 2c8a4c52..a02920db 100644 --- a/test/Expr/Parser/ConstantFolding.pc +++ b/test/Expr/Parser/ConstantFolding.pc @@ -2,196 +2,196 @@ array a[64] : w32 -> w8 = symbolic -# RUN: grep -A 2 \"# Query 1$\" %t > %t2 -# RUN: grep \"(query .. false)\" %t2 +# RUN: grep -A 2 "# Query 1$" %t > %t2 +# RUN: grep "(query .. false)" %t2 (query [] (Not (Ult (w32 0) (w32 1)))) # Check -- 0 + X ==> X -# RUN: grep -A 2 \"# Query 2$\" %t > %t2 -# RUN: grep \"(query .. false .(Read w8 0 a).)\" %t2 +# RUN: grep -A 2 "# Query 2$" %t > %t2 +# RUN: grep "(query .. false .(Read w8 0 a).)" %t2 (query [] false [(Add w8 0 (Read w8 0 a))]) -# RUN: grep -A 2 \"# Query 3$\" %t > %t2 -# RUN: grep \"(query .. false .(Read w8 0 a).)\" %t2 +# RUN: grep -A 2 "# Query 3$" %t > %t2 +# RUN: grep "(query .. false .(Read w8 0 a).)" %t2 (query [] false [(Add w8 (Read w8 0 a) 0)]) # Check -- C_0 + (C_1 + X) ==> (C_0 + C_1) + X -# RUN: grep -A 2 \"# Query 4$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 30 (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 4$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 30 (Read w8 0 a)).)" %t2 (query [] false [(Add w8 10 (Add w8 20 (Read w8 0 a)))]) # Check -- C_0 + (X + C_1) ==> (C_0 + C_1) + X -# RUN: grep -A 2 \"# Query 5$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 30 (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 5$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 30 (Read w8 0 a)).)" %t2 (query [] false [(Add w8 10 (Add w8 (Read w8 0 a) 20))]) # Check -- C_0 + (C_1 - X) ==> (C_0 + C_1) - X -# RUN: grep -A 2 \"# Query 6$\" %t > %t2 -# RUN: grep \"(query .. false .(Sub w8 30 (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 6$" %t > %t2 +# RUN: grep "(query .. false .(Sub w8 30 (Read w8 0 a)).)" %t2 (query [] false [(Add w8 10 (Sub w8 20 (Read w8 0 a)))]) # Check -- C_0 + (X - C_1) ==> (C_0 - C_1) + X -# RUN: grep -A 2 \"# Query 7$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 246 (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 7$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 246 (Read w8 0 a)).)" %t2 (query [] false [(Add w8 10 (Sub w8 (Read w8 0 a) 20))]) # Check -- (X + Y) + Z ==> X + (Y + Z) -# RUN: grep -A 3 \"# Query 8$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 (Read w8 0 a)\" %t2 -# RUN: grep \"(Add w8 (Read w8 1 a) (Read w8 2 a)\" %t2 +# RUN: grep -A 3 "# Query 8$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 (Read w8 0 a)" %t2 +# RUN: grep "(Add w8 (Read w8 1 a) (Read w8 2 a)" %t2 (query [] false [(Add w8 (Add w8 (Read w8 0 a) (Read w8 1 a)) (Read w8 2 a))]) # Check -- (X - Y) + Z ==> X + (Z - Y) -# RUN: grep -A 3 \"# Query 9$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 (Read w8 0 a)\" %t2 -# RUN: grep \"(Sub w8 (Read w8 2 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 9$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 (Read w8 0 a)" %t2 +# RUN: grep "(Sub w8 (Read w8 2 a) (Read w8 1 a)" %t2 (query [] false [(Add w8 (Sub w8 (Read w8 0 a) (Read w8 1 a)) (Read w8 2 a))]) # Check -- X + (C + Y) ==> C + (X + Y) -# RUN: grep -A 3 \"# Query 10$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 10\" %t2 -# RUN: grep \"(Add w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 10$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 10" %t2 +# RUN: grep "(Add w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Add w8 (Read w8 0 a) (Add w8 10 (Read w8 1 a)))]) # Check -- X + (Y + C) ==> C + (X + Y) -# RUN: grep -A 3 \"# Query 11$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 10\" %t2 -# RUN: grep \"(Add w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 11$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 10" %t2 +# RUN: grep "(Add w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Add w8 (Read w8 0 a) (Add w8 (Read w8 1 a) 10))]) # Check -- X + (C - Y) ==> C + (X - Y) -# RUN: grep -A 3 \"# Query 12$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 10\" %t2 -# RUN: grep \"(Sub w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 12$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 10" %t2 +# RUN: grep "(Sub w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Add w8 (Read w8 0 a) (Sub w8 10 (Read w8 1 a)))]) # Check -- X + (Y - C) ==> -C + (X + Y) -# RUN: grep -A 3 \"# Query 13$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 246\" %t2 -# RUN: grep \"(Add w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 13$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 246" %t2 +# RUN: grep "(Add w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Add w8 (Read w8 0 a) (Sub w8 (Read w8 1 a) 10))]) # Check -- C_0 - (C_1 + X) ==> (C_0 - C1) - X -# RUN: grep -A 2 \"# Query 14$\" %t > %t2 -# RUN: grep \"(query .. false .(Sub w8 10 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 14$" %t > %t2 +# RUN: grep "(query .. false .(Sub w8 10 (Read w8 0 a))" %t2 (query [] false [(Sub w8 20 (Add w8 10 (Read w8 0 a)))]) # Check -- C_0 - (X + C_1) ==> (C_0 + C1) + X -# RUN: grep -A 2 \"# Query 15$\" %t > %t2 -# RUN: grep \"(query .. false .(Sub w8 10 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 15$" %t > %t2 +# RUN: grep "(query .. false .(Sub w8 10 (Read w8 0 a))" %t2 (query [] false [(Sub w8 20 (Add w8 (Read w8 0 a) 10))]) # Check -- C_0 - (C_1 - X) ==> (C_0 - C1) + X -# RUN: grep -A 2 \"# Query 16$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 10 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 16$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 10 (Read w8 0 a))" %t2 (query [] false [(Sub w8 20 (Sub w8 10 (Read w8 0 a)))]) # Check -- C_0 - (X - C_1) ==> (C_0 + C1) - X -# RUN: grep -A 2 \"# Query 17$\" %t > %t2 -# RUN: grep \"(query .. false .(Sub w8 30 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 17$" %t > %t2 +# RUN: grep "(query .. false .(Sub w8 30 (Read w8 0 a))" %t2 (query [] false [(Sub w8 20 (Sub w8 (Read w8 0 a) 10))]) # Check -- (C_0 + X) - C_1 ==> (C_0 - C1) + X -# RUN: grep -A 2 \"# Query 18$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 246 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 18$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 246 (Read w8 0 a))" %t2 (query [] false [(Sub w8 (Add w8 10 (Read w8 0 a)) 20)]) # Check -- (X + C_0) - C_1 ==> (C_0 - C1) + X -# RUN: grep -A 2 \"# Query 19$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 246 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 19$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 246 (Read w8 0 a))" %t2 (query [] false [(Sub w8 (Add w8 (Read w8 0 a) 10) 20)]) # Check -- (C_0 - X) - C_1 ==> (C_0 - C1) - X -# RUN: grep -A 2 \"# Query 20$\" %t > %t2 -# RUN: grep \"(query .. false .(Sub w8 246 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 20$" %t > %t2 +# RUN: grep "(query .. false .(Sub w8 246 (Read w8 0 a))" %t2 (query [] false [(Sub w8 (Sub w8 10 (Read w8 0 a)) 20)]) # Check -- (X - C_0) - C_1 ==> -(C_0 + C1) + X -# RUN: grep -A 2 \"# Query 21$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 226 (Read w8 0 a))\" %t2 +# RUN: grep -A 2 "# Query 21$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 226 (Read w8 0 a))" %t2 (query [] false [(Sub w8 (Sub w8 (Read w8 0 a) 10) 20)]) # Check -- (X + Y) - Z ==> X + (Y - Z) -# RUN: grep -A 3 \"# Query 22$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 (Read w8 0 a)\" %t2 -# RUN: grep \"(Sub w8 (Read w8 1 a) (Read w8 2 a)\" %t2 +# RUN: grep -A 3 "# Query 22$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 (Read w8 0 a)" %t2 +# RUN: grep "(Sub w8 (Read w8 1 a) (Read w8 2 a)" %t2 (query [] false [(Sub w8 (Add w8 (Read w8 0 a) (Read w8 1 a)) (Read w8 2 a))]) # Check -- (X - Y) - Z ==> X - (Y + Z) -# RUN: grep -A 3 \"# Query 23$\" %t > %t2 -# RUN: grep \"(query .. false .(Sub w8 (Read w8 0 a)\" %t2 -# RUN: grep \"(Add w8 (Read w8 1 a) (Read w8 2 a)\" %t2 +# RUN: grep -A 3 "# Query 23$" %t > %t2 +# RUN: grep "(query .. false .(Sub w8 (Read w8 0 a)" %t2 +# RUN: grep "(Add w8 (Read w8 1 a) (Read w8 2 a)" %t2 (query [] false [(Sub w8 (Sub w8 (Read w8 0 a) (Read w8 1 a)) (Read w8 2 a))]) # Check -- X - (C + Y) ==> -C + (X - Y) -# RUN: grep -A 3 \"# Query 24$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 246\" %t2 -# RUN: grep \"(Sub w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 24$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 246" %t2 +# RUN: grep "(Sub w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Sub w8 (Read w8 0 a) (Add w8 10 (Read w8 1 a)))]) # Check -- X - (Y + C) ==> -C + (X - Y) -# RUN: grep -A 3 \"# Query 25$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 246\" %t2 -# RUN: grep \"(Sub w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 25$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 246" %t2 +# RUN: grep "(Sub w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Sub w8 (Read w8 0 a) (Add w8 (Read w8 1 a) 10))]) # Check -- X - (C - Y) ==> -C + (X + Y) -# RUN: grep -A 3 \"# Query 26$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 246\" %t2 -# RUN: grep \"(Add w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 26$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 246" %t2 +# RUN: grep "(Add w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Sub w8 (Read w8 0 a) (Sub w8 10 (Read w8 1 a)))]) # Check -- X - (Y - C) ==> C + (X - Y) -# RUN: grep -A 3 \"# Query 27$\" %t > %t2 -# RUN: grep \"(query .. false .(Add w8 10\" %t2 -# RUN: grep \"(Sub w8 (Read w8 0 a) (Read w8 1 a)\" %t2 +# RUN: grep -A 3 "# Query 27$" %t > %t2 +# RUN: grep "(query .. false .(Add w8 10" %t2 +# RUN: grep "(Sub w8 (Read w8 0 a) (Read w8 1 a)" %t2 (query [] false [(Sub w8 (Read w8 0 a) (Sub w8 (Read w8 1 a) 10))]) # Check -- X * 0 ==> 0 -# RUN: grep -A 2 \"# Query 28$\" %t > %t2 -# RUN: grep \"(query .. false .(w8 0).\" %t2 +# RUN: grep -A 2 "# Query 28$" %t > %t2 +# RUN: grep "(query .. false .(w8 0)." %t2 (query [] false [(Mul w8 0 (Read w8 0 a))]) # Check -- X * 1 ==> X -# RUN: grep -A 2 \"# Query 29$\" %t > %t2 -# RUN: grep \"(query .. false .(Read w8 0 a).\" %t2 +# RUN: grep -A 2 "# Query 29$" %t > %t2 +# RUN: grep "(query .. false .(Read w8 0 a)." %t2 (query [] false [(Mul w8 1 (Read w8 0 a))]) # Check -- X & 0 ==> 0 -# RUN: grep -A 2 \"# Query 30$\" %t > %t2 -# RUN: grep \"(query .. false .(w8 0).\" %t2 +# RUN: grep -A 2 "# Query 30$" %t > %t2 +# RUN: grep "(query .. false .(w8 0)." %t2 (query [] false [(And w8 0 (Read w8 0 a))]) # Check -- X & 0b1...1 ==> X -# RUN: grep -A 2 \"# Query 31$\" %t > %t2 -# RUN: grep \"(query .. false .(Read w8 0 a).\" %t2 +# RUN: grep -A 2 "# Query 31$" %t > %t2 +# RUN: grep "(query .. false .(Read w8 0 a)." %t2 (query [] false [(And w8 255 (Read w8 0 a))]) # Check -- X | 0 ==> X -# RUN: grep -A 2 \"# Query 32$\" %t > %t2 -# RUN: grep \"(query .. false .(Read w8 0 a).\" %t2 +# RUN: grep -A 2 "# Query 32$" %t > %t2 +# RUN: grep "(query .. false .(Read w8 0 a)." %t2 (query [] false [(Or w8 0 (Read w8 0 a))]) # Check -- X | 0b1...1 ==> X -# RUN: grep -A 2 \"# Query 33$\" %t > %t2 -# RUN: grep \"(query .. false .(w8 255).\" %t2 +# RUN: grep -A 2 "# Query 33$" %t > %t2 +# RUN: grep "(query .. false .(w8 255)." %t2 (query [] false [(Or w8 255 (Read w8 0 a))]) # Check -- X ^ 0b1...1 ==> X -# RUN: grep -A 2 \"# Query 34$\" %t > %t2 -# RUN: grep \"(query .. false .(Read w8 0 a).\" %t2 +# RUN: grep -A 2 "# Query 34$" %t > %t2 +# RUN: grep "(query .. false .(Read w8 0 a)." %t2 (query [] false [(Xor w8 0 (Read w8 0 a))]) # Check -- true == X ==> X -# RUN: grep -A 2 \"# Query 35$\" %t > %t2 -# RUN: grep \"(query .. false .(Eq 0 (Read w8 0 a)).\" %t2 +# RUN: grep -A 2 "# Query 35$" %t > %t2 +# RUN: grep "(query .. false .(Eq 0 (Read w8 0 a))." %t2 (query [] false [(Eq true (Eq 0 (Read w8 0 a)))]) # Check -- !!X ==> X -# RUN: grep -A 2 \"# Query 36$\" %t > %t2 -# RUN: grep \"(query .. false .(Eq 0 (Read w8 0 a)).\" %t2 +# RUN: grep -A 2 "# Query 36$" %t > %t2 +# RUN: grep "(query .. false .(Eq 0 (Read w8 0 a))." %t2 (query [] false [(Not (Not (Eq 0 (Read w8 0 a))))]) # Check -- !Const -# RUN: grep -A 2 \"# Query 37$\" %t > %t2 -# RUN: grep \"(query .. false .true.\" %t2 +# RUN: grep -A 2 "# Query 37$" %t > %t2 +# RUN: grep "(query .. false .true." %t2 (query [] false [(Eq (Not w32 0xdeadbeef) 0x21524110)]) diff --git a/test/Expr/Parser/MultiByteReads.pc b/test/Expr/Parser/MultiByteReads.pc index ea2e7a5d..71f0288f 100644 --- a/test/Expr/Parser/MultiByteReads.pc +++ b/test/Expr/Parser/MultiByteReads.pc @@ -1,6 +1,6 @@ -# RUN: %kleaver -print-ast -pc-multibyte-reads=true %s >log -# RUN: grep -q "(ReadLSB w32 4 arr1)" log -# RUN: grep -q "(ReadMSB w32 2 arr2)" log +# RUN: %kleaver -print-ast -pc-multibyte-reads=true %s > %t.log +# RUN: grep -q "(ReadLSB w32 4 arr1)" %t.log +# RUN: grep -q "(ReadMSB w32 2 arr2)" %t.log array arr1[8] : w32 -> w8 = symbolic array arr2[8] : w32 -> w8 = symbolic diff --git a/test/Expr/Parser/Simplify.pc b/test/Expr/Parser/Simplify.pc index 1a853b16..6d817b6f 100644 --- a/test/Expr/Parser/Simplify.pc +++ b/test/Expr/Parser/Simplify.pc @@ -3,38 +3,38 @@ array a[64] : w32 -> w8 = symbolic # Check -- X u> Y ==> Y u< X -# RUN: grep -A 2 \"# Query 1\" %t > %t2 -# RUN: grep \"(query .. false .(Ult (Read w8 1 a) (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 1" %t > %t2 +# RUN: grep "(query .. false .(Ult (Read w8 1 a) (Read w8 0 a)).)" %t2 (query [] false [(Ugt (Read w8 0 a) (Read w8 1 a))]) # Check -- X u>= Y ==> Y u<= X -# RUN: grep -A 2 \"# Query 2\" %t > %t2 -# RUN: grep \"(query .. false .(Ule (Read w8 1 a) (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 2" %t > %t2 +# RUN: grep "(query .. false .(Ule (Read w8 1 a) (Read w8 0 a)).)" %t2 (query [] false [(Uge (Read w8 0 a) (Read w8 1 a))]) # Check -- X u> Y ==> Y u< X -# RUN: grep -A 2 \"# Query 3\" %t > %t2 -# RUN: grep \"(query .. false .(Slt (Read w8 1 a) (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 3" %t > %t2 +# RUN: grep "(query .. false .(Slt (Read w8 1 a) (Read w8 0 a)).)" %t2 (query [] false [(Sgt (Read w8 0 a) (Read w8 1 a))]) # Check -- X u>= Y ==> Y u<= X -# RUN: grep -A 2 \"# Query 4\" %t > %t2 -# RUN: grep \"(query .. false .(Sle (Read w8 1 a) (Read w8 0 a)).)\" %t2 +# RUN: grep -A 2 "# Query 4" %t > %t2 +# RUN: grep "(query .. false .(Sle (Read w8 1 a) (Read w8 0 a)).)" %t2 (query [] false [(Sge (Read w8 0 a) (Read w8 1 a))]) # Check -- X != Y ==> !(X == Y) -# RUN: grep -A 2 \"# Query 5\" %t > %t2 -# RUN: grep \"(query .. false .(Not (Eq (Read w8 0 a) (Read w8 1 a))).)\" %t2 +# RUN: grep -A 2 "# Query 5" %t > %t2 +# RUN: grep "(query .. false .(Not (Eq (Read w8 0 a) (Read w8 1 a))).)" %t2 (query [] false [(Ne (Read w8 0 a) (Read w8 1 a))]) # Check -- !(X or Y) ==> !X and !Y -# RUN: grep -A 3 \"# Query 6$\" %t > %t2 -# RUN: grep \"(query .. false .(And (Not (Eq 0 (Read w8 0 a)))\" %t2 -# RUN: grep \"(Not (Eq 1 (Read w8 1 a))))\" %t2 +# RUN: grep -A 3 "# Query 6$" %t > %t2 +# RUN: grep "(query .. false .(And (Not (Eq 0 (Read w8 0 a)))" %t2 +# RUN: grep "(Not (Eq 1 (Read w8 1 a))))" %t2 (query [] false [(Not (Or (Eq 0 (Read w8 0 a)) (Eq 1 (Read w8 1 a))))]) # Check -- false == X ==> !X -# RUN: grep -A 2 \"# Query 7\" %t > %t2 -# RUN: grep \"(query .. false .(Not (Extract 1 (Read w8 0 a))).)\" %t2 +# RUN: grep -A 2 "# Query 7" %t > %t2 +# RUN: grep "(query .. false .(Not (Extract 1 (Read w8 0 a))).)" %t2 (query [] false [(Eq (Extract w1 1 (Read w8 0 a)) false)]) diff --git a/test/Expr/Parser/dg.exp b/test/Expr/Parser/dg.exp deleted file mode 100644 index 94fc4df8..00000000 --- a/test/Expr/Parser/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{pc}]] diff --git a/test/Expr/dg.exp b/test/Expr/dg.exp deleted file mode 100644 index 94fc4df8..00000000 --- a/test/Expr/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{pc}]] diff --git a/test/Expr/print-smt.smt2.good b/test/Expr/print-smt.smt2.good index cca282af..7b2002b9 100644 --- a/test/Expr/print-smt.smt2.good +++ b/test/Expr/print-smt.smt2.good @@ -859,9 +859,9 @@ ;SMTLIBv2 Query 72 (set-option :produce-models true) (set-logic QF_AUFBV ) -(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun const_arr2 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (= (select const_arr2 (_ bv0 32) ) (_ bv121 8) ) ) (assert (= (select const_arr2 (_ bv1 32) ) (_ bv101 8) ) ) (assert (= (select const_arr2 (_ bv2 32) ) (_ bv115 8) ) ) @@ -881,8 +881,8 @@ ;SMTLIBv2 Query 73 (set-option :produce-models true) (set-logic QF_AUFBV ) -(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (let ( (?B0 ((_ extract 31 0) (bvadd (_ bv18446744073709533360 64) (bvmul (_ bv4 64) ((_ sign_extend 32) (concat (select unnamed_1 (_ bv3 32) ) (concat (select unnamed_1 (_ bv2 32) ) (concat (select unnamed_1 (_ bv1 32) ) (select unnamed_1 (_ bv0 32) ) ) ) ) ) ) ) ) ) (?B1 (bvadd (_ bv18446744073709533360 64) (bvmul (_ bv4 64) ((_ sign_extend 32) (concat (select unnamed_1 (_ bv3 32) ) (concat (select unnamed_1 (_ bv2 32) ) (concat (select unnamed_1 (_ bv1 32) ) (select unnamed_1 (_ bv0 32) ) ) ) ) ) ) ) ) (?B2 (bvmul (_ bv4 64) ((_ sign_extend 32) (concat (select unnamed_1 (_ bv3 32) ) (concat (select unnamed_1 (_ bv2 32) ) (concat (select unnamed_1 (_ bv1 32) ) (select unnamed_1 (_ bv0 32) ) ) ) ) ) ) ) ) (and (= false (bvult ?B2 (_ bv13 64) ) ) (and (= false (bvult (bvadd (_ bv31312 64) ?B2 ) (_ bv1 64) ) ) (and (= false (bvult (bvadd (_ bv31760 64) ?B2 ) (_ bv13 64) ) ) (and (= false (bvult (bvadd (_ bv111120 64) ?B2 ) (_ bv1 64) ) ) (and (bvult ?B1 (_ bv1 64) ) (= false (= (concat (select unnamed (_ bv3 32) ) (concat (select unnamed (_ bv2 32) ) (concat (select unnamed (_ bv1 32) ) (select unnamed (_ bv0 32) ) ) ) ) (concat (select unnamed (bvadd (_ bv3 32) ?B0 ) ) (concat (select unnamed (bvadd (_ bv2 32) ?B0 ) ) (concat (select unnamed (bvadd (_ bv1 32) ?B0 ) ) (select unnamed ?B0 ) ) ) ) ) ) ) ) ) ) ) ) ) (check-sat) (get-value ( (select unnamed_1 (_ bv0 32) ) ) ) @@ -898,9 +898,9 @@ ;SMTLIBv2 Query 74 (set-option :produce-models true) (set-logic QF_AUFBV ) -(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) -(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun const_arr5 () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (= (select const_arr5 (_ bv0 32) ) (_ bv171 8) ) ) (assert (= (select const_arr5 (_ bv1 32) ) (_ bv171 8) ) ) (assert (= (select const_arr5 (_ bv2 32) ) (_ bv171 8) ) ) @@ -920,9 +920,9 @@ ;SMTLIBv2 Query 75 (set-option :produce-models true) (set-logic QF_AUFBV ) -(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) -(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun const_arr1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (= (select const_arr1 (_ bv0 32) ) (_ bv12 8) ) ) (assert (= (select const_arr1 (_ bv1 32) ) (_ bv0 8) ) ) (assert (= (select const_arr1 (_ bv2 32) ) (_ bv0 8) ) ) @@ -954,9 +954,9 @@ ;SMTLIBv2 Query 76 (set-option :produce-models true) (set-logic QF_AUFBV ) -(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) -(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun const_arr4 () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (= (select const_arr4 (_ bv0 32) ) (_ bv171 8) ) ) (assert (= (select const_arr4 (_ bv1 32) ) (_ bv171 8) ) ) (assert (= (select const_arr4 (_ bv2 32) ) (_ bv171 8) ) ) @@ -976,9 +976,9 @@ ;SMTLIBv2 Query 77 (set-option :produce-models true) (set-logic QF_AUFBV ) -(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) -(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun const_arr3 () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (= (select const_arr3 (_ bv0 32) ) (_ bv12 8) ) ) (assert (= (select const_arr3 (_ bv1 32) ) (_ bv0 8) ) ) (assert (= (select const_arr3 (_ bv2 32) ) (_ bv0 8) ) ) @@ -1010,8 +1010,8 @@ ;SMTLIBv2 Query 78 (set-option :produce-models true) (set-logic QF_AUFBV ) -(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun unnamed () (Array (_ BitVec 32) (_ BitVec 8) ) ) +(declare-fun unnamed_1 () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (let ( (?B0 ((_ extract 31 0) (bvadd (_ bv18446744073709532800 64) (bvmul (_ bv4 64) ((_ sign_extend 32) (concat (select unnamed_1 (_ bv3 32) ) (concat (select unnamed_1 (_ bv2 32) ) (concat (select unnamed_1 (_ bv1 32) ) (select unnamed_1 (_ bv0 32) ) ) ) ) ) ) ) ) ) (?B1 (bvadd (_ bv18446744073709532800 64) (bvmul (_ bv4 64) ((_ sign_extend 32) (concat (select unnamed_1 (_ bv3 32) ) (concat (select unnamed_1 (_ bv2 32) ) (concat (select unnamed_1 (_ bv1 32) ) (select unnamed_1 (_ bv0 32) ) ) ) ) ) ) ) ) (?B2 (bvmul (_ bv4 64) ((_ sign_extend 32) (concat (select unnamed_1 (_ bv3 32) ) (concat (select unnamed_1 (_ bv2 32) ) (concat (select unnamed_1 (_ bv1 32) ) (select unnamed_1 (_ bv0 32) ) ) ) ) ) ) ) ) (and (= false (bvult ?B2 (_ bv13 64) ) ) (and (= false (bvult (bvadd (_ bv31312 64) ?B2 ) (_ bv1 64) ) ) (and (= false (bvult (bvadd (_ bv31760 64) ?B2 ) (_ bv13 64) ) ) (and (= false (bvult (bvadd (_ bv111120 64) ?B2 ) (_ bv1 64) ) ) (and (= false (bvult (bvadd (_ bv18446744073709533360 64) ?B2 ) (_ bv1 64) ) ) (and (= false (bvult (bvadd (_ bv18446744073709533328 64) ?B2 ) (_ bv1 64) ) ) (and (bvult ?B1 (_ bv1 64) ) (= (concat (select unnamed (_ bv3 32) ) (concat (select unnamed (_ bv2 32) ) (concat (select unnamed (_ bv1 32) ) (select unnamed (_ bv0 32) ) ) ) ) (concat (select unnamed_1 (bvadd (_ bv3 32) ?B0 ) ) (concat (select unnamed_1 (bvadd (_ bv2 32) ?B0 ) ) (concat (select unnamed_1 (bvadd (_ bv1 32) ?B0 ) ) (select unnamed_1 ?B0 ) ) ) ) ) ) ) ) ) ) ) ) ) ) (check-sat) (get-value ( (select unnamed_1 (_ bv0 32) ) ) ) diff --git a/test/Feature/AliasFunction.c b/test/Feature/AliasFunction.c index 16d89ef6..176b152e 100644 --- a/test/Feature/AliasFunction.c +++ b/test/Feature/AliasFunction.c @@ -1,25 +1,28 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee %t1.bc > %t1.log // RUN: grep -c foo %t1.log | grep 5 -// RUN: grep -c bar %t1.log | grep 3 +// RUN: grep -c bar %t1.log | grep 4 #include <stdio.h> #include <stdlib.h> -void foo() { printf(" foo()\n"); } -void bar() { printf(" bar()\n"); } +void __attribute__ ((noinline)) foo() { printf(" foo()\n"); } +void __attribute__ ((noinline)) bar() { printf(" bar()\n"); } int main() { int x; klee_make_symbolic(&x, sizeof(x), "x"); + // call once, so that it is not removed by optimizations + bar(); + // no aliases foo(); if (x > 10) { // foo -> bar - klee_alias_function("foo", "bar"); + klee_alias_function("foo", "bar"); if (x > 20) foo(); diff --git a/test/Feature/AliasFunctionExit.c b/test/Feature/AliasFunctionExit.c index 4bda950a..acfa4350 100644 --- a/test/Feature/AliasFunctionExit.c +++ b/test/Feature/AliasFunctionExit.c @@ -13,7 +13,7 @@ void start(int x) { exit(1); } -void end(int status) { +void __attribute__ ((noinline)) end(int status) { klee_alias_function("exit", "exit"); printf("END: status = %d\n", status); exit(status); diff --git a/test/Feature/AsmAddresses.c b/test/Feature/AsmAddresses.c index a58fc059..d0b89ef1 100644 --- a/test/Feature/AsmAddresses.c +++ b/test/Feature/AsmAddresses.c @@ -1,6 +1,6 @@ -// RUN: %llvmgcc -g -c -o %t.bc %s +// RUN: %llvmgcc -emit-llvm -g -c -o %t.bc %s // RUN: %klee --exit-on-error --use-asm-addresses %t.bc -// RUN: %llvmgcc -DOVERLAP -g -c -o %t.bc %s +// RUN: %llvmgcc -emit-llvm -DOVERLAP -g -c -o %t.bc %s // RUN: not %klee --exit-on-error --use-asm-addresses %t.bc #include <assert.h> diff --git a/test/Feature/CallToUndefinedExternal.cpp b/test/Feature/CallToUndefinedExternal.cpp index 84b5a3b4..26e8fc55 100644 --- a/test/Feature/CallToUndefinedExternal.cpp +++ b/test/Feature/CallToUndefinedExternal.cpp @@ -1,10 +1,11 @@ // RUN: %llvmgxx %s -emit-llvm -g -c -o %t1.bc -// RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.external.err +// RUN: %klee %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.external.err extern "C" void poof(void); int main() { + // CHECK: failed external call: poof poof(); return 0; diff --git a/test/Feature/CheckMemoryAccess.c b/test/Feature/CheckMemoryAccess.c index dd6e8745..30590f88 100644 --- a/test/Feature/CheckMemoryAccess.c +++ b/test/Feature/CheckMemoryAccess.c @@ -1,4 +1,4 @@ -// RUN: %llvmgcc -g -c %s -o %t.bc +// RUN: %llvmgcc -emit-llvm -g -c %s -o %t.bc // RUN: %klee %t.bc > %t.log // RUN: grep -q "good" %t.log // RUN: not grep -q "bad" %t.log diff --git a/test/Feature/DanglingConcreteReadExpr.c b/test/Feature/DanglingConcreteReadExpr.c index 1bf44c3f..204187a2 100644 --- a/test/Feature/DanglingConcreteReadExpr.c +++ b/test/Feature/DanglingConcreteReadExpr.c @@ -1,6 +1,6 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee %t1.bc -// RUN: grep "total queries = 2" klee-last/info +// RUN: grep "total queries = 2" %T/klee-last/info #include <assert.h> diff --git a/test/Feature/DefineFixedObject.c b/test/Feature/DefineFixedObject.c index 36822434..9f71f89b 100644 --- a/test/Feature/DefineFixedObject.c +++ b/test/Feature/DefineFixedObject.c @@ -1,4 +1,4 @@ -// RUN: %llvmgcc -c -o %t1.bc %s +// RUN: %llvmgcc -emit-llvm -c -o %t1.bc %s // RUN: %klee --exit-on-error %t1.bc #include <stdio.h> diff --git a/test/Feature/DoubleFree.c b/test/Feature/DoubleFree.c index 3727ef2b..d97e0c08 100644 --- a/test/Feature/DoubleFree.c +++ b/test/Feature/DoubleFree.c @@ -1,10 +1,11 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.ptr.err +// RUN: %klee %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.ptr.err int main() { int *x = malloc(4); free(x); + // CHECK: memory error: invalid pointer: free free(x); return 0; } diff --git a/test/Feature/DumpStatesOnHalt.c b/test/Feature/DumpStatesOnHalt.c index d86b786b..993fdb6a 100644 --- a/test/Feature/DumpStatesOnHalt.c +++ b/test/Feature/DumpStatesOnHalt.c @@ -1,8 +1,11 @@ // RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee --stop-after-n-instructions=1 --dump-states-on-halt=true %t1.bc -// RUN: test -f klee-last/test000001.ktest +// RUN: %klee --stop-after-n-instructions=1 --dump-states-on-halt=true %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.ktest -int main() { - int x = 10; +int main(int argc, char** argv) { + int x = 1; + if (argc == 1) + x = 0; return x; } +// CHECK: halting execution, dumping remaining states diff --git a/test/Feature/ExprLogging.c b/test/Feature/ExprLogging.c index 9e9df87a..abab8031 100644 --- a/test/Feature/ExprLogging.c +++ b/test/Feature/ExprLogging.c @@ -1,14 +1,14 @@ // RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t1.bc // We disable the cex-cache to eliminate nondeterminism across different solvers, in particular when counting the number of queries in the last two commands // RUN: %klee --use-cex-cache=false --use-query-log=all:pc,all:smt2,solver:pc,solver:smt2 --write-pcs --write-cvcs --write-smt2s %t1.bc 2> %t2.log -// RUN: %kleaver -print-ast klee-last/all-queries.pc > %t3.log +// RUN: %kleaver -print-ast %T/klee-last/all-queries.pc > %t3.log // RUN: %kleaver -print-ast %t3.log > %t4.log // RUN: diff %t3.log %t4.log -// RUN: %kleaver -print-ast klee-last/solver-queries.pc > %t3.log +// RUN: %kleaver -print-ast %T/klee-last/solver-queries.pc > %t3.log // RUN: %kleaver -print-ast %t3.log > %t4.log // RUN: diff %t3.log %t4.log -// RUN: grep "^; Query" klee-last/all-queries.smt2 | wc -l | grep -q 17 -// RUN: grep "^; Query" klee-last/solver-queries.smt2 | wc -l | grep -q 17 +// RUN: grep "^; Query" %T/klee-last/all-queries.smt2 | wc -l | grep -q 17 +// RUN: grep "^; Query" %T/klee-last/solver-queries.smt2 | wc -l | grep -q 17 #include <assert.h> diff --git a/test/Feature/Float.c b/test/Feature/Float.c index a1f54fd8..f7e4dde0 100644 --- a/test/Feature/Float.c +++ b/test/Feature/Float.c @@ -1,4 +1,4 @@ -// RUN: %llvmgcc -g -c %s -o %t.bc +// RUN: %llvmgcc -emit-llvm -g -c %s -o %t.bc // RUN: %klee %t.bc > %t.log // RUN: grep "3.30* -1.10* 2.420*" %t.log diff --git a/test/Feature/GetValue.c b/test/Feature/GetValue.c index dfd40d69..5023c51c 100644 --- a/test/Feature/GetValue.c +++ b/test/Feature/GetValue.c @@ -1,4 +1,4 @@ -// RUN: %llvmgcc -c -o %t1.bc %s +// RUN: %llvmgcc -emit-llvm -c -o %t1.bc %s // RUN: %klee --exit-on-error %t1.bc #include <stdio.h> diff --git a/test/Feature/InAndOutOfBounds.c b/test/Feature/InAndOutOfBounds.c index ba655b83..729d6b78 100644 --- a/test/Feature/InAndOutOfBounds.c +++ b/test/Feature/InAndOutOfBounds.c @@ -1,8 +1,8 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.ptr.err -o -f klee-last/test000002.ptr.err -// RUN: test ! -f klee-last/test000001.ptr.err -o ! -f klee-last/test000002.ptr.err -// RUN: test ! -f klee-last/test000003.ktest +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.ptr.err -o -f %T/klee-last/test000002.ptr.err +// RUN: not test -f %T/klee-last/test000001.ptr.err -a -f %T/klee-last/test000002.ptr.err +// RUN: not test -f %T/klee-last/test000003.ktest unsigned klee_urange(unsigned start, unsigned end) { unsigned x; @@ -12,7 +12,9 @@ unsigned klee_urange(unsigned start, unsigned end) { } int main() { - int *x = malloc(4); + int *x = malloc(sizeof(int)); + // FIXME: Use newer FileCheck syntax to support relative line numbers + // CHECK: InAndOutOfBounds.c:18: memory error: out of bound pointer x[klee_urange(0,2)] = 1; free(x); return 0; diff --git a/test/Feature/IntrinsicTrap.ll b/test/Feature/IntrinsicTrap.ll index 5af46225..13b93e4d 100644 --- a/test/Feature/IntrinsicTrap.ll +++ b/test/Feature/IntrinsicTrap.ll @@ -1,8 +1,6 @@ ; RUN: llvm-as %s -f -o %t1.bc ; RUN: %klee -disable-opt %t1.bc -; RUN: grep abort() klee-last/assembly.ll | wc -l | grep -q 2 -; RUN: echo "llvm.trap()" > %t2.ll -; RUN: grep llvm.trap() klee-last/assembly.ll %t2.ll | wc -l | grep -q 1 +; RUN: FileCheck %s --input-file=%T/klee-last/assembly.ll target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" @@ -15,6 +13,8 @@ entry: br i1 %c, label %btrue, label %bfalse btrue: + ; CHECK-NOT: call void @llvm.trap() + ; CHECK: call void @abort() call void @llvm.trap() noreturn nounwind unreachable @@ -25,4 +25,6 @@ return: ret i32 0 } +; CHECK-NOT: call void @llvm.trap() +; CHECK: declare void @abort() declare void @llvm.trap() noreturn nounwind diff --git a/test/Feature/KleeReportError.c b/test/Feature/KleeReportError.c index dda72fd0..37c07ed1 100644 --- a/test/Feature/KleeReportError.c +++ b/test/Feature/KleeReportError.c @@ -1,6 +1,6 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc -// RUN: %klee --emit-all-errors %t2.bc > %t3.log -// RUN: ls klee-last/ | grep .my.err | wc -l | grep 2 +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --emit-all-errors %t2.bc 2>&1 | FileCheck %s +// RUN: ls %T/klee-last/ | grep .my.err | wc -l | grep 2 #include <stdio.h> #include <assert.h> @@ -16,6 +16,9 @@ int main(int argc, char** argv) { if (y) { fprintf(stderr, "My error\n"); + // CHECK: KleeReportError.c:22: My error + // CHECK: KleeReportError.c:22: My error + // FIXME: Use FileCheck's relative line number syntax klee_report_error(__FILE__, __LINE__, "My error", "my.err"); } diff --git a/test/Feature/LongDouble.cpp b/test/Feature/LongDouble.cpp index ecee43b4..6e6baf6a 100644 --- a/test/Feature/LongDouble.cpp +++ b/test/Feature/LongDouble.cpp @@ -1,11 +1,11 @@ // RUN: %llvmgxx -I../../../include -g -fno-exceptions -emit-llvm -O0 -c -o %t.bc %s // RUN: %klee --libc=klee --no-output --exit-on-error %t.bc > %t.log -// RUN: grep -q {powl\(-11\\.0,0\)=1\\.0\\+} %t.log -// RUN: grep -q {powl\(-11\\.0,1\)=-11\\.0\\+} %t.log -// RUN: grep -q {powl\(-11\\.0,2\)=121\\.0\\+} %t.log -// RUN: grep -q {1/0=inf} %t.log -// RUN: grep -q {1/-1=-1\\.0\\+} %t.log -// RUN: grep -q {1/-2=-0\\.50\\+} %t.log +// RUN: grep -q powl\(-11\\.0,0\)=1\\.0\\+ %t.log +// RUN: grep -q powl\(-11\\.0,1\)=-11\\.0\\+ %t.log +// RUN: grep -q powl\(-11\\.0,2\)=121\\.0\\+ %t.log +// RUN: grep -q 1/0=inf %t.log +// RUN: grep -q 1/-1=-1\\.0\\+ %t.log +// RUN: grep -q 1/-2=-0\\.50\\+ %t.log #include <cstdio> #include <cstdlib> @@ -44,10 +44,17 @@ int main(int argc, char ** argv) // test 80-bit external dispatch long double d = powl((long double)-11.0, (long double)a); + // FIXME: Use CHECK-DAG: with FileCheck tool + // CHECK-DAG: powl(-11.0,0)=1.0 + // CHECK-DAG: powl(-11.0,1)=-11.0 + // CHECK-DAG: powl(-11.0,2)=121.0 printf("powl(-11.0,%d)=%Lf\n", a, d); // test 80-bit fdiv long double e = (long double) 1 / (long double) b; + // CHECK-DAG: 1/0=inf + // CHECK-DAG: 1/1-1=-1.0 + // CHECK-DAG: 1/-2=-0.50 printf("1/%d=%Lf\n", b, e); return 0; diff --git a/test/Feature/LowerSwitch.c b/test/Feature/LowerSwitch.c index 1b92e398..49cad076 100644 --- a/test/Feature/LowerSwitch.c +++ b/test/Feature/LowerSwitch.c @@ -1,8 +1,8 @@ // RUN: %llvmgcc %s -emit-llvm -g -c -o %t.bc // RUN: %klee --exit-on-error --allow-external-sym-calls --switch-type=internal %t.bc -// RUN: not test -f klee-last/test000010.ktest +// RUN: not test -f %T/klee-last/test000010.ktest // RUN: %klee --exit-on-error --allow-external-sym-calls --switch-type=simple %t.bc -// RUN: test -f klee-last/test000010.ktest +// RUN: test -f %T/klee-last/test000010.ktest #include <stdio.h> diff --git a/test/Feature/MakeConcreteSymbolic.c b/test/Feature/MakeConcreteSymbolic.c index 29b43a04..bfbb807d 100644 --- a/test/Feature/MakeConcreteSymbolic.c +++ b/test/Feature/MakeConcreteSymbolic.c @@ -1,8 +1,8 @@ // RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc // RUN: %klee --exit-on-error %t1.bc -// RUN: grep "done: total queries = 0" klee-last/info +// RUN: grep "done: total queries = 0" %T/klee-last/info // RUN: %klee --make-concrete-symbolic=1 --exit-on-error %t1.bc -// RUN: grep "done: total queries = 2" klee-last/info +// RUN: grep "done: total queries = 2" %T/klee-last/info #include <assert.h> diff --git a/test/Feature/MemoryLimit.c b/test/Feature/MemoryLimit.c index d959c3de..a3c1250e 100644 --- a/test/Feature/MemoryLimit.c +++ b/test/Feature/MemoryLimit.c @@ -1,5 +1,5 @@ -// RUN: %llvmgcc -DLITTLE_ALLOC -g -c %s -o %t.little.bc -// RUN: %llvmgcc -g -c %s -o %t.big.bc +// RUN: %llvmgcc -emit-llvm -DLITTLE_ALLOC -g -c %s -o %t.little.bc +// RUN: %llvmgcc -emit-llvm -g -c %s -o %t.big.bc // RUN: %klee --max-memory=20 %t.little.bc > %t.little.log // RUN: %klee --max-memory=20 %t.big.bc > %t.big.log // RUN: not grep -q "MALLOC FAILED" %t.little.log diff --git a/test/Feature/MultipleFreeResolution.c b/test/Feature/MultipleFreeResolution.c index 8a36f459..cd8a383b 100644 --- a/test/Feature/MultipleFreeResolution.c +++ b/test/Feature/MultipleFreeResolution.c @@ -1,7 +1,7 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee --emit-all-errors %t1.bc -// RUN: ls klee-last/ | grep .ktest | wc -l | grep 4 -// RUN: ls klee-last/ | grep .err | wc -l | grep 3 +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --emit-all-errors %t1.bc 2>&1 | FileCheck %s +// RUN: ls %T/klee-last/ | grep .ktest | wc -l | grep 4 +// RUN: ls %T/klee-last/ | grep .err | wc -l | grep 3 #include <stdlib.h> #include <stdio.h> @@ -31,9 +31,14 @@ int main() { free(buf[s]); + // CHECK: MultipleFreeResolution.c:39: memory error: out of bound pointer + // CHECK: MultipleFreeResolution.c:39: memory error: out of bound pointer + // CHECK: MultipleFreeResolution.c:39: memory error: out of bound pointer + // FIXME: Use FileCheck's relative line numbers for (i=0; i<3; i++) { printf("*buf[%d] = %d\n", i, *buf[i]); } return 0; } +// CHECK: KLEE: done: generated tests = 4 diff --git a/test/Feature/MultipleReallocResolution.c b/test/Feature/MultipleReallocResolution.c index b1a14ace..1f77485f 100644 --- a/test/Feature/MultipleReallocResolution.c +++ b/test/Feature/MultipleReallocResolution.c @@ -1,7 +1,7 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee %t1.bc -// RUN: ls klee-last/ | grep .err | wc -l | grep 2 -// RUN: ls klee-last/ | grep .ptr.err | wc -l | grep 2 +// RUN: ls %T/klee-last/ | grep .err | wc -l | grep 2 +// RUN: ls %T/klee-last/ | grep .ptr.err | wc -l | grep 2 #include <assert.h> #include <stdlib.h> diff --git a/test/Feature/NamedSeedMatching.c b/test/Feature/NamedSeedMatching.c index bb7f6097..16da3117 100644 --- a/test/Feature/NamedSeedMatching.c +++ b/test/Feature/NamedSeedMatching.c @@ -1,4 +1,4 @@ -// RUN: %llvmgcc -c -g %s -o %t.bc +// RUN: %llvmgcc -emit-llvm -c -g %s -o %t.bc // RUN: rm -rf %t.out // RUN: %klee --output-dir=%t.out %t.bc "initial" // RUN: test -f %t.out/test000001.ktest diff --git a/test/Feature/OneFreeError.c b/test/Feature/OneFreeError.c index 8eb13298..e83b535a 100644 --- a/test/Feature/OneFreeError.c +++ b/test/Feature/OneFreeError.c @@ -1,10 +1,12 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.ptr.err +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.ptr.err int main() { int *x = malloc(4); free(x); + // CHECK: OneFreeError.c:10: memory error: out of bound pointer + // FIXME: Use FileCheck's relative line numbers x[0] = 1; return 0; } diff --git a/test/Feature/OneOutOfBounds.c b/test/Feature/OneOutOfBounds.c index 11a9eecb..72d36b70 100644 --- a/test/Feature/OneOutOfBounds.c +++ b/test/Feature/OneOutOfBounds.c @@ -1,9 +1,11 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.ptr.err +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.ptr.err int main() { - int *x = malloc(4); + int *x = malloc(sizeof(int)); + // CHECK: OneOutOfBounds.c:9: memory error: out of bound pointer + // FIXME: Use FileCheck's relative line numbers x[1] = 1; free(x); return 0; diff --git a/test/Feature/OverlappedError.c b/test/Feature/OverlappedError.c index aa220ed9..886c7ec8 100644 --- a/test/Feature/OverlappedError.c +++ b/test/Feature/OverlappedError.c @@ -1,7 +1,7 @@ // RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc // RUN: %klee %t1.bc -// RUN: ls klee-last/ | grep .ktest | wc -l | grep 4 -// RUN: ls klee-last/ | grep .ptr.err | wc -l | grep 2 +// RUN: ls %T/klee-last/ | grep .ktest | wc -l | grep 4 +// RUN: ls %T/klee-last/ | grep .ptr.err | wc -l | grep 2 #include <stdlib.h> diff --git a/test/Feature/PreferCex.c b/test/Feature/PreferCex.c index 97ce5101..6cdb8446 100644 --- a/test/Feature/PreferCex.c +++ b/test/Feature/PreferCex.c @@ -1,6 +1,6 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee --exit-on-error %t1.bc -// RUN: ktest-tool klee-last/test000001.ktest | grep -F 'Hi\x00\x00' +// RUN: ktest-tool %T/klee-last/test000001.ktest | FileCheck %s #include <assert.h> #include <stdlib.h> @@ -10,6 +10,7 @@ int main() { char buf[4]; klee_make_symbolic(buf, sizeof buf); + // CHECK: Hi\x00\x00 klee_prefer_cex(buf, buf[0]=='H'); klee_prefer_cex(buf, buf[1]=='i'); klee_prefer_cex(buf, buf[2]=='\0'); diff --git a/test/Feature/Realloc.c b/test/Feature/Realloc.c index a47adad6..62aa170b 100644 --- a/test/Feature/Realloc.c +++ b/test/Feature/Realloc.c @@ -1,6 +1,5 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee --exit-on-error %t1.bc -// RUN: grep "KLEE: WARNING ONCE: Large alloc" klee-last/warnings.txt +// RUN: %klee --exit-on-error %t1.bc 2>&1 | FileCheck %s #include <assert.h> #include <stdlib.h> @@ -11,6 +10,7 @@ int main() { assert(p); p[1] = 52; + // CHECK: KLEE: WARNING ONCE: Large alloc int *p2 = realloc(p, 1<<30); assert(p2[1] == 52); diff --git a/test/Feature/ReplayPath.c b/test/Feature/ReplayPath.c index f88ad6dc..ccf59657 100644 --- a/test/Feature/ReplayPath.c +++ b/test/Feature/ReplayPath.c @@ -1,7 +1,7 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -DCOND_EXIT -c -o %t1.bc // RUN: klee --write-paths %t1.bc > %t3.good // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc -// RUN: %klee --replay-path klee-last/test000001.path %t2.bc >%t3.log +// RUN: %klee --replay-path %T/klee-last/test000001.path %t2.bc > %t3.log // RUN: diff %t3.log %t3.good #include <unistd.h> diff --git a/test/Feature/SetForking.c b/test/Feature/SetForking.c index 8620110d..cbae33c0 100644 --- a/test/Feature/SetForking.c +++ b/test/Feature/SetForking.c @@ -1,4 +1,4 @@ -// RUN: %llvmgcc -g -c %s -o %t.bc +// RUN: %llvmgcc -emit-llvm -g -c %s -o %t.bc // RUN: %klee %t.bc > %t.log // RUN: sort %t.log | uniq -c > %t.uniq.log // RUN: grep "1 A" %t.uniq.log diff --git a/test/Feature/Vararg.c b/test/Feature/Vararg.c index 9f6643bc..31eee235 100644 --- a/test/Feature/Vararg.c +++ b/test/Feature/Vararg.c @@ -1,7 +1,7 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee %t1.bc > %t2.out // RUN: grep "types: (52, 37, 2.00, (9,12,15))" %t2.out -// RUN: test -f klee-last/test000001.ptr.err +// RUN: test -f %T/klee-last/test000001.ptr.err #include <stdarg.h> #include <assert.h> diff --git a/test/Feature/WriteCov.c b/test/Feature/WriteCov.c index bb2d64e8..45e7bc43 100644 --- a/test/Feature/WriteCov.c +++ b/test/Feature/WriteCov.c @@ -1,7 +1,7 @@ // RUN: %llvmgcc %s -emit-llvm -g -c -o %t2.bc // RUN: %klee --exit-on-error --write-cov %t2.bc -// RUN: grep -c WriteCov.c:15 klee-last/test000001.cov klee-last/test000002.cov >%t3.txt -// RUN: grep -c WriteCov.c:17 klee-last/test000001.cov klee-last/test000002.cov >>%t3.txt +// RUN: grep -c WriteCov.c:15 %T/klee-last/test000001.cov %T/klee-last/test000002.cov >%t3.txt +// RUN: grep -c WriteCov.c:17 %T/klee-last/test000001.cov %T/klee-last/test000002.cov >>%t3.txt // RUN: grep klee-last/test000001.cov:0 %t3.txt // RUN: grep klee-last/test000001.cov:1 %t3.txt // RUN: grep klee-last/test000002.cov:0 %t3.txt diff --git a/test/Feature/arithmetic-right-overshift-sym-conc.c b/test/Feature/arithmetic-right-overshift-sym-conc.c new file mode 100644 index 00000000..81995b2b --- /dev/null +++ b/test/Feature/arithmetic-right-overshift-sym-conc.c @@ -0,0 +1,65 @@ +// RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee -use-cex-cache=1 -check-overshift=0 %t.bc +// RUN: not grep "ASSERTION FAIL" %T/klee-last/messages.txt +// RUN: grep "KLEE: done: explored paths = 1" %T/klee-last/info +#include <stdio.h> +#include <assert.h> + +typedef enum +{ + TO_ZERO, + MASKED, + UNKNOWN +} overshift_t; + +// We're using signed ints so should be doing +// arithmetic right shift. +int overshift(volatile unsigned int y, const char * type) +{ + overshift_t ret; + volatile signed int x=15; + unsigned int limit = sizeof(x)*8; + + volatile signed int result; + result = x >> y; // Potential overshift + + if (result ==0) + { + printf("%s : Overshift to zero\n", type); + ret = TO_ZERO; + } + else if (result == ( x >> (y % limit)) ) + { + printf("%s : Bitmasked overshift\n", type); + ret = MASKED; + } + else + { + printf("%s : Unrecognised behaviour.\n", type); + ret = UNKNOWN; + } + + return ret; +} + +int main(int argc, char** argv) +{ + // Concrete overshift + volatile unsigned int y = sizeof(unsigned int)*8; + overshift_t conc = overshift(y, "Concrete"); + assert( conc == TO_ZERO); + + // Symbolic overshift + volatile unsigned int y2; + klee_make_symbolic(&y2,sizeof(y),"y2"); + // Add constraints so only one value possible + klee_assume(y2 > (y-1)); + klee_assume(y2 < (y+1)); + overshift_t sym = overshift(y2, "Symbolic"); + assert( sym == TO_ZERO); + + // Concrete and symbolic behaviour should be the same + assert( conc == sym); + + return 0; +} diff --git a/test/Feature/dg.exp b/test/Feature/dg.exp deleted file mode 100644 index 879685ca..00000000 --- a/test/Feature/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Feature/left-overshift-sym-conc.c b/test/Feature/left-overshift-sym-conc.c new file mode 100644 index 00000000..e962fa28 --- /dev/null +++ b/test/Feature/left-overshift-sym-conc.c @@ -0,0 +1,63 @@ +// RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee -use-cex-cache=1 -check-overshift=0 %t.bc +// RUN: not grep "ASSERTION FAIL" %T/klee-last/messages.txt +// RUN: grep "KLEE: done: explored paths = 1" %T/klee-last/info +#include <stdio.h> +#include <assert.h> + +typedef enum +{ + TO_ZERO, + MASKED, + UNKNOWN +} overshift_t; + +int overshift(volatile unsigned int y, const char * type) +{ + overshift_t ret; + volatile unsigned int x=15; + unsigned int limit = sizeof(x)*8; + + volatile unsigned int result; + result = x << y; // Potential overshift + + if (result ==0) + { + printf("%s : Overshift to zero\n", type); + ret = TO_ZERO; + } + else if (result == ( x << (y % limit)) ) + { + printf("%s : Bitmasked overshift\n", type); + ret = MASKED; + } + else + { + printf("%s : Unrecognised behaviour.\n", type); + ret = UNKNOWN; + } + + return ret; +} + +int main(int argc, char** argv) +{ + // Concrete overshift + volatile unsigned int y = sizeof(unsigned int)*8; + overshift_t conc = overshift(y, "Concrete"); + assert( conc == TO_ZERO); + + // Symbolic overshift + volatile unsigned int y2; + klee_make_symbolic(&y2,sizeof(y),"y2"); + // Add constraints so only one value possible + klee_assume(y2 > (y-1)); + klee_assume(y2 < (y+1)); + overshift_t sym = overshift(y2, "Symbolic"); + assert( sym == TO_ZERO); + + // Concrete and symbolic behaviour should be the same + assert( conc == sym); + + return 0; +} diff --git a/test/Feature/logical-right-overshift-sym-conc.c b/test/Feature/logical-right-overshift-sym-conc.c new file mode 100644 index 00000000..00281ec4 --- /dev/null +++ b/test/Feature/logical-right-overshift-sym-conc.c @@ -0,0 +1,65 @@ +// RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee -use-cex-cache=1 -check-overshift=0 %t.bc +// RUN: not grep "ASSERTION FAIL" %T/klee-last/messages.txt +// RUN: grep "KLEE: done: explored paths = 1" %T/klee-last/info +#include <stdio.h> +#include <assert.h> + +typedef enum +{ + TO_ZERO, + MASKED, + UNKNOWN +} overshift_t; + +// We're using unsigned ints so should be doing +// logical right shift. +int overshift(volatile unsigned int y, const char * type) +{ + overshift_t ret; + volatile unsigned int x=15; + unsigned int limit = sizeof(x)*8; + + volatile unsigned int result; + result = x >> y; // Potential overshift + + if (result ==0) + { + printf("%s : Overshift to zero\n", type); + ret = TO_ZERO; + } + else if (result == ( x >> (y % limit)) ) + { + printf("%s : Bitmasked overshift\n", type); + ret = MASKED; + } + else + { + printf("%s : Unrecognised behaviour.\n", type); + ret = UNKNOWN; + } + + return ret; +} + +int main(int argc, char** argv) +{ + // Concrete overshift + volatile unsigned int y = sizeof(unsigned int)*8; + overshift_t conc = overshift(y, "Concrete"); + assert( conc == TO_ZERO); + + // Symbolic overshift + volatile unsigned int y2; + klee_make_symbolic(&y2,sizeof(y),"y2"); + // Add constraints so only one value possible + klee_assume(y2 > (y-1)); + klee_assume(y2 < (y+1)); + overshift_t sym = overshift(y2, "Symbolic"); + assert( sym == TO_ZERO); + + // Concrete and symbolic behaviour should be the same + assert( conc == sym); + + return 0; +} diff --git a/test/Makefile b/test/Makefile index 75e05dda..61a91800 100644 --- a/test/Makefile +++ b/test/Makefile @@ -11,7 +11,7 @@ LEVEL = .. DIRS = # -# Make Dejagnu the default for testing +# Make llvm-lit the default for testing # all:: check-local @@ -19,12 +19,12 @@ all:: check-local include Makefile.tests #===------------------------------------------------------------------------===# -# DejaGNU testing support +# llvm-lit testing support #===------------------------------------------------------------------------===# +ULIMIT = ulimit -t 600 ; ulimit -d 512000 ; # FIXME: Fix test suite so we can run lit in parallel. ifdef VERBOSE -RUNTESTFLAGS := $(VERBOSE) LIT_ARGS := -j1 -v else LIT_ARGS := -j1 -s -v @@ -32,50 +32,27 @@ endif ifdef TESTSUITE LIT_TESTSUITE := $(TESTSUITE) -CLEANED_TESTSUITE := $(patsubst %/,%,$(TESTSUITE)) -CLEANED_TESTSUITE := $(patsubst test/%,%,$(CLEANED_TESTSUITE)) -RUNTESTFLAGS := --tool $(CLEANED_TESTSUITE) else LIT_TESTSUITE := . endif -ifneq ($(RUNTEST),) -check-local:: site.exp - ( ulimit -t 600 ; ulimit -d 512000 ; \ - PATH="$(ToolDir):$(LLVMToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$(PATH)" \ - $(RUNTEST) $(RUNTESTFLAGS) ; \ - ! grep FAIL testrun.log; ! grep -q ^FAIL testrun.log; ) -else -check-local:: site.exp - @echo "*** dejagnu not found. Make sure runtest is in your PATH, then reconfigure llvm." +# Older LLVM versions don't detect python at configure time +# so guess the location +ifndef PYTHON + # llvm-lit doesn't work with python3 so force python2 + PYTHON := python2 endif -check-local-lit:: lit.site.cfg - ( $(ULIMIT) \ - $(LLVM_SRC_ROOT)/utils/lit/lit.py $(LIT_ARGS) $(LIT_TESTSUITE) ) +# Potential support in the future for multiple test suites +LIT_ALL_TESTSUITES := $(LIT_TESTSUITE) -check-local-all:: lit.site.cfg - ( $(ULIMIT) \ - $(LLVM_SRC_ROOT)/utils/lit/lit.py $(LIT_ARGS) $(LIT_TESTSUITE) ) +check-local:: lit.site.cfg + $(Verb) ( $(ULIMIT) \ + $(PYTHON) $(LLVM_SRC_ROOT)/utils/lit/lit.py $(LIT_ARGS) $(LIT_TESTSUITE) ) -ifdef TESTONE -CLEANED_TESTONE := $(patsubst %/,%,$(TESTONE)) -CLEANED_TESTONE := $(patsubst test/%,%,$(CLEANED_TESTONE)) -SUBDIR := $(shell dirname $(CLEANED_TESTONE)) -TESTPATH := $(PROJ_SRC_ROOT)/test/$(CLEANED_TESTONE) -check-one: site.exp $(TCLSH) - $(Verb)( echo "source $(PROJ_OBJ_ROOT)/test/site.exp" ; \ - echo "set subdir $(SUBDIR)" ; \ - echo "proc pass { msg } { puts \"PASS: \$$msg\" } "; \ - echo "proc fail { msg } { puts \"FAIL: \$$msg\" }" ; \ - echo "proc xfail { msg } { puts \"XFAIL: \$$msg\" }" ; \ - echo "proc xpass { msg } { puts \"XPASS: \$$msg\" }" ; \ - echo "source $(PROJ_SRC_ROOT)/test/lib/llvm.exp" ; \ - echo "RunLLVMTests $(TESTPATH)" ) | \ - ( ulimit -t 600 ; ulimit -d 512000 ; \ - PATH="$(ToolDir):$(LLVMToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$(PATH)" \ - $(TCLSH) ) -endif +check-local-all:: lit.site.cfg + $(Verb) ( $(ULIMIT) \ + $(PYTHON) $(LLVM_SRC_ROOT)/utils/lit/lit.py $(LIT_ARGS) $(LIT_ALL_TESTSUITES) ) clean:: $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name Output -type d -print` @@ -87,31 +64,17 @@ clean:: $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name test.log` rm -f site.exp -site.exp: Makefile $(LEVEL)/Makefile.config - @echo 'Making a new site.exp file...' - @echo '## these variables are automatically generated by make ##' >site.tmp - @echo '# Do not edit here. If you wish to override these values' >>site.tmp - @echo '# edit the last section' >>site.tmp - @echo 'set target_triplet "$(TARGET_TRIPLE)"' >> site.tmp - @echo 'set ENABLE_UCLIBC "$(ENABLE_UCLIBC)"' >> site.tmp - @echo 'set ENABLE_POSIX_RUNTIME "$(ENABLE_POSIX_RUNTIME)"' >> site.tmp - @echo 'set TEST_FEATURE_LIST "$(TEST_FEATURE_LIST)"' >> site.tmp - @echo 'set srcroot "$(PROJ_SRC_ROOT)"' >>site.tmp - @echo 'set objroot "$(PROJ_OBJ_ROOT)"' >>site.tmp - @echo 'set srcdir "$(PROJ_SRC_ROOT)/test"' >>site.tmp - @echo 'set objdir "$(PROJ_OBJ_ROOT)/test"' >>site.tmp - @echo 'set llvmgcc "$(LLVMCC) -I$(PROJ_SRC_ROOT)/include"' >> site.tmp - @echo 'set llvmgxx "$(LLVMCXX) -I$(PROJ_SRC_ROOT)/include"' >> site.tmp - @echo '## All variables above are generated by configure. Do Not Edit ## ' >>site.tmp - @test ! -f site.exp || \ - sed '1,/^## All variables above are.*##/ d' site.exp >> site.tmp - @-rm -f site.bak - @test ! -f site.exp || mv site.exp site.bak - @mv site.tmp site.exp - -lit.site.cfg: site.exp +lit.site.cfg: lit.site.cfg.in @echo "Making KLEE 'lit.site.cfg' file..." @sed -e "s#@KLEE_SOURCE_DIR@#$(PROJ_SRC_ROOT)#g" \ -e "s#@KLEE_BINARY_DIR@#$(PROJ_OBJ_ROOT)#g" \ -e "s#@KLEE_TOOLS_DIR@#$(ToolDir)#g" \ + -e "s#@LLVM_TOOLS_DIR@#$(LLVMToolDir)#g" \ + -e "s#@LLVM_VERSION_MAJOR@#$(LLVM_VERSION_MAJOR)#g" \ + -e "s#@LLVMCC@#$(KLEE_BITCODE_C_COMPILER) -I$(PROJ_SRC_ROOT)/include#g" \ + -e "s#@LLVMCXX@#$(KLEE_BITCODE_CXX_COMPILER) -I$(PROJ_SRC_ROOT)/include#g" \ + -e "s#@ENABLE_UCLIBC@#$(ENABLE_UCLIBC)#g" \ + -e "s#@ENABLE_POSIX_RUNTIME@#$(ENABLE_POSIX_RUNTIME)#g" \ + -e "s#@TARGET_TRIPLE@#$(TARGET_TRIPLE)#g" \ + -e "s#@HAVE_SELINUX@#$(HAVE_SELINUX)#g" \ $(PROJ_SRC_DIR)/lit.site.cfg.in > $@ diff --git a/test/Programs/dg.exp b/test/Programs/dg.exp deleted file mode 100644 index 879685ca..00000000 --- a/test/Programs/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Runtime/POSIX/FD_Fail2.c b/test/Runtime/POSIX/FD_Fail2.c index b42e03bf..624329fc 100644 --- a/test/Runtime/POSIX/FD_Fail2.c +++ b/test/Runtime/POSIX/FD_Fail2.c @@ -1,12 +1,12 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee --libc=uclibc --posix-runtime --search=dfs %t1.bc --sym-files 1 10 --max-fail 1 -// RUN: test -f klee-last/test000001.ktest -// RUN: test -f klee-last/test000002.ktest -// RUN: test -f klee-last/test000003.ktest -// RUN: test -f klee-last/test000004.ktest -// RUN: test -f klee-last/test000005.ktest -// RUN: test -f klee-last/test000006.ktest -// RUN: test -f klee-last/test000007.ktest +// RUN: test -f %T/klee-last/test000001.ktest +// RUN: test -f %T/klee-last/test000002.ktest +// RUN: test -f %T/klee-last/test000003.ktest +// RUN: test -f %T/klee-last/test000004.ktest +// RUN: test -f %T/klee-last/test000005.ktest +// RUN: test -f %T/klee-last/test000006.ktest +// RUN: test -f %T/klee-last/test000007.ktest #include <stdio.h> #include <assert.h> diff --git a/test/Runtime/POSIX/FilePerm.c b/test/Runtime/POSIX/FilePerm.c index d387c2a9..1346c09a 100644 --- a/test/Runtime/POSIX/FilePerm.c +++ b/test/Runtime/POSIX/FilePerm.c @@ -1,8 +1,8 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc // RUN: %klee --posix-runtime %t.bc --sym-files 1 10 --sym-stdout 2>%t.log -// RUN: test -f klee-last/test000001.ktest -// RUN: test -f klee-last/test000002.ktest -// RUN: test -f klee-last/test000003.ktest +// RUN: test -f %T/klee-last/test000001.ktest +// RUN: test -f %T/klee-last/test000002.ktest +// RUN: test -f %T/klee-last/test000003.ktest #include <stdio.h> #include <sys/types.h> diff --git a/test/Runtime/POSIX/FreeArgv.c b/test/Runtime/POSIX/FreeArgv.c index ceec4de2..4d2e5b75 100644 --- a/test/Runtime/POSIX/FreeArgv.c +++ b/test/Runtime/POSIX/FreeArgv.c @@ -1,18 +1,22 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc -// RUN: %klee --posix-runtime %t.bc --sym-args 1 1 1 -// RUN: test -f klee-last/test000001.free.err -// RUN: test -f klee-last/test000002.free.err -// RUN: test -f klee-last/test000003.free.err +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --posix-runtime %t.bc --sym-args 1 1 1 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.free.err +// RUN: test -f %T/klee-last/test000002.free.err +// RUN: test -f %T/klee-last/test000003.free.err int main(int argc, char **argv) { + // FIXME: Use FileCheck's CHECK-DAG to check source locations switch(klee_range(0, 3, "range")) { case 0: + // CHECK: free of global free(argv); break; case 1: + // CHECK: free of global free(argv[0]); break; case 2: + // CHECK: free of global free(argv[1]); break; } diff --git a/test/Runtime/POSIX/Isatty.c b/test/Runtime/POSIX/Isatty.c index 293ee653..3054aadb 100644 --- a/test/Runtime/POSIX/Isatty.c +++ b/test/Runtime/POSIX/Isatty.c @@ -1,30 +1,35 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc -// RUN: %klee --libc=uclibc --posix-runtime %t.bc --sym-files 0 10 --sym-stdout 2>%t.log -// RUN: test -f klee-last/test000001.ktest -// RUN: test -f klee-last/test000002.ktest -// RUN: test -f klee-last/test000003.ktest -// RUN: test -f klee-last/test000004.ktest +// RUN: %klee --libc=uclibc --posix-runtime %t.bc --sym-files 0 10 --sym-stdout > %t.log 2>&1 +// RUN: test -f %T/klee-last/test000001.ktest +// RUN: test -f %T/klee-last/test000002.ktest +// RUN: test -f %T/klee-last/test000003.ktest +// RUN: test -f %T/klee-last/test000004.ktest // RUN: grep -q "stdin is a tty" %t.log // RUN: grep -q "stdin is NOT a tty" %t.log // RUN: grep -q "stdout is a tty" %t.log // RUN: grep -q "stdout is NOT a tty" %t.log // Depending on how uClibc is compiled (i.e. without -DKLEE_SYM_PRINTF) -// fprintf prints out on stdout even stderr is provided. +// fprintf prints out on stdout even if stderr is provided. #include <unistd.h> #include <stdio.h> #include <assert.h> +// FIXME: Use new FileCheck to check klee's output int main(int argc, char** argv) { int fd0 = 0; // stdin int fd1 = 1; // stdout int r = isatty(fd0); + // CHECK-DAG: stdin is a tty + // CHECK-DAG: stdin is NOT a tty if (r) fprintf(stderr, "stdin is a tty\n"); else fprintf(stderr, "stdin is NOT a tty\n"); r = isatty(fd1); + // CHECK-DAG: stdout is a tty + // CHECK-DAG: stdout is NOT a tty if (r) fprintf(stderr, "stdout is a tty\n"); else fprintf(stderr, "stdout is NOT a tty\n"); diff --git a/test/Runtime/POSIX/Openat.c b/test/Runtime/POSIX/Openat.c index d417ee47..3c17f976 100644 --- a/test/Runtime/POSIX/Openat.c +++ b/test/Runtime/POSIX/Openat.c @@ -1,6 +1,6 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc // RUN: %klee --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 -// RUN: test -f klee-last/test000001.ktest +// RUN: test -f %T/klee-last/test000001.ktest #include <assert.h> #include <fcntl.h> diff --git a/test/Runtime/POSIX/PrgName.c b/test/Runtime/POSIX/PrgName.c index dc6a4b8c..6bc682ca 100644 --- a/test/Runtime/POSIX/PrgName.c +++ b/test/Runtime/POSIX/PrgName.c @@ -1,7 +1,7 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc // RUN: %klee --posix-runtime --exit-on-error %t2.bc --sym-arg 10 >%t.log -// RUN: test -f klee-last/test000001.ktest -// RUN: test -f klee-last/test000002.ktest +// RUN: test -f %T/klee-last/test000001.ktest +// RUN: test -f %T/klee-last/test000002.ktest // RUN: grep -q "No" %t.log // RUN: grep -qv "Yes" %t.log diff --git a/test/Runtime/POSIX/SELinux.c b/test/Runtime/POSIX/SELinux/SELinux.c index 65dd1a7f..65dd1a7f 100644 --- a/test/Runtime/POSIX/SELinux.c +++ b/test/Runtime/POSIX/SELinux/SELinux.c diff --git a/test/Runtime/POSIX/SELinux/lit.local.cfg b/test/Runtime/POSIX/SELinux/lit.local.cfg new file mode 100644 index 00000000..2046d4d0 --- /dev/null +++ b/test/Runtime/POSIX/SELinux/lit.local.cfg @@ -0,0 +1,7 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +if not getRoot(config).have_selinux: + config.unsupported = True diff --git a/test/Runtime/POSIX/SeedAndFail.c b/test/Runtime/POSIX/SeedAndFail.c index 740db664..d9bd7f8d 100644 --- a/test/Runtime/POSIX/SeedAndFail.c +++ b/test/Runtime/POSIX/SeedAndFail.c @@ -1,8 +1,8 @@ // RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t.bc -// RUN: rm -rf tmp-123 -// RUN: %klee --libc=uclibc --output-dir=tmp-123 --posix-runtime %t.bc --sym-files 1 10 2>%t.log -// RUN: %klee --seed-out-dir=tmp-123 --zero-seed-extension --libc=uclibc --posix-runtime %t.bc --sym-files 1 10 --max-fail 1 -// RUN: ls klee-last | grep -c assert | grep 4 +// RUN: rm -rf %T/tmp-123 +// RUN: %klee --libc=uclibc --output-dir=%T/tmp-123 --posix-runtime %t.bc --sym-files 1 10 2>%t.log +// RUN: %klee --seed-out-dir=%T/tmp-123 --zero-seed-extension --libc=uclibc --posix-runtime %t.bc --sym-files 1 10 --max-fail 1 +// RUN: ls %T/klee-last | grep -c assert | grep 4 #include <string.h> #include <assert.h> diff --git a/test/Runtime/POSIX/dg.exp b/test/Runtime/POSIX/dg.exp deleted file mode 100644 index 88406208..00000000 --- a/test/Runtime/POSIX/dg.exp +++ /dev/null @@ -1,5 +0,0 @@ -load_lib llvm.exp - -if { [klee_supports_posix_runtime] } { - RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] -} diff --git a/test/Runtime/POSIX/lit.local.cfg b/test/Runtime/POSIX/lit.local.cfg new file mode 100644 index 00000000..680351b7 --- /dev/null +++ b/test/Runtime/POSIX/lit.local.cfg @@ -0,0 +1,7 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +if not getRoot(config).enable_posix_runtime: + config.unsupported = True diff --git a/test/Runtime/Uclibc/dg.exp b/test/Runtime/Uclibc/dg.exp deleted file mode 100644 index 9c1663c3..00000000 --- a/test/Runtime/Uclibc/dg.exp +++ /dev/null @@ -1,5 +0,0 @@ -load_lib llvm.exp - -if { [klee_supports_uclibc] } { - RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] -} diff --git a/test/Runtime/Uclibc/lit.local.cfg b/test/Runtime/Uclibc/lit.local.cfg new file mode 100644 index 00000000..c9944834 --- /dev/null +++ b/test/Runtime/Uclibc/lit.local.cfg @@ -0,0 +1,7 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +if not getRoot(config).enable_uclibc: + config.unsupported = True diff --git a/test/Solver/LargeIntegers.pc b/test/Solver/LargeIntegers.pc index 53ff3a51..e0921393 100644 --- a/test/Solver/LargeIntegers.pc +++ b/test/Solver/LargeIntegers.pc @@ -2,16 +2,16 @@ array a[64] : w32 -> w8 = symbolic -# RUN: grep -A 1 \"Query 0\" %t > %t2 -# RUN: grep \"Expr 0:\t18446744073709551618\" %t2 +# RUN: grep -A 1 "Query 0" %t > %t2 +# RUN: grep "Expr 0: 18446744073709551618" %t2 (query [] false [(Concat w128 (w64 1) (w64 2))]) -# RUN: grep -A 1 \"Query 1\" %t > %t2 -# RUN: grep \"Expr 0:\t16\" %t2 +# RUN: grep -A 1 "Query 1" %t > %t2 +# RUN: grep "Expr 0: 16" %t2 (query [] false [(Extract w5 60 (Concat w128 (w64 1) (w64 2)))]) -# RUN: grep -A 1 \"Query 2\" %t > %t2 -# RUN: grep \"Array 0:\ta.16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1\" %t2 +# RUN: grep -A 1 "Query 2" %t > %t2 +# RUN: grep "Array 0: a.16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1" %t2 (query [(Eq 0x0102030405060708090A0B0C0D0E0F10 (ReadLSB w128 0 a))] false [] [a]) diff --git a/test/Solver/dg.exp b/test/Solver/dg.exp deleted file mode 100644 index 94fc4df8..00000000 --- a/test/Solver/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{pc}]] diff --git a/test/Solver/lit.local.cfg b/test/Solver/lit.local.cfg new file mode 100644 index 00000000..d64daf29 --- /dev/null +++ b/test/Solver/lit.local.cfg @@ -0,0 +1,2 @@ +# Look for .kquery files too +config.suffixes.add('.kquery') diff --git a/test/Solver/overshift-aright-by-constant.kquery b/test/Solver/overshift-aright-by-constant.kquery new file mode 100644 index 00000000..c21889e2 --- /dev/null +++ b/test/Solver/overshift-aright-by-constant.kquery @@ -0,0 +1,14 @@ +# RUN: %kleaver %s > %t +# RUN: not grep INVALID %t +array x[4] : w32 -> w8 = symbolic +# ∀ x. x > 0 → ( ((signed int) x) >> 32 = 0 ) +# Check we overshift to zero for when shifting for all 32-bit values >0 + +(query [ (Ult (w32 0) (ReadLSB w32 (w32 0) x)) ] + (Eq + (AShr w32 + (ReadLSB w32 (w32 0) x) + (w32 32) + ) + (w32 0) + ) [ ] [x] ) diff --git a/test/Solver/overshift-aright-by-symbolic.kquery b/test/Solver/overshift-aright-by-symbolic.kquery new file mode 100644 index 00000000..af563ea3 --- /dev/null +++ b/test/Solver/overshift-aright-by-symbolic.kquery @@ -0,0 +1,26 @@ +# RUN: %kleaver %s > %t +# RUN: not grep INVALID %t + +array shift[4] : w32 -> w8 = symbolic +# ∀ x. x >= 32 → ( ( ( (signed int)2 ) >> x) = 0 ) +# Check we arithmetic right overshift to zero when shifting a constant ALWAYS! + +(query [ (Ule (w32 32) (ReadLSB w32 (w32 0) shift)) ] + (Eq + (AShr w32 (w32 2) + (ReadLSB w32 (w32 0) shift) + ) + (w32 0) + ) [ ] [shift] ) + +# 64-bit version +# ∀ x. x >= 64 → ( (((signed int) 2) >> x) = 0 ) +array shift64[8] : w32 -> w8 = symbolic + +(query [ (Ule (w64 64) (ReadLSB w64 (w32 0) shift64)) ] + (Eq + (AShr w64 (w64 2) + (ReadLSB w64 (w32 0) shift64) + ) + (w64 0) + ) [ ] [shift64] ) diff --git a/test/Solver/overshift-left-by-constant.kquery b/test/Solver/overshift-left-by-constant.kquery new file mode 100644 index 00000000..e0709100 --- /dev/null +++ b/test/Solver/overshift-left-by-constant.kquery @@ -0,0 +1,14 @@ +# RUN: %kleaver %s > %t +# RUN: not grep INVALID %t +array x[4] : w32 -> w8 = symbolic +# ∀ x. x > 0 → ( x << 32 = 0 ) +# Check we overshift to zero for when shifting for all 32-bit values >0 + +(query [ (Ult (w32 0) (ReadLSB w32 (w32 0) x)) ] + (Eq + (Shl w32 + (ReadLSB w32 (w32 0) x) + (w32 32) + ) + (w32 0) + ) [ ] [x] ) diff --git a/test/Solver/overshift-left-by-symbolic.kquery b/test/Solver/overshift-left-by-symbolic.kquery new file mode 100644 index 00000000..9d0d272c --- /dev/null +++ b/test/Solver/overshift-left-by-symbolic.kquery @@ -0,0 +1,26 @@ +# RUN: %kleaver %s > %t +# RUN: not grep INVALID %t + +array shift[4] : w32 -> w8 = symbolic +# ∀ x. x >= 32 → ( (2 << x) = 0 ) +# Check we left overshift to zero when shifting a constant ALWAYS! + +(query [ (Ule (w32 32) (ReadLSB w32 (w32 0) shift)) ] + (Eq + (Shl w32 (w32 2) + (ReadLSB w32 (w32 0) shift) + ) + (w32 0) + ) [ ] [shift] ) + +# 64-bit version +# ∀ x. x >= 64 → ( (2 << x) = 0 ) +array shift64[8] : w32 -> w8 = symbolic + +(query [ (Ule (w64 64) (ReadLSB w64 (w32 0) shift64)) ] + (Eq + (Shl w64 (w64 2) + (ReadLSB w64 (w32 0) shift64) + ) + (w64 0) + ) [ ] [shift64] ) diff --git a/test/Solver/overshift-lright-by-constant.kquery b/test/Solver/overshift-lright-by-constant.kquery new file mode 100644 index 00000000..cb223dd5 --- /dev/null +++ b/test/Solver/overshift-lright-by-constant.kquery @@ -0,0 +1,14 @@ +# RUN: %kleaver %s > %t +# RUN: not grep INVALID %t +array x[4] : w32 -> w8 = symbolic +# ∀ x. x > 0 → ( x >> 32 = 0 ) +# Check we overshift to zero for when shifting for all 32-bit values >0 + +(query [ (Ult (w32 0) (ReadLSB w32 (w32 0) x)) ] + (Eq + (LShr w32 + (ReadLSB w32 (w32 0) x) + (w32 32) + ) + (w32 0) + ) [ ] [x] ) diff --git a/test/Solver/overshift-lright-by-symbolic.kquery b/test/Solver/overshift-lright-by-symbolic.kquery new file mode 100644 index 00000000..7ca6d4d5 --- /dev/null +++ b/test/Solver/overshift-lright-by-symbolic.kquery @@ -0,0 +1,26 @@ +# RUN: %kleaver %s > %t +# RUN: not grep INVALID %t + +array shift[4] : w32 -> w8 = symbolic +# ∀ x. x >= 32 → ( (2 >> x) = 0 ) +# Check we logical right overshift to zero when shifting a constant ALWAYS! + +(query [ (Ule (w32 32) (ReadLSB w32 (w32 0) shift)) ] + (Eq + (LShr w32 (w32 2) + (ReadLSB w32 (w32 0) shift) + ) + (w32 0) + ) [ ] [shift] ) + +# 64-bit version +# ∀ x. x >= 64 → ( (2 >> x) = 0 ) +array shift64[8] : w32 -> w8 = symbolic + +(query [ (Ule (w64 64) (ReadLSB w64 (w32 0) shift64)) ] + (Eq + (LShr w64 (w64 2) + (ReadLSB w64 (w32 0) shift64) + ) + (w64 0) + ) [ ] [shift64] ) diff --git a/test/TestRunner.sh b/test/TestRunner.sh index 3e2cace4..3a69604b 100755 --- a/test/TestRunner.sh +++ b/test/TestRunner.sh @@ -1,36 +1,6 @@ #!/bin/sh -# -# TestRunner.sh - This script is used to run the deja-gnu tests exactly like -# deja-gnu does, by executing the Tcl script specified in the test case's -# RUN: lines. This is made possible by a simple make target supported by the -# test/Makefile. All this script does is invoke that make target. -# -# Usage: -# TestRunner.sh {script_names} -# -# This script is typically used by cd'ing to a test directory and then -# running TestRunner.sh with a list of test file names you want to run. -# -TESTPATH=`pwd` -SUBDIR="" -if test `dirname $1` = "." ; then - while test `basename $TESTPATH` != "test" -a ! -z "$TESTPATH" ; do - tmp=`basename $TESTPATH` - SUBDIR="$tmp/$SUBDIR" - TESTPATH=`dirname $TESTPATH` - done -fi +# Deprecated, use 'llvm-lit'. -for TESTFILE in "$@" ; do - if test `dirname $TESTFILE` = . ; then - if test -d "$TESTPATH" ; then - cd $TESTPATH - make check-one TESTONE="$SUBDIR$TESTFILE" - cd $PWD - else - echo "Can't find klee/test directory in " `pwd` - fi - else - make check-one TESTONE=$TESTFILE - fi -done +echo "warning: '$0' is deprecated, use 'llvm-lit' instead." +# FIXME: Make test suite work in parallel. +exec llvm-lit --threads=1 "$@" diff --git a/test/lib/llvm.exp b/test/lib/llvm.exp deleted file mode 100644 index ce52c4b5..00000000 --- a/test/lib/llvm.exp +++ /dev/null @@ -1,199 +0,0 @@ -# This procedure executes one line of a test case's execution script. -proc execOneLine { test PRS outcome lineno line } { - set status 0 - set resultmsg "" - set retval [ catch { eval exec -keepnewline -- $line } errmsg ] - if { $retval != 0 } { - set code [lindex $::errorCode 0] - set lineno [expr $lineno + 1] - if { $PRS != ""} { - set PRS " for $PRS" - } - set errmsg " at line $lineno\nwhile running: $line\n$errmsg" - switch "$code" { - CHILDSTATUS { - set status [lindex $::errorCode 2] - if { $status != 0 } { - set resultmsg "$test$PRS\nFailed with exit($status)$errmsg" - } - } - CHILDKILLED { - set signal [lindex $::errorCode 2] - set resultmsg "$test$PRS\nFailed with signal($signal)$errmsg" - } - CHILDSUSP { - set signal [lindex $::errorCode 2] - set resultmsg "$test$PRS\nFailed with suspend($signal)$errmsg" - } - POSIX { - set posixNum [lindex $::errorCode 1] - set posixMsg [lindex $::errorCode 2] - set resultmsg "$test$PRS\nFailed with posix($posixNum,$posixMsg)$errmsg" - } - NONE { - } - default { - } - } - } - return $resultmsg -} - -# This procedure performs variable substitutions on the RUN: lines of a test -# cases. -proc substitute { line test tmpFile } { - global srcroot objroot srcdir objdir subdir target_triplet - global llvmgcc llvmgxx llvmgcc_version - set path [file join $srcdir $subdir] - - # Substitute all Tcl variables. - set new_line [subst $line ] - - #replace %llvmgcc with actual path to llvmgcc - regsub -all {%llvmgcc} $new_line "$llvmgcc -emit-llvm" new_line - #replace %llvmgxx with actual path to llvmg++ - regsub -all {%llvmgxx} $new_line "$llvmgxx -emit-llvm" new_line - #replace %klee with klee binary - regsub -all {%klee} $new_line "klee" new_line - #replace %kleaver with kleaver binary - regsub -all {%kleaver} $new_line "kleaver" new_line - #replace %p with path to source, - regsub -all {%p} $new_line [file join $srcdir $subdir] new_line - #replace %s with filename - regsub -all {%s} $new_line $test new_line - #replace %t with temp filenames - regsub -all {%t} $new_line $tmpFile new_line - #replace %% with % - regsub -all {%%} $new_line % new_line - return $new_line -} - -# This procedure runs the set of tests for the test_source_files array. -proc RunLLVMTests { test_source_files } { - global srcroot objroot srcdir objdir subdir TEST_FEATURE_LIST target_triplet - set timeout 60 - - set path [file join $objdir $subdir] - - #Make Output Directory if it does not exist already - if { [file exists path] } { - cd $path - } else { - file mkdir $path - cd $path - } - - file mkdir Output - cd Output - - foreach test $test_source_files { - #Should figure out best way to set the timeout - #set timeout 40 - - set filename [file tail $test] - set outcome PASS - set tmpFile "$filename.tmp" - - #set hasRunline bool to check if testcase has a runline - set numLines 0 - - # Open the test file and start reading lines - set testFileId [ open $test r] - set runline "" - set PRNUMS "" - foreach line [split [read $testFileId] \n] { - - # if its the END. line then stop parsing (optimization for big files) - if {[regexp {END.[ *]$} $line match endofscript]} { - break - - # if the line is continued, concatenate and continue the loop - } elseif {[regexp {RUN: *(.+)(\\)$} $line match oneline suffix]} { - set runline "$runline$oneline " - - # if its a terminating RUN: line then do substitution on the whole line - # and then save the line. - } elseif {[regexp {RUN: *([^&]+)(&&)?} $line match oneline suffix]} { - set runline "$runline$oneline" - set runline [ substitute $runline $test $tmpFile ] - set lines($numLines) $runline - set numLines [expr $numLines + 1] - set runline "" - - # if its an PR line, save the problem report number - } elseif {[regexp {PR([0-9]+)} $line match prnum]} { - if {$PRNUMS == ""} { - set PRNUMS "PR$prnum" - } else { - set PRNUMS "$PRNUMS,$prnum" - } - # if its an XFAIL line, see if we should be XFAILing or not. - } elseif {[regexp {XFAIL:[ *](.+)} $line match features]} { - set features - - foreach feature [split $features ,] { - if { [regexp {\*} $feature match] } { - set outcome XFAIL - } elseif { [regexp $feature $target_triplet match] } { - set outcome XFAIL - } elseif { [regexp $feature $TEST_FEATURE_LIST match] } { - set outcome XFAIL - } - } - } - } - - # Done reading the script - close $testFileId - - - if { $numLines == 0 } { - fail "$test: \nDoes not have a RUN line\n" - } else { - set failed 0 - for { set i 0 } { $i < $numLines } { set i [ expr $i + 1 ] } { - regsub ^.*RUN:(.*) $lines($i) \1 theLine - set resultmsg [execOneLine $test $PRNUMS $outcome $i $theLine ] - if { $resultmsg != "" } { - if { $outcome == "XFAIL" } { - xfail "$resultmsg" - } else { - fail "$resultmsg" - } - set failed 1 - break - } - } - if { $failed } { - continue - } else { - if { $PRNUMS != "" } { - set PRNUMS " for $PRNUMS" - } - if { $outcome == "XFAIL" } { - xpass "$test$PRNUMS" - } else { - pass "$test$PRNUMS" - } - } - } - } -} - -# Check if klee was configured with POSIX runtime support. -proc klee_supports_posix_runtime { } { - global ENABLE_POSIX_RUNTIME - if { $ENABLE_POSIX_RUNTIME == "1" } { - return 1 - } - return 0 -} - -# Check if klee was configured with uclibc support. -proc klee_supports_uclibc { } { - global ENABLE_UCLIBC - if { $ENABLE_UCLIBC == "1" } { - return 1 - } - return 0 -} diff --git a/test/lit.cfg b/test/lit.cfg index 39aaa824..3d00da53 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -3,16 +3,25 @@ # Configuration file for the 'lit' test runner. import os +import sys +import re +import platform + +try: + import lit.util + import lit.formats +except ImportError: + pass # name: The name of this test suite. config.name = 'KLEE' # testFormat: The test format to use to interpret tests. -config.test_format = lit.formats.TclTest() +config.test_format = lit.formats.ShTest(execute_external=False) -# suffixes: A list of file extensions to treat as test files, this is actually -# set by on_clone(). -config.suffixes = [] +# suffixes: A list of file extensions to treat as test files +# Note this can be overridden by lit.local.cfg files +config.suffixes = ['.ll', '.c', '.cpp', '.pc'] # test_source_root: The root path where tests are located. config.test_source_root = os.path.dirname(__file__) @@ -27,107 +36,69 @@ if klee_obj_root is not None: klee_tools_dir = getattr(config, 'klee_tools_dir', None) if not klee_tools_dir: lit.fatal('No KLEE tools dir set!') - path = os.path.pathsep.join((klee_tools_dir, config.environment['PATH'])) + + # Check LLVM tool directory + llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) + if not llvm_tools_dir: + lit.fatal('No LLVM tool directory set!') + + path = os.path.pathsep.join((llvm_tools_dir, klee_tools_dir, config.environment['PATH'] )) config.environment['PATH'] = path -# Propogate 'HOME' through the environment. -config.environment['HOME'] = os.environ['HOME'] -### +# Propogate some environment variable to test environment. +def addEnv(name): + if name in os.environ: + config.environment[name] = os.environ[name] -import os +addEnv('HOME') +addEnv('PWD') + +# llvm-gcc on Ubuntu needs to be told where to look +# for headers. If user has these in their environment +# we should propagate to test environment +addEnv('C_INCLUDE_PATH') +addEnv('CPLUS_INCLUDE_PATH') # Check that the object root is known. if config.test_exec_root is None: lit.fatal('test execution root not set!') -### -# Load site data from DejaGNU's site.exp. -import re -site_exp = {} -# FIXME: Implement lit.site.cfg. -for line in open(os.path.join(config.klee_obj_root, 'test', 'site.exp')): - m = re.match('set ([^ ]+) "([^"]*)"', line) - if m: - site_exp[m.group(1)] = m.group(2) - -# Add substitutions. -config.substitutions.append(('%llvmgcc_only', site_exp['llvmgcc'])) -for sub in ['llvmgcc', 'llvmgxx']: - if sub in ('llvmgcc', 'llvmgxx'): - config.substitutions.append(('%' + sub, - site_exp[sub] + ' -emit-llvm -w')) - # FIXME: This is a hack to avoid LLVMC tests failing due to a clang driver - # warning when passing in "-fexceptions -fno-exceptions". - elif sub == 'compile_cxx': - config.substitutions.append(('%' + sub, - site_exp[sub].replace('-fno-exceptions', ''))) - else: - config.substitutions.append(('%' + sub, site_exp[sub])) - -# FIXME: Give these proper paths. -config.substitutions.append(('%kleaver', 'kleaver')) -config.substitutions.append(('%klee', 'klee')) - -def klee_supports_posix_runtime(): - return int(site_exp['ENABLE_POSIX_RUNTIME']) - -def klee_supports_uclibc(): - return int(site_exp['ENABLE_UCLIBC']) - -excludes = [] - -# Provide target_triple for use in XFAIL and XTARGET. -config.target_triple = site_exp['target_triplet'] - -# Provide on_clone hook for reading 'dg.exp'. -import os -simpleLibData = re.compile(r"""load_lib llvm.exp - -RunLLVMTests \[lsort \[glob -nocomplain \$srcdir/\$subdir/\*\.(.*)\]\]""", - re.MULTILINE) -conditionalLibData = re.compile(r"""load_lib llvm.exp - -if.*\[?(klee[^ ]*)\].*{ - *RunLLVMTests \[lsort \[glob -nocomplain \$srcdir/\$subdir/\*\.(.*)\]\] -\}""", re.MULTILINE) -def on_clone(parent, cfg, for_path): - def addSuffixes(match): - if match[0] == '{' and match[-1] == '}': - cfg.suffixes = ['.' + s for s in match[1:-1].split(',')] - else: - cfg.suffixes = ['.' + match] - - libPath = os.path.join(os.path.dirname(for_path), - 'dg.exp') - if not os.path.exists(libPath): - cfg.unsupported = True - return - - # Reset unsupported, in case we inherited it. - cfg.unsupported = False - lib = open(libPath).read().strip() - - # Check for a simple library. - m = simpleLibData.match(lib) - if m: - addSuffixes(m.group(1)) - return - - # Check for a conditional test set. - m = conditionalLibData.match(lib) - if m: - funcname,match = m.groups() - addSuffixes(match) - - func = globals().get(funcname) - if not func: - lit.error('unsupported predicate %r' % funcname) - elif not func(): - cfg.unsupported = True - return - # Otherwise, give up. - lit.error('unable to understand %r:\n%s' % (libPath, lib)) - -config.on_clone = on_clone +# Add substitutions from lit.site.cfg +subs = [ 'llvmgcc', 'llvmgxx'] +for name in subs: + value = getattr(config, name, None) + if value == None: + lit.fatal('{0} is not set'.format(name)) + config.substitutions.append( ('%' + name, value)) + +# Get KLEE and Kleaver specific parameters passed on llvm-lit cmd line +# e.g. llvm-lit --param klee_opts=--help +try: + lit.params +except AttributeError: + klee_extra_params = lit_config.params.get('klee_opts',"") + kleaver_extra_params = lit_config.params.get('kleaver_opts',"") +else: + klee_extra_params = lit.params.get('klee_opts',"") + kleaver_extra_params = lit.params.get('kleaver_opts',"") + +if len(klee_extra_params) != 0: + print("Passing extra KLEE command line args: {0}".format(klee_extra_params)) +if len(kleaver_extra_params) != 0: + print("Passing extra Kleaver command line args: {0}".format(kleaver_extra_params)) + +# Set absolute paths and extra cmdline args for KLEE's tools +subs = [ ('%kleaver', 'kleaver', kleaver_extra_params), ('%klee','klee', klee_extra_params) ] +for s,basename,extra_args in subs: + config.substitutions.append( ( s, + "{0} {1}".format( os.path.join(klee_tools_dir, basename), extra_args ) + ) + ) + + +# LLVM < 3.0 doesn't Support %T directive +if int(config.llvm_version_major) == 2: + # This is a hack + config.substitutions.append(('%T','Output')) diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index ec92b32d..14ba94e6 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -3,6 +3,30 @@ config.klee_src_root = "@KLEE_SOURCE_DIR@" config.klee_obj_root = "@KLEE_BINARY_DIR@" config.klee_tools_dir = "@KLEE_TOOLS_DIR@" +config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" + +# Needed to check if a hack needs to be applied +config.llvm_version_major = "@LLVM_VERSION_MAJOR@" + +# Compilers +# FIXME: use llvmcc not llvmgcc +config.llvmgcc = "@LLVMCC@" +config.llvmgxx = "@LLVMCXX@" + +# Features +config.enable_uclibc = True if @ENABLE_UCLIBC@ == 1 else False +config.enable_posix_runtime = True if @ENABLE_POSIX_RUNTIME@ == 1 else False +config.have_selinux = True if @HAVE_SELINUX@ == 1 else False + +# Current target +config.target_triple = "@TARGET_TRIPLE@" # Let the main config do the real work. -lit.load_config(config, "@KLEE_SOURCE_DIR@/test/lit.cfg") +try: + lit +except NameError: + # Use lit_config class + lit_config.load_config(config, "@KLEE_SOURCE_DIR@/test/lit.cfg") +else: + # Use old lit class + lit.load_config(config, "@KLEE_SOURCE_DIR@/test/lit.cfg") diff --git a/test/regression/2007-08-01-bool-zext-in-call.ll b/test/regression/2007-08-01-bool-zext-in-call.ll index d10a41ef..fc77785d 100644 --- a/test/regression/2007-08-01-bool-zext-in-call.ll +++ b/test/regression/2007-08-01-bool-zext-in-call.ll @@ -1,5 +1,12 @@ -; RUN: llvm-as -f %s -o - | %klee 2> %t1.log -; RUN: not test -f klee-last/test0001.abort.err +; RUN: rm -rf %T/xxx +; +; The output directory must be explicitly set so that it ends up in the Output/ +; directory which is not scanned for .ll files by llvm-lit, otherwise running +; test suite a second time will cause problems because assembly.ll generated by +; executing this test case the first time will be detected as a test case. +; +; RUN: llvm-as -f %s -o - | %klee --output-dir=%T/xxx +; RUN: not test -f %T/xxx/klee-last/test0001.abort.err declare void @klee_abort() diff --git a/test/regression/2007-08-08-free-zero.c b/test/regression/2007-08-08-free-zero.c index 964889a1..935b04fd 100644 --- a/test/regression/2007-08-08-free-zero.c +++ b/test/regression/2007-08-08-free-zero.c @@ -1,6 +1,8 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee %t1.bc -// RUN: ls klee-last | not grep *.err +// RUN: ls %T/klee-last | not grep *.err + +#include <stdlib.h> int main() { free(0); diff --git a/test/regression/2007-10-11-free-of-alloca.c b/test/regression/2007-10-11-free-of-alloca.c index 71a16f6b..44a9ed4e 100644 --- a/test/regression/2007-10-11-free-of-alloca.c +++ b/test/regression/2007-10-11-free-of-alloca.c @@ -1,9 +1,10 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.free.err +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.free.err int main() { int buf[4]; + // CHECK: 2007-10-11-free-of-alloca.c:8: free of alloca free(buf); // this should give runtime error, not crash return 0; } diff --git a/test/regression/2007-10-11-illegal-access-after-free-and-branch.c b/test/regression/2007-10-11-illegal-access-after-free-and-branch.c index fbbb99c3..73b3ed3f 100644 --- a/test/regression/2007-10-11-illegal-access-after-free-and-branch.c +++ b/test/regression/2007-10-11-illegal-access-after-free-and-branch.c @@ -1,6 +1,6 @@ // RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc -// RUN: %klee --optimize %t1.bc -// RUN: test -f klee-last/test000001.ptr.err +// RUN: %klee --optimize %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.ptr.err #include <stdlib.h> #include <stdio.h> @@ -13,7 +13,10 @@ int main(int argc, char **argv) { unsigned char x = buf[1]; free(buf); if (x) + { + // CHECK: 2007-10-11-illegal-access-after-free-and-branch.c:18: memory error: out of bound pointer return buf[2]; + } klee_silent_exit(0); return 0; } diff --git a/test/regression/2007-10-12-failed-make-symbolic-after-copy.c b/test/regression/2007-10-12-failed-make-symbolic-after-copy.c index e9a280c3..bfe61f2c 100644 --- a/test/regression/2007-10-12-failed-make-symbolic-after-copy.c +++ b/test/regression/2007-10-12-failed-make-symbolic-after-copy.c @@ -1,6 +1,6 @@ // RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc // RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.ktest +// RUN: test -f %T/klee-last/test000001.ktest int main() { unsigned x, y[4]; diff --git a/test/regression/2008-03-04-free-of-global.c b/test/regression/2008-03-04-free-of-global.c index 7821398d..5351128d 100644 --- a/test/regression/2008-03-04-free-of-global.c +++ b/test/regression/2008-03-04-free-of-global.c @@ -1,10 +1,11 @@ -// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc -// RUN: %klee %t1.bc -// RUN: test -f klee-last/test000001.free.err +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc 2>&1 | FileCheck %s +// RUN: test -f %T/klee-last/test000001.free.err int buf[4]; int main() { + // CHECK: 2008-03-04-free-of-global.c:9: free of global free(buf); // this should give runtime error, not crash return 0; } diff --git a/test/regression/2008-05-23-gep-with-global-const.c b/test/regression/2008-05-23-gep-with-global-const.c index 5e03ec1d..3ad9b24e 100644 --- a/test/regression/2008-05-23-gep-with-global-const.c +++ b/test/regression/2008-05-23-gep-with-global-const.c @@ -1,4 +1,4 @@ -// RUN: %llvmgcc -O0 -c -o %t.bc %s +// RUN: %llvmgcc -emit-llvm -O0 -c -o %t.bc %s // RUN: %klee --exit-on-error %t.bc #include <assert.h> diff --git a/test/regression/2014-07-04-unflushed-error-report.c b/test/regression/2014-07-04-unflushed-error-report.c new file mode 100644 index 00000000..63431370 --- /dev/null +++ b/test/regression/2014-07-04-unflushed-error-report.c @@ -0,0 +1,25 @@ +// RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee -check-overshift %t.bc 2> %t.log +// RUN: FileCheck -input-file=%T/klee-last/test000001.overshift.err %s + +/* This test checks that the error file isn't empty and contains the + * right content. + */ +int main() +{ + unsigned int x=15; + unsigned int y; + unsigned int z; + volatile unsigned int result; + + /* Overshift if y>= sizeof(x) */ + klee_make_symbolic(&y,sizeof(y),"shift_amount1"); + // CHECK: Error: overshift error + // CHECK-NEXT: 2014-07-04-unflushed-error-report.c + // FIXME: Need newer FileCheck for to do ``Line: [[@LINE+1]]`` + // Just hardcode line number for now + // CHECK-NEXT: Line: 22 + result = x << y; + + return 0; +} diff --git a/test/regression/dg.exp b/test/regression/dg.exp deleted file mode 100644 index 879685ca..00000000 --- a/test/regression/dg.exp +++ /dev/null @@ -1,3 +0,0 @@ -load_lib llvm.exp - -RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/tools/kleaver/Makefile b/tools/kleaver/Makefile index b93e361d..656ffeae 100644 --- a/tools/kleaver/Makefile +++ b/tools/kleaver/Makefile @@ -29,5 +29,9 @@ ifeq ($(ENABLE_METASMT),1) -L$(METASMT_ROOT)/../../deps/boost-1_52_0/lib CXX.Flags += -DBOOST_HAS_GCC_TR1 CXX.Flags := $(filter-out -fno-exceptions,$(CXX.Flags)) - LIBS += -lrt -lgomp -lboost_iostreams -lboost_thread -lboost_system -lmetaSMT -lz3 -lboolector -lminisat_core -endif \ No newline at end of file + LIBS += -lgomp -lboost_iostreams -lboost_thread -lboost_system -lmetaSMT -lz3 -lrt -lboolector -lminisat_core +endif + +ifeq ($(STP_NEEDS_BOOST),1) + LIBS += $(UPSTREAM_STP_LINK_FLAGS) +endif diff --git a/tools/kleaver/main.cpp b/tools/kleaver/main.cpp index abc37d4b..b19e2ea6 100644 --- a/tools/kleaver/main.cpp +++ b/tools/kleaver/main.cpp @@ -1,5 +1,3 @@ -#include <iostream> - #include "expr/Lexer.h" #include "expr/Parser.h" @@ -124,9 +122,11 @@ static std::string getQueryLogPath(const char filename[]) struct stat s; if( !(stat(directoryToWriteQueryLogs.c_str(),&s) == 0 && S_ISDIR(s.st_mode)) ) { - std::cerr << "Directory to log queries \"" << directoryToWriteQueryLogs << "\" does not exist!" << std::endl; - exit(1); - } + llvm::errs() << "Directory to log queries \"" + << directoryToWriteQueryLogs << "\" does not exist!" + << "\n"; + exit(1); + } //check permissions okay if( !( (s.st_mode & S_IWUSR) && getuid() == s.st_uid) && @@ -134,9 +134,11 @@ static std::string getQueryLogPath(const char filename[]) !( s.st_mode & S_IWOTH) ) { - std::cerr << "Directory to log queries \"" << directoryToWriteQueryLogs << "\" is not writable!" << std::endl; - exit(1); - } + llvm::errs() << "Directory to log queries \"" + << directoryToWriteQueryLogs << "\" is not writable!" + << "\n"; + exit(1); + } std::string path=directoryToWriteQueryLogs; path+="/"; @@ -167,10 +169,9 @@ static void PrintInputTokens(const MemoryBuffer *MB) { Token T; do { L.Lex(T); - std::cout << "(Token \"" << T.getKindName() << "\" " - << "\"" << escapedString(T.start, T.length) << "\" " - << T.length << " " - << T.line << " " << T.column << ")\n"; + llvm::outs() << "(Token \"" << T.getKindName() << "\" " + << "\"" << escapedString(T.start, T.length) << "\" " + << T.length << " " << T.line << " " << T.column << ")\n"; } while (T.kind != Token::EndOfFile); } @@ -185,7 +186,7 @@ static bool PrintInputAST(const char *Filename, while (Decl *D = P->ParseTopLevelDecl()) { if (!P->GetNumErrors()) { if (isa<QueryCommand>(D)) - std::cout << "# Query " << ++NumQueries << "\n"; + llvm::outs() << "# Query " << ++NumQueries << "\n"; D->dump(); } @@ -194,8 +195,7 @@ static bool PrintInputAST(const char *Filename, bool success = true; if (unsigned N = P->GetNumErrors()) { - std::cerr << Filename << ": parse failure: " - << N << " errors.\n"; + llvm::errs() << Filename << ": parse failure: " << N << " errors.\n"; success = false; } @@ -220,8 +220,7 @@ static bool EvaluateInputAST(const char *Filename, bool success = true; if (unsigned N = P->GetNumErrors()) { - std::cerr << Filename << ": parse failure: " - << N << " errors.\n"; + llvm::errs() << Filename << ": parse failure: " << N << " errors.\n"; success = false; } @@ -253,7 +252,7 @@ static bool EvaluateInputAST(const char *Filename, assert(false); break; }; - std::cerr << "Starting MetaSMTSolver(" << backend << ") ...\n"; + llvm::errs() << "Starting MetaSMTSolver(" << backend << ") ...\n"; } else { coreSolver = UseDummySolver ? createDummySolver() : new STPSolver(UseForkedCoreSolver); @@ -280,16 +279,16 @@ static bool EvaluateInputAST(const char *Filename, ie = Decls.end(); it != ie; ++it) { Decl *D = *it; if (QueryCommand *QC = dyn_cast<QueryCommand>(D)) { - std::cout << "Query " << Index << ":\t"; + llvm::outs() << "Query " << Index << ":\t"; assert("FIXME: Support counterexample query commands!"); if (QC->Values.empty() && QC->Objects.empty()) { bool result; if (S->mustBeTrue(Query(ConstraintManager(QC->Constraints), QC->Query), result)) { - std::cout << (result ? "VALID" : "INVALID"); + llvm::outs() << (result ? "VALID" : "INVALID"); } else { - std::cout << "FAIL (reason: " + llvm::outs() << "FAIL (reason: " << SolverImpl::getOperationStatusString(S->impl->getOperationStatusCode()) << ")"; } @@ -304,10 +303,10 @@ static bool EvaluateInputAST(const char *Filename, if (S->getValue(Query(ConstraintManager(QC->Constraints), QC->Values[0]), result)) { - std::cout << "INVALID\n"; - std::cout << "\tExpr 0:\t" << result; + llvm::outs() << "INVALID\n"; + llvm::outs() << "\tExpr 0:\t" << result; } else { - std::cout << "FAIL (reason: " + llvm::outs() << "FAIL (reason: " << SolverImpl::getOperationStatusString(S->impl->getOperationStatusCode()) << ")"; } @@ -317,35 +316,35 @@ static bool EvaluateInputAST(const char *Filename, if (S->getInitialValues(Query(ConstraintManager(QC->Constraints), QC->Query), QC->Objects, result)) { - std::cout << "INVALID\n"; + llvm::outs() << "INVALID\n"; for (unsigned i = 0, e = result.size(); i != e; ++i) { - std::cout << "\tArray " << i << ":\t" + llvm::outs() << "\tArray " << i << ":\t" << QC->Objects[i]->name << "["; for (unsigned j = 0; j != QC->Objects[i]->size; ++j) { - std::cout << (unsigned) result[i][j]; + llvm::outs() << (unsigned) result[i][j]; if (j + 1 != QC->Objects[i]->size) - std::cout << ", "; + llvm::outs() << ", "; } - std::cout << "]"; + llvm::outs() << "]"; if (i + 1 != e) - std::cout << "\n"; + llvm::outs() << "\n"; } } else { SolverImpl::SolverRunStatus retCode = S->impl->getOperationStatusCode(); if (SolverImpl::SOLVER_RUN_STATUS_TIMEOUT == retCode) { - std::cout << " FAIL (reason: " + llvm::outs() << " FAIL (reason: " << SolverImpl::getOperationStatusString(retCode) << ")"; } else { - std::cout << "VALID (counterexample request ignored)"; + llvm::outs() << "VALID (counterexample request ignored)"; } } } - std::cout << "\n"; + llvm::outs() << "\n"; ++Index; } } @@ -358,7 +357,7 @@ static bool EvaluateInputAST(const char *Filename, delete S; if (uint64_t queries = *theStatisticManager->getStatisticByName("Queries")) { - std::cout + llvm::outs() << "--\n" << "total queries = " << queries << "\n" << "total queries constructs = " @@ -390,7 +389,7 @@ static bool printInputAsSMTLIBv2(const char *Filename, bool success = true; if (unsigned N = P->GetNumErrors()) { - std::cerr << Filename << ": parse failure: " + llvm::errs() << Filename << ": parse failure: " << N << " errors.\n"; success = false; } @@ -399,7 +398,7 @@ static bool printInputAsSMTLIBv2(const char *Filename, return false; ExprSMTLIBPrinter* printer = createSMTLIBPrinter(); - printer->setOutput(std::cout); + printer->setOutput(llvm::outs()); unsigned int queryNumber = 0; //Loop over the declarations @@ -409,10 +408,10 @@ static bool printInputAsSMTLIBv2(const char *Filename, if (QueryCommand *QC = dyn_cast<QueryCommand>(D)) { //print line break to separate from previous query - if(queryNumber!=0) std::cout << std::endl; + if(queryNumber!=0) llvm::outs() << "\n"; //Output header for this query as a SMT-LIBv2 comment - std::cout << ";SMTLIBv2 Query " << queryNumber << std::endl; + llvm::outs() << ";SMTLIBv2 Query " << queryNumber << "\n"; /* Can't pass ConstraintManager constructor directly * as argument to Query object. Like... @@ -458,7 +457,7 @@ int main(int argc, char **argv) { OwningPtr<MemoryBuffer> MB; error_code ec=MemoryBuffer::getFileOrSTDIN(InputFile.c_str(), MB); if (ec) { - std::cerr << argv[0] << ": error: " << ec.message() << "\n"; + llvm::errs() << argv[0] << ": error: " << ec.message() << "\n"; return 1; } @@ -494,7 +493,7 @@ int main(int argc, char **argv) { success = printInputAsSMTLIBv2(InputFile=="-"? "<stdin>" : InputFile.c_str(), MB.get(),Builder); break; default: - std::cerr << argv[0] << ": error: Unknown program action!\n"; + llvm::errs() << argv[0] << ": error: Unknown program action!\n"; } delete Builder; diff --git a/tools/klee-stats/Makefile b/tools/klee-stats/Makefile index 0b35fa51..89578b12 100644 --- a/tools/klee-stats/Makefile +++ b/tools/klee-stats/Makefile @@ -11,6 +11,10 @@ LEVEL = ../.. TOOLSCRIPTNAME := klee-stats +# Hack to prevent install trying to strip +# symbols from a python script +KEEP_SYMBOLS := 1 + include $(LEVEL)/Makefile.common # FIXME: Move this stuff (to "build" a script) into Makefile.rules. diff --git a/tools/klee/Debug.cpp b/tools/klee/Debug.cpp index 3d46de03..fbabed9d 100644 --- a/tools/klee/Debug.cpp +++ b/tools/klee/Debug.cpp @@ -1,12 +1,11 @@ #include <klee/Expr.h> -#include <iostream> void kdb_printExpr(klee::Expr *e) { - std::cerr << "expr: " << e << " -- "; + llvm::errs() << "expr: " << e << " -- "; if (e) { - std::cerr << *e; + llvm::errs() << *e; } else { - std::cerr << "(null)"; + llvm::errs() << "(null)"; } - std::cerr << "\n"; + llvm::errs() << "\n"; } diff --git a/tools/klee/Makefile b/tools/klee/Makefile index f050bf74..e526f2a2 100644 --- a/tools/klee/Makefile +++ b/tools/klee/Makefile @@ -30,5 +30,9 @@ ifeq ($(ENABLE_METASMT),1) -L$(METASMT_ROOT)/../../deps/boost-1_52_0/lib CXX.Flags += -DBOOST_HAS_GCC_TR1 CXX.Flags := $(filter-out -fno-exceptions,$(CXX.Flags)) - LIBS += -lrt -lgomp -lboost_iostreams -lboost_thread -lboost_system -lmetaSMT -lz3 -lboolector -lminisat_core -endif \ No newline at end of file + LIBS += -lgomp -lboost_iostreams -lboost_thread -lboost_system -lmetaSMT -lz3 -lrt -lboolector -lminisat_core +endif + +ifeq ($(STP_NEEDS_BOOST),1) + LIBS += $(UPSTREAM_STP_LINK_FLAGS) +endif diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp index 3616bfa6..aecf6991 100644 --- a/tools/klee/main.cpp +++ b/tools/klee/main.cpp @@ -34,8 +34,10 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" // FIXME: Ugh, this is gross. But otherwise our config.h conflicts with LLVMs. #undef PACKAGE_BUGREPORT @@ -60,7 +62,6 @@ #include <cerrno> #include <fstream> #include <iomanip> -#include <iostream> #include <iterator> #include <sstream> @@ -169,7 +170,7 @@ namespace { cl::opt<bool> ReplayKeepSymbolic("replay-keep-symbolic", - cl::desc("Replay the test cases only by asserting" + cl::desc("Replay the test cases only by asserting " "the bytes, not necessarily making them concrete.")); cl::list<std::string> @@ -195,7 +196,9 @@ namespace { cl::opt<unsigned> MakeConcreteSymbolic("make-concrete-symbolic", - cl::desc("Rate at which to make concrete reads symbolic (0=off)"), + cl::desc("Probabilistic rate at which to make concrete reads symbolic, " + "i.e. approximately 1 in n concrete reads will be made symbolic (0=off, 1=all). " + "Used for testing."), cl::init(0)); cl::opt<unsigned> @@ -217,9 +220,10 @@ class KleeHandler : public InterpreterHandler { private: Interpreter *m_interpreter; TreeStreamWriter *m_pathWriter, *m_symPathWriter; - std::ostream *m_infoFile; + llvm::raw_ostream *m_infoFile; + + SmallString<128> m_outputDirectory; - sys::Path m_outputDirectory; unsigned m_testIndex; // number of tests written so far unsigned m_pathsExplored; // number of paths explored so far @@ -231,7 +235,7 @@ public: KleeHandler(int argc, char **argv); ~KleeHandler(); - std::ostream &getInfoStream() const { return *m_infoFile; } + llvm::raw_ostream &getInfoStream() const { return *m_infoFile; } unsigned getNumTestCases() { return m_testIndex; } unsigned getNumPathsExplored() { return m_pathsExplored; } void incPathsExplored() { m_pathsExplored++; } @@ -243,9 +247,9 @@ public: const char *errorSuffix); std::string getOutputFilename(const std::string &filename); - std::ostream *openOutputFile(const std::string &filename); + llvm::raw_fd_ostream *openOutputFile(const std::string &filename); std::string getTestFilename(const std::string &suffix, unsigned id); - std::ostream *openTestFile(const std::string &suffix, unsigned id); + llvm::raw_fd_ostream *openTestFile(const std::string &suffix, unsigned id); // load a .out file static void loadOutFile(std::string name, @@ -257,6 +261,8 @@ public: static void getOutFiles(std::string path, std::vector<std::string> &results); + + static std::string getRunTimeLibraryPath(const char *argv0); }; KleeHandler::KleeHandler(int argc, char **argv) @@ -270,81 +276,66 @@ KleeHandler::KleeHandler(int argc, char **argv) m_argc(argc), m_argv(argv) { - if (OutputDir=="") { - llvm::sys::Path directory(InputFile); - std::stringstream dirname; - directory.eraseComponent(); - - if (directory.isEmpty()) - directory.set("."); - - for (int i = 0; i< INT_MAX ; i++) { - dirname << "klee-out-"; - dirname << i; + // create output directory (OutputDir or "klee-out-<i>") + bool dir_given = OutputDir != ""; + SmallString<128> directory(dir_given ? OutputDir : InputFile); - m_outputDirectory = llvm::sys::Path(directory); // Copy - if (!m_outputDirectory.appendComponent(dirname.str())) - klee_error("Failed to append \"%s\" to \"%s\"", dirname.str().c_str(), directory.c_str()); - - bool isDir = true; - llvm::error_code e = llvm::sys::fs::exists(m_outputDirectory.str(), isDir); - if ( e != llvm::errc::success ) - klee_error("Failed to check if \"%s\" exists.", m_outputDirectory.str().c_str()); - - if (!isDir) - { - break; // Found an available directory name - } + error_code ec; + if (!dir_given) sys::path::remove_filename(directory); + if ((ec = sys::fs::make_absolute(directory)) != errc::success) + klee_error("unable to determine absolute path: %s", ec.message().c_str()); - // Warn the user if the klee-out-* exists but is not a directory - e = llvm::sys::fs::is_directory(m_outputDirectory.str(), isDir); - if ( e == llvm::errc::success && !isDir ) - klee_warning("A file \"%s\" exists, but it is not a directory", - m_outputDirectory.str().c_str()); + if (dir_given) { + // OutputDir + if (mkdir(directory.c_str(), 0775) < 0) + klee_error("cannot create \"%s\": %s", directory.c_str(), strerror(errno)); - dirname.str(""); // Clear - m_outputDirectory.clear(); - } + m_outputDirectory = directory; + } else { + // "klee-out-<i>" + int i = 0; + for (; i <= INT_MAX; ++i) { + SmallString<128> d(directory); + llvm::sys::path::append(d, "klee-out-"); + raw_svector_ostream ds(d); ds << i; ds.flush(); - if (m_outputDirectory.empty()) - klee_error("Failed to find available output directory in %s", dirname.str().c_str()); + // create directory and try to link klee-last + if (mkdir(d.c_str(), 0775) == 0) { + m_outputDirectory = d; - std::cerr << "KLEE: output directory = \"" << dirname.str() << "\"\n"; + SmallString<128> klee_last(directory); + llvm::sys::path::append(klee_last, "klee-last"); - llvm::sys::Path klee_last(directory); - if(!klee_last.appendComponent("klee-last")) - klee_error("cannot create path name for klee-last"); + if (((unlink(klee_last.c_str()) < 0) && (errno != ENOENT)) || + symlink(m_outputDirectory.c_str(), klee_last.c_str()) < 0) { - if ((unlink(klee_last.c_str()) < 0) && (errno != ENOENT)) - klee_error("cannot unlink klee-last: %s", strerror(errno)); - - if (symlink(dirname.str().c_str(), klee_last.c_str()) < 0) - klee_error("cannot create klee-last symlink: %s", strerror(errno)); + klee_warning("cannot create klee-last symlink: %s", strerror(errno)); + } - } else { - if (!m_outputDirectory.set(OutputDir)) - klee_error("cannot use klee output directory: %s", OutputDir.c_str()); - } - - if (!sys::path::is_absolute(m_outputDirectory.c_str())) { - sys::Path cwd = sys::Path::GetCurrentDirectory(); - if(!cwd.appendComponent( m_outputDirectory.c_str())) - klee_error("cannot create absolute path name for output directory"); + break; + } - m_outputDirectory = cwd; + // otherwise try again or exit on error + if (errno != EEXIST) + klee_error("cannot create \"%s\": %s", m_outputDirectory.c_str(), strerror(errno)); + } + if (i == INT_MAX && m_outputDirectory.str().equals("")) + klee_error("cannot create output directory: index out of range"); } - if (mkdir(m_outputDirectory.c_str(), 0775) < 0) - klee_error("cannot create directory \"%s\": %s", m_outputDirectory.c_str(), strerror(errno)); + klee_message("output directory is \"%s\"", m_outputDirectory.c_str()); + // open warnings.txt std::string file_path = getOutputFilename("warnings.txt"); if ((klee_warning_file = fopen(file_path.c_str(), "w")) == NULL) klee_error("cannot open file \"%s\": %s", file_path.c_str(), strerror(errno)); + // open messages.txt file_path = getOutputFilename("messages.txt"); if ((klee_message_file = fopen(file_path.c_str(), "w")) == NULL) klee_error("cannot open file \"%s\": %s", file_path.c_str(), strerror(errno)); + // open info m_infoFile = openOutputFile("info"); } @@ -373,24 +364,25 @@ void KleeHandler::setInterpreter(Interpreter *i) { } std::string KleeHandler::getOutputFilename(const std::string &filename) { - sys::Path path(m_outputDirectory); - if(!path.appendComponent(filename)) { - klee_error("cannot create path name for \"%s\"", filename.c_str()); - } - + SmallString<128> path = m_outputDirectory; + sys::path::append(path,filename); return path.str(); } -std::ostream *KleeHandler::openOutputFile(const std::string &filename) { - std::ios::openmode io_mode = std::ios::out | std::ios::trunc - | std::ios::binary; - std::ostream *f; +llvm::raw_fd_ostream *KleeHandler::openOutputFile(const std::string &filename) { + llvm::raw_fd_ostream *f; + std::string Error; std::string path = getOutputFilename(filename); - f = new std::ofstream(path.c_str(), io_mode); - if (!f) { - klee_error("error opening file \"%s\" (out of memory)", filename.c_str()); - } else if (!f->good()) { - klee_error("error opening file \"%s\". KLEE may have run out of file descriptors: try to increase the maximum number of open file descriptors by using ulimit.", filename.c_str()); +#if LLVM_VERSION_CODE >= LLVM_VERSION(3,0) + f = new llvm::raw_fd_ostream(path.c_str(), Error, llvm::sys::fs::F_Binary); +#else + f = new llvm::raw_fd_ostream(path.c_str(), Error, llvm::raw_fd_ostream::F_Binary); +#endif + if (!Error.empty()) { + klee_error("error opening file \"%s\". KLEE may have run out of file " + "descriptors: try to increase the maximum number of open file " + "descriptors by using ulimit (%s).", + filename.c_str(), Error.c_str()); delete f; f = NULL; } @@ -404,7 +396,8 @@ std::string KleeHandler::getTestFilename(const std::string &suffix, unsigned id) return filename.str(); } -std::ostream *KleeHandler::openTestFile(const std::string &suffix, unsigned id) { +llvm::raw_fd_ostream *KleeHandler::openTestFile(const std::string &suffix, + unsigned id) { return openOutputFile(getTestFilename(suffix, id)); } @@ -414,7 +407,7 @@ void KleeHandler::processTestCase(const ExecutionState &state, const char *errorMessage, const char *errorSuffix) { if (errorMessage && ExitOnError) { - std::cerr << "EXITING ON ERROR:\n" << errorMessage << "\n"; + llvm::errs() << "EXITING ON ERROR:\n" << errorMessage << "\n"; exit(1); } @@ -457,7 +450,7 @@ void KleeHandler::processTestCase(const ExecutionState &state, } if (errorMessage) { - std::ostream *f = openTestFile(errorSuffix, id); + llvm::raw_ostream *f = openTestFile(errorSuffix, id); *f << errorMessage; delete f; } @@ -466,16 +459,19 @@ void KleeHandler::processTestCase(const ExecutionState &state, std::vector<unsigned char> concreteBranches; m_pathWriter->readStream(m_interpreter->getPathStreamID(state), concreteBranches); - std::ostream *f = openTestFile("path", id); - std::copy(concreteBranches.begin(), concreteBranches.end(), - std::ostream_iterator<unsigned char>(*f, "\n")); + llvm::raw_fd_ostream *f = openTestFile("path", id); + for (std::vector<unsigned char>::iterator I = concreteBranches.begin(), + E = concreteBranches.end(); + I != E; ++I) { + *f << *I << "\n"; + } delete f; } if (errorMessage || WritePCs) { std::string constraints; m_interpreter->getConstraintLog(state, constraints,Interpreter::KQUERY); - std::ostream *f = openTestFile("pc", id); + llvm::raw_ostream *f = openTestFile("pc", id); *f << constraints; delete f; } @@ -483,7 +479,7 @@ void KleeHandler::processTestCase(const ExecutionState &state, if (WriteCVCs) { std::string constraints; m_interpreter->getConstraintLog(state, constraints, Interpreter::STP); - std::ostream *f = openTestFile("cvc", id); + llvm::raw_ostream *f = openTestFile("cvc", id); *f << constraints; delete f; } @@ -491,7 +487,7 @@ void KleeHandler::processTestCase(const ExecutionState &state, if(WriteSMT2s) { std::string constraints; m_interpreter->getConstraintLog(state, constraints, Interpreter::SMTLIB2); - std::ostream *f = openTestFile("smt2", id); + llvm::raw_ostream *f = openTestFile("smt2", id); *f << constraints; delete f; } @@ -500,16 +496,17 @@ void KleeHandler::processTestCase(const ExecutionState &state, std::vector<unsigned char> symbolicBranches; m_symPathWriter->readStream(m_interpreter->getSymbolicPathStreamID(state), symbolicBranches); - std::ostream *f = openTestFile("sym.path", id); - std::copy(symbolicBranches.begin(), symbolicBranches.end(), - std::ostream_iterator<unsigned char>(*f, "\n")); + llvm::raw_fd_ostream *f = openTestFile("sym.path", id); + for (std::vector<unsigned char>::iterator I = symbolicBranches.begin(), E = symbolicBranches.end(); I!=E; ++I) { + *f << *I << "\n"; + } delete f; } if (WriteCov) { std::map<const std::string*, std::set<unsigned> > cov; m_interpreter->getCoveredLines(state, cov); - std::ostream *f = openTestFile("cov", id); + llvm::raw_ostream *f = openTestFile("cov", id); for (std::map<const std::string*, std::set<unsigned> >::iterator it = cov.begin(), ie = cov.end(); it != ie; ++it) { @@ -526,7 +523,7 @@ void KleeHandler::processTestCase(const ExecutionState &state, if (WriteTestInfo) { double elapsed_time = util::getWallTime() - start_time; - std::ostream *f = openTestFile("info", id); + llvm::raw_ostream *f = openTestFile("info", id); *f << "Time to generate test case: " << elapsed_time << "s\n"; delete f; @@ -552,21 +549,56 @@ void KleeHandler::loadPathFile(std::string name, void KleeHandler::getOutFiles(std::string path, std::vector<std::string> &results) { - llvm::sys::Path p(path); - std::set<llvm::sys::Path> contents; - std::string error; - if (p.getDirectoryContents(contents, &error)) { - std::cerr << "ERROR: unable to read output directory: " << path - << ": " << error << "\n"; - exit(1); - } - for (std::set<llvm::sys::Path>::iterator it = contents.begin(), - ie = contents.end(); it != ie; ++it) { - std::string f = it->str(); + error_code ec; + for (llvm::sys::fs::directory_iterator i(path,ec),e; i!=e && !ec; i.increment(ec)){ + std::string f = (*i).path(); if (f.substr(f.size()-6,f.size()) == ".ktest") { - results.push_back(f); + results.push_back(f); } } + + if (ec) { + llvm::errs() << "ERROR: unable to read output directory: " << path << ": " + << ec.message() << "\n"; + exit(1); + } +} + +std::string KleeHandler::getRunTimeLibraryPath(const char *argv0) { + // Take any function from the execution binary but not main (as not allowed by + // C++ standard) + void *MainExecAddr = (void *)(intptr_t)getRunTimeLibraryPath; + SmallString<128> toolRoot( + #if LLVM_VERSION_CODE >= LLVM_VERSION(3,4) + llvm::sys::fs::getMainExecutable(argv0, MainExecAddr) + #else + llvm::sys::Path::GetMainExecutable(argv0, MainExecAddr).str() + #endif + ); + + // Strip off executable so we have a directory path + llvm::sys::path::remove_filename(toolRoot); + + SmallString<128> libDir; + + if ( strcmp(toolRoot.c_str(), KLEE_INSTALL_BIN_DIR ) == 0) + { + DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() << + "Using installed KLEE library runtime: "); + libDir = KLEE_INSTALL_LIB_DIR ; + } + else + { + DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() << + "Using build directory KLEE library runtime :"); + libDir = KLEE_DIR; + llvm::sys::path::append(libDir,RUNTIME_CONFIGURATION); + llvm::sys::path::append(libDir,"lib"); + } + + DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() << + libDir.c_str() << "\n"); + return libDir.str(); } //===----------------------------------------------------------------------===// @@ -932,11 +964,11 @@ void stop_forking() { static void interrupt_handle() { if (!interrupted && theInterpreter) { - std::cerr << "KLEE: ctrl-c detected, requesting interpreter to halt.\n"; + llvm::errs() << "KLEE: ctrl-c detected, requesting interpreter to halt.\n"; halt_execution(); sys::SetInterruptFunction(interrupt_handle); } else { - std::cerr << "KLEE: ctrl-c detected, exiting.\n"; + llvm::errs() << "KLEE: ctrl-c detected, exiting.\n"; exit(1); } interrupted = true; @@ -977,8 +1009,8 @@ static char *format_tdiff(char *buf, long seconds) return buf; } -#ifndef KLEE_UCLIBC -static llvm::Module *linkWithUclibc(llvm::Module *mainModule) { +#ifndef SUPPORT_KLEE_UCLIBC +static llvm::Module *linkWithUclibc(llvm::Module *mainModule, StringRef libDir) { fprintf(stderr, "error: invalid libc, no uclibc support!\n"); exit(1); return 0; @@ -1000,13 +1032,15 @@ static void replaceOrRenameFunction(llvm::Module *module, } } } +static llvm::Module *linkWithUclibc(llvm::Module *mainModule, StringRef libDir) { + // Ensure that klee-uclibc exists + SmallString<128> uclibcBCA(libDir); + llvm::sys::path::append(uclibcBCA, KLEE_UCLIBC_BCA_NAME); -static llvm::Module *linkWithUclibc(llvm::Module *mainModule) { - // Ensure that KLEE_UCLIBC exists - bool uclibcRootExists=false; - llvm::sys::fs::is_directory(KLEE_UCLIBC, uclibcRootExists); - if (!uclibcRootExists) - klee_error("Cannot link with uclibc. KLEE_UCLIBC (\"" KLEE_UCLIBC "\") is not a directory."); + bool uclibcExists=false; + llvm::sys::fs::exists(uclibcBCA.c_str(), uclibcExists); + if (!uclibcExists) + klee_error("Cannot find klee-uclibc : %s", uclibcBCA.c_str()); Function *f; // force import of __uClibc_main @@ -1065,8 +1099,7 @@ static llvm::Module *linkWithUclibc(llvm::Module *mainModule) { } } - mainModule = klee::linkWithLibrary(mainModule, - KLEE_UCLIBC "/lib/libc.a"); + mainModule = klee::linkWithLibrary(mainModule, uclibcBCA.c_str()); assert(mainModule && "unable to link with uclibc"); @@ -1119,6 +1152,7 @@ static llvm::Module *linkWithUclibc(llvm::Module *mainModule) { new UnreachableInst(getGlobalContext(), bb); + klee_message("NOTE: Using klee-uclibc : %s", uclibcBCA.c_str()); return mainModule; } #endif @@ -1227,14 +1261,7 @@ int main(int argc, char **argv, char **envp) { return r; } -#if defined(KLEE_LIB_DIR) && defined(USE_KLEE_LIB_DIR) - /* KLEE_LIB_DIR is the lib dir of installed files as opposed to - * where libs in the klee source tree are generated. - */ - llvm::sys::Path LibraryDir(KLEE_LIB_DIR); -#else - llvm::sys::Path LibraryDir(KLEE_DIR "/" RUNTIME_CONFIGURATION "/lib"); -#endif + std::string LibraryDir = KleeHandler::getRunTimeLibraryPath(argv[0]); Interpreter::ModuleOptions Opts(LibraryDir.c_str(), /*Optimize=*/OptimizeModule, /*CheckDivZero=*/CheckDivZero, @@ -1246,11 +1273,11 @@ int main(int argc, char **argv, char **envp) { case KleeLibc: { // FIXME: Find a reasonable solution for this. - llvm::sys::Path Path(Opts.LibraryDir); -#if LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) - Path.appendComponent("klee-libc.bc"); + SmallString<128> Path(Opts.LibraryDir); +#if LLVM_VERSION_CODE >= LLVM_VERSION(3,3) + llvm::sys::path::append(Path, "klee-libc.bc"); #else - Path.appendComponent("libklee-libc.bca"); + llvm::sys::path::append(Path, "libklee-libc.bca"); #endif mainModule = klee::linkWithLibrary(mainModule, Path.c_str()); assert(mainModule && "unable to link with klee-libc"); @@ -1258,13 +1285,13 @@ int main(int argc, char **argv, char **envp) { } case UcLibc: - mainModule = linkWithUclibc(mainModule); + mainModule = linkWithUclibc(mainModule, LibraryDir); break; } if (WithPOSIXRuntime) { - llvm::sys::Path Path(Opts.LibraryDir); - Path.appendComponent("libkleeRuntimePOSIX.bca"); + SmallString<128> Path(Opts.LibraryDir); + llvm::sys::path::append(Path, "libkleeRuntimePOSIX.bca"); klee_message("NOTE: Using model: %s", Path.c_str()); mainModule = klee::linkWithLibrary(mainModule, Path.c_str()); assert(mainModule && "unable to link with simple model"); @@ -1274,7 +1301,7 @@ int main(int argc, char **argv, char **envp) { // locale and other data and then calls main. Function *mainFn = mainModule->getFunction("main"); if (!mainFn) { - std::cerr << "'main' function not found in module.\n"; + llvm::errs() << "'main' function not found in module.\n"; return -1; } @@ -1329,8 +1356,8 @@ int main(int argc, char **argv, char **envp) { Interpreter *interpreter = theInterpreter = Interpreter::create(IOpts, handler); handler->setInterpreter(interpreter); - - std::ostream &infoFile = handler->getInfoStream(); + + llvm::raw_ostream &infoFile = handler->getInfoStream(); for (int i=0; i<argc; i++) { infoFile << argv[i] << (i+1<argc ? " ":"\n"); } @@ -1368,7 +1395,7 @@ int main(int argc, char **argv, char **envp) { if (out) { kTests.push_back(out); } else { - std::cerr << "KLEE: unable to open: " << *it << "\n"; + llvm::errs() << "KLEE: unable to open: " << *it << "\n"; } } @@ -1385,8 +1412,9 @@ int main(int argc, char **argv, char **envp) { it != ie; ++it) { KTest *out = *it; interpreter->setReplayOut(out); - std::cerr << "KLEE: replaying: " << *it << " (" << kTest_numBytes(out) << " bytes)" - << " (" << ++i << "/" << outFiles.size() << ")\n"; + llvm::errs() << "KLEE: replaying: " << *it << " (" << kTest_numBytes(out) + << " bytes)" + << " (" << ++i << "/" << outFiles.size() << ")\n"; // XXX should put envp in .ktest ? interpreter->runFunctionAsMain(mainFn, out->numArgs, out->args, pEnvp); if (interrupted) break; @@ -1403,7 +1431,7 @@ int main(int argc, char **argv, char **envp) { it != ie; ++it) { KTest *out = kTest_fromFile(it->c_str()); if (!out) { - std::cerr << "KLEE: unable to open: " << *it << "\n"; + llvm::errs() << "KLEE: unable to open: " << *it << "\n"; exit(1); } seeds.push_back(out); @@ -1418,19 +1446,19 @@ int main(int argc, char **argv, char **envp) { it2 != ie; ++it2) { KTest *out = kTest_fromFile(it2->c_str()); if (!out) { - std::cerr << "KLEE: unable to open: " << *it2 << "\n"; + llvm::errs() << "KLEE: unable to open: " << *it2 << "\n"; exit(1); } seeds.push_back(out); } if (outFiles.empty()) { - std::cerr << "KLEE: seeds directory is empty: " << *it << "\n"; + llvm::errs() << "KLEE: seeds directory is empty: " << *it << "\n"; exit(1); } } if (!seeds.empty()) { - std::cerr << "KLEE: using " << seeds.size() << " seeds\n"; + llvm::errs() << "KLEE: using " << seeds.size() << " seeds\n"; interpreter->useSeeds(&seeds); } if (RunInDir != "") { @@ -1500,7 +1528,7 @@ int main(int argc, char **argv, char **envp) { << handler->getNumPathsExplored() << "\n"; stats << "KLEE: done: generated tests = " << handler->getNumTestCases() << "\n"; - std::cerr << stats.str(); + llvm::errs() << stats.str(); handler->getInfoStream() << stats.str(); BufferPtr.take(); diff --git a/tools/ktest-tool/Makefile b/tools/ktest-tool/Makefile index 69d7324c..580b1f6a 100644 --- a/tools/ktest-tool/Makefile +++ b/tools/ktest-tool/Makefile @@ -11,6 +11,10 @@ LEVEL = ../.. TOOLSCRIPTNAME := ktest-tool +# Hack to prevent install trying to strip +# symbols from a python script +KEEP_SYMBOLS := 1 + include $(LEVEL)/Makefile.common # FIXME: Move this stuff (to "build" a script) into Makefile.rules. diff --git a/unittests/Expr/Makefile b/unittests/Expr/Makefile index f1cd4ec4..a9bfeda1 100644 --- a/unittests/Expr/Makefile +++ b/unittests/Expr/Makefile @@ -9,4 +9,5 @@ LINK_COMPONENTS := support include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest +CXXFLAGS += -DLLVM_29_UNITTEST LIBS += -lstp diff --git a/unittests/Makefile b/unittests/Makefile index 761987d6..175ccdd5 100644 --- a/unittests/Makefile +++ b/unittests/Makefile @@ -14,5 +14,9 @@ DIRS = Expr Solver Ref include $(LEVEL)/Makefile.common +# Remove -fno-rtti as this prevents typeid() being used +# in gtest +CXX.Flags := $(filter-out -fno-rtti,$(CXX.Flags)) + clean:: $(Verb) $(RM) -f *Tests diff --git a/unittests/Solver/Makefile b/unittests/Solver/Makefile index 00713691..83427795 100644 --- a/unittests/Solver/Makefile +++ b/unittests/Solver/Makefile @@ -10,3 +10,7 @@ LINK_COMPONENTS := support include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest LIBS += -lstp + +ifeq ($(STP_NEEDS_BOOST),1) + LIBS += $(UPSTREAM_STP_LINK_FLAGS) +endif |