diff options
-rw-r--r-- | .travis.yml | 9 | ||||
-rwxr-xr-x | .travis/install-llvm-and-runtime-compiler.sh | 19 | ||||
-rwxr-xr-x | .travis/install-tcmalloc.sh | 26 | ||||
-rwxr-xr-x | .travis/klee.sh | 34 | ||||
-rwxr-xr-x | .travis/solvers.sh | 9 | ||||
-rwxr-xr-x | .travis/stp.sh | 63 | ||||
-rwxr-xr-x | .travis/testing-utils.sh | 15 | ||||
-rwxr-xr-x | .travis/z3.sh | 20 | ||||
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | Dockerfile | 3 | ||||
-rw-r--r-- | README-CMake.md | 1 | ||||
-rw-r--r-- | cmake/find_llvm.cmake | 2 | ||||
-rw-r--r-- | include/klee/CommandLine.h | 2 | ||||
-rw-r--r-- | include/klee/Solver.h | 6 | ||||
-rw-r--r-- | include/klee/util/Assignment.h | 1 | ||||
-rw-r--r-- | lib/Basic/CmdLineOptions.cpp | 4 | ||||
-rw-r--r-- | lib/Basic/ConstructSolverChain.cpp | 3 | ||||
-rw-r--r-- | lib/Expr/Assigment.cpp | 17 | ||||
-rw-r--r-- | lib/Solver/AssignmentValidatingSolver.cpp | 158 | ||||
-rw-r--r-- | lib/Solver/CMakeLists.txt | 1 | ||||
-rw-r--r-- | runtime/CMakeLists.txt | 11 | ||||
-rw-r--r-- | runtime/Makefile.cmake.bitcode.rules | 9 | ||||
-rw-r--r-- | runtime/POSIX/stubs.c | 22 | ||||
-rw-r--r-- | test/lit.cfg | 106 |
24 files changed, 442 insertions, 106 deletions
diff --git a/.travis.yml b/.travis.yml index cd2a9771..3d01b506 100644 --- a/.travis.yml +++ b/.travis.yml @@ -82,6 +82,12 @@ env: - secure: Hrp1MRSxDUH2GTQg3QR/yUttY/3KmgbFb5e+zyy551dKpHjxJdsNe8bquY9oFoT7KmPQYl0HNNjEv4qWW8RK+HWHOCB55nL1KlGpOG7vAJcUEZg7ScbliGgiovMB6jIQVfeP9FhYngfc13vNZQ5PGlqzfSsHSAbvkwEogBToHVw= - secure: DQAEQWJblXvIztN/sgH63OtFncI+Qju6wRy1zIV/iLf5KbAmLs1h3itU7EsE/+3+LgV1MVQ5QNJDBUj17A6VHRKNaQ5qnIllTAcC3o0nPDohQkQoCgDG8HZ+M4wtVfr7q2K6byEPB2UbSH+mEjSMTihJufgBBVfKyyozAfYycjg= +matrix: + include: + - os: osx + osx_image: xcode8.2 + env: LLVM_VERSION=3.4 SOLVERS=STP:Z3 STP_VERSION=2.1.2 KLEE_UCLIBC=0 DISABLE_ASSERTIONS=0 ENABLE_OPTIMIZED=1 COVERAGE=0 USE_TCMALLOC=0 USE_CMAKE=1 + addons: apt: sources: @@ -103,7 +109,8 @@ before_install: # We assume the Travis image uses Ubuntu 14.04 LTS ########################################################################### # Update package information - - sudo apt-get update + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew tap andreamattavelli/klee; fi ########################################################################### # Set up out of source build directory ########################################################################### diff --git a/.travis/install-llvm-and-runtime-compiler.sh b/.travis/install-llvm-and-runtime-compiler.sh index 1068d158..8e8e9863 100755 --- a/.travis/install-llvm-and-runtime-compiler.sh +++ b/.travis/install-llvm-and-runtime-compiler.sh @@ -1,13 +1,14 @@ #!/bin/bash -x set -ev -sudo apt-get install -y llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev +if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + sudo apt-get install -y llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev -if [ "${LLVM_VERSION}" != "2.9" ]; then + if [ "${LLVM_VERSION}" != "2.9" ]; then sudo apt-get install -y llvm-${LLVM_VERSION}-tools clang-${LLVM_VERSION} sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 20 sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 20 -else + else # Get llvm-gcc. We don't bother installing it wget http://llvm.org/releases/2.9/llvm-gcc4.2-2.9-x86_64-linux.tar.bz2 tar -xjf llvm-gcc4.2-2.9-x86_64-linux.tar.bz2 @@ -27,4 +28,16 @@ else export CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu llvm-gcc/bin/llvm-gcc test.c -o hello_world ./hello_world + fi +elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + # NOTE: We should not easily generalize, since we need the corresponding support of bottled formulas + if [ "${LLVM_VERSION}" == "3.4" ]; then + brew install llvm34 + else + echo "Error: Requested to install LLVM ${LLVM_VERSION} on macOS, which is not supported" + exit 1 + fi +else + echo "Unhandled TRAVIS_OS_NAME \"${TRAVIS_OS_NAME}\"" + exit 1 fi diff --git a/.travis/install-tcmalloc.sh b/.travis/install-tcmalloc.sh index 5a86380b..0bc26616 100755 --- a/.travis/install-tcmalloc.sh +++ b/.travis/install-tcmalloc.sh @@ -1,12 +1,22 @@ #!/bin/bash -x set -ev -if [ ${USE_TCMALLOC:-0} -eq 1 ] ; then - # Get tcmalloc release - wget https://github.com/gperftools/gperftools/releases/download/gperftools-2.4/gperftools-2.4.tar.gz - tar xfz gperftools-2.4.tar.gz - cd gperftools-2.4 - ./configure --disable-dependency-tracking --disable-cpu-profiler --disable-heap-checker --disable-debugalloc --enable-minimal --prefix=/usr - make - sudo make install +if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + if [ ${USE_TCMALLOC:-0} -eq 1 ] ; then + # Get tcmalloc release + wget https://github.com/gperftools/gperftools/releases/download/gperftools-2.4/gperftools-2.4.tar.gz + tar xfz gperftools-2.4.tar.gz + cd gperftools-2.4 + ./configure --disable-dependency-tracking --disable-cpu-profiler --disable-heap-checker --disable-debugalloc --enable-minimal --prefix=/usr + make + sudo make install + fi +elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + if [ ${USE_TCMALLOC:-0} -eq 1 ] ; then + echo "Error: Requested to install TCMalloc on macOS, which is not supported" + exit 1 + fi +else + echo "Unhandled TRAVIS_OS_NAME \"${TRAVIS_OS_NAME}\"" + exit 1 fi diff --git a/.travis/klee.sh b/.travis/klee.sh index 61806df3..5ee631fa 100755 --- a/.travis/klee.sh +++ b/.travis/klee.sh @@ -10,8 +10,16 @@ SVN_BRANCH="release_$( echo ${LLVM_VERSION} | sed 's/\.//g')" # Select the compiler to use to generate LLVM bitcode ############################################################################### if [ "${LLVM_VERSION}" != "2.9" ]; then + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then KLEE_CC=/usr/bin/clang-${LLVM_VERSION} KLEE_CXX=/usr/bin/clang++-${LLVM_VERSION} + elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + KLEE_CC=/usr/local/bin/clang-${LLVM_VERSION} + KLEE_CXX=/usr/local/bin/clang++-${LLVM_VERSION} + else + echo "Unhandled TRAVIS_OS_NAME \"${TRAVIS_OS_NAME}\"" + exit 1 + fi else # Just use pre-built llvm-gcc downloaded earlier KLEE_CC=${BUILD_DIR}/llvm-gcc/bin/llvm-gcc @@ -117,6 +125,20 @@ fi source ${KLEE_SRC}/.travis/sanitizer_flags.sh ############################################################################### +# Handling LLVM configuration +############################################################################### +if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + LLVM_CONFIG="/usr/lib/llvm-${LLVM_VERSION}/bin/llvm-config" + LLVM_BUILD_DIR="/usr/lib/llvm-${LLVM_VERSION}/build" +elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + LLVM_CONFIG="/usr/local/bin/llvm-config-${LLVM_VERSION}" + LLVM_BUILD_DIR="$(${LLVM_CONFIG} --src-root)" +else + echo "Unhandled TRAVIS_OS_NAME \"${TRAVIS_OS_NAME}\"" + exit 1 +fi + +############################################################################### # KLEE ############################################################################### mkdir klee @@ -139,7 +161,7 @@ if [ "X${USE_CMAKE}" == "X1" ]; then CXXFLAGS="${COVERAGE_FLAGS} ${SANITIZER_CXX_FLAGS}" \ CFLAGS="${COVERAGE_FLAGS} ${SANITIZER_C_FLAGS}" \ cmake \ - -DLLVM_CONFIG_BINARY="/usr/lib/llvm-${LLVM_VERSION}/bin/llvm-config" \ + -DLLVM_CONFIG_BINARY="${LLVM_CONFIG}" \ -DLLVMCC="${KLEE_CC}" \ -DLLVMCXX="${KLEE_CXX}" \ ${KLEE_STP_CONFIGURE_OPTION} \ @@ -160,8 +182,8 @@ else # Note: ENABLE_SHARED=0 is required because llvm-2.9 is incorectly packaged # and is missing the shared library that was supposed to be built that the build # system will try to use by default. - ${KLEE_SRC}/configure --with-llvmsrc=/usr/lib/llvm-${LLVM_VERSION}/build \ - --with-llvmobj=/usr/lib/llvm-${LLVM_VERSION}/build \ + ${KLEE_SRC}/configure --with-llvmsrc=${LLVM_BUILD_DIR} \ + --with-llvmobj=${LLVM_BUILD_DIR} \ --with-llvmcc=${KLEE_CC} \ --with-llvmcxx=${KLEE_CXX} \ ${KLEE_STP_CONFIGURE_OPTION} \ @@ -234,14 +256,14 @@ if [ ${COVERAGE} -eq 1 ]; then cd zcov #these files are not where zcov expects them to be after install so we move them - sudo cp js/sorttable.js /usr/local/lib/python2.7/dist-packages/zcov-0.3.0.dev0-py2.7.egg/zcov/js/sorttable.js - sudo cp js/sourceview.js /usr/local/lib/python2.7/dist-packages/zcov-0.3.0.dev0-py2.7.egg/zcov/js/sourceview.js + sudo cp js/sorttable.js /usr/local/lib/python2.7/dist-packages/zcov-0.3.0.dev0-py2.7.egg/zcov/js/sorttable.js + sudo cp js/sourceview.js /usr/local/lib/python2.7/dist-packages/zcov-0.3.0.dev0-py2.7.egg/zcov/js/sourceview.js sudo cp style.css /usr/local/lib/python2.7/dist-packages/zcov-0.3.0.dev0-py2.7.egg/zcov/style.css #install zcov dependency sudo apt-get install -y enscript -#update gcov from v4.6 to v4.8. This is becauase gcda files are made for v4.8 and cause +#update gcov from v4.6 to v4.8. This is becauase gcda files are made for v4.8 and cause #a segmentation fault in v4.6 sudo apt-get install -y ggcov sudo rm /usr/bin/gcov diff --git a/.travis/solvers.sh b/.travis/solvers.sh index 04f3276f..b419d679 100755 --- a/.travis/solvers.sh +++ b/.travis/solvers.sh @@ -16,15 +16,8 @@ for solver in ${SOLVER_LIST}; do cd ../ ;; Z3) - # FIXME: Move this into its own script - source ${KLEE_SRC}/.travis/sanitizer_flags.sh - if [ "X${IS_SANITIZED_BUILD}" != "X0" ]; then - echo "Error: Requested Sanitized build but Z3 being used is not sanitized" - exit 1 - fi echo "Z3" - # Should we install libz3-dbg too? - sudo apt-get -y install libz3 libz3-dev + ${KLEE_SRC}/.travis/z3.sh ;; metaSMT) echo "metaSMT" diff --git a/.travis/stp.sh b/.travis/stp.sh index 4cc55c62..0112ae31 100755 --- a/.travis/stp.sh +++ b/.travis/stp.sh @@ -1,46 +1,57 @@ #!/bin/bash -x +# TODO: For OSX we can prepare bottled formulas for STP and minisat + # Make sure we exit if there is a failure set -e STP_LOG="$(pwd)/stp-build.log" if [ "x${STP_VERSION}" != "x" ]; then - # Get Sanitizer flags - source ${KLEE_SRC}/.travis/sanitizer_flags.sh - - # Build minisat - git clone https://github.com/stp/minisat - cd minisat - mkdir build - cd build - MINISAT_DIR=`pwd` + # Get Sanitizer flags + source ${KLEE_SRC}/.travis/sanitizer_flags.sh + + # Build minisat + git clone https://github.com/stp/minisat + cd minisat + mkdir build + cd build + MINISAT_DIR=`pwd` + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then CFLAGS="${SANITIZER_C_FLAGS}" \ CXXFLAGS="${SANITIZER_CXX_FLAGS}" \ cmake -DCMAKE_INSTALL_PREFIX=/usr .. - make - sudo make install - cd ../../ - - # Build STP - git clone --depth 1 -b "${STP_VERSION}" git://github.com/stp/stp.git src - mkdir build - cd build - # Disabling building of shared libs is a workaround. - # Don't build against boost because that is broken when mixing packaged boost libraries and gcc 4.8 + elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then CFLAGS="${SANITIZER_C_FLAGS}" \ CXXFLAGS="${SANITIZER_CXX_FLAGS}" \ - cmake -DBUILD_SHARED_LIBS:BOOL=OFF -DENABLE_PYTHON_INTERFACE:BOOL=OFF -DNO_BOOST:BOOL=ON ../src + cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. + else + echo "Unhandled TRAVIS_OS_NAME \"${TRAVIS_OS_NAME}\"" + exit 1 + fi + make + sudo make install + cd ../../ - set +e # Do not exit if build fails because we need to display the log - make >> "${STP_LOG}" 2>&1 + # Build STP + git clone --depth 1 -b "${STP_VERSION}" git://github.com/stp/stp.git src + mkdir build + cd build + # Disabling building of shared libs is a workaround. + # Don't build against boost because that is broken when mixing packaged boost libraries and gcc 4.8 + CFLAGS="${SANITIZER_C_FLAGS}" \ + CXXFLAGS="${SANITIZER_CXX_FLAGS}" \ + cmake -DBUILD_SHARED_LIBS:BOOL=OFF -DENABLE_PYTHON_INTERFACE:BOOL=OFF -DNO_BOOST:BOOL=ON ../src + + set +e # Do not exit if build fails because we need to display the log + make >> "${STP_LOG}" 2>&1 else - echo "No STP_VERSION given or empty" - exit 1 + echo "No STP_VERSION given or empty" + exit 1 fi # Only show build output if something went wrong to keep log output short if [ $? -ne 0 ]; then - echo "Build error" - cat "${STP_LOG}" + echo "Build error" + cat "${STP_LOG}" fi diff --git a/.travis/testing-utils.sh b/.travis/testing-utils.sh index 3d52457f..153a5546 100755 --- a/.travis/testing-utils.sh +++ b/.travis/testing-utils.sh @@ -18,11 +18,19 @@ if [ "${LLVM_VERSION}" != "2.9" ]; then cmake . make # Normally I wouldn't do something like this but hey we're running on a temporary virtual machine, so who cares? - sudo cp lib* /usr/lib/ - sudo cp -r include/gtest /usr/include + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + sudo cp lib* /usr/lib/ + sudo cp -r include/gtest /usr/include + elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + sudo cp lib* /usr/local/lib/ + sudo cp -r include/gtest /usr/local/include + else + echo "Unhandled TRAVIS_OS_NAME \"${TRAVIS_OS_NAME}\"" + exit 1 + fi else # LLVM2.9 on the other hand is a pain - + # We need the version of GoogleTest used in LLVM2.9 # This is a hack old_dir=`pwd` @@ -45,4 +53,3 @@ else cd "${old_dir}" fi - diff --git a/.travis/z3.sh b/.travis/z3.sh new file mode 100755 index 00000000..a4c00f82 --- /dev/null +++ b/.travis/z3.sh @@ -0,0 +1,20 @@ +#!/bin/bash -x + +# Make sure we exit if there is a failure +set -e + +source ${KLEE_SRC}/.travis/sanitizer_flags.sh +if [ "X${IS_SANITIZED_BUILD}" != "X0" ]; then + echo "Error: Requested Sanitized build but Z3 being used is not sanitized" + exit 1 +fi + +if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + # Should we install libz3-dbg too? + sudo apt-get -y install libz3 libz3-dev +elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + brew install z3 +else + echo "Unhandled TRAVIS_OS_NAME \"${TRAVIS_OS_NAME}\"" + exit 1 +fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 97c51a2e..ff55ad23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,13 @@ else() set(ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG "") endif() +if (("${CMAKE_VERSION}" VERSION_EQUAL "3.4") OR ("${CMAKE_VERSION}" VERSION_GREATER "3.4")) + # In CMake >= 3.4 ExternalProject_Add_Step() supports a `USES_TERMINAL` argument + set(EXTERNAL_PROJECT_ADD_STEP_USES_TERMINAL_ARG "USES_TERMINAL" "1") +else() + set(EXTERNAL_PROJECT_ADD_STEP_USES_TERMINAL_ARG "") +endif() + ################################################################################ # Sanity check - Disallow building in source. # Otherwise we would overwrite the Makefiles of the old build system. diff --git a/Dockerfile b/Dockerfile index d42b09c8..11174e6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,8 @@ ENV LLVM_VERSION=3.4 \ BUILD_DIR=/home/klee/klee_build \ USE_CMAKE=1 \ ASAN_BUILD=0 \ - UBSAN_BUILD=0 + UBSAN_BUILD=0 \ + TRAVIS_OS_NAME=linux RUN apt-get update && \ apt-get -y --no-install-recommends install \ diff --git a/README-CMake.md b/README-CMake.md index c2893004..2d438546 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -7,6 +7,7 @@ its autoconf/Makefile based build system. * `check` - Build and run all tests. * `clean` - Clean the build tree. Note this won't clean the runtime build. +* `clean_runtime` - Clean the runtime build tree. * `docs` - Build documentation * `edit_cache` - Show cmake/ccmake/cmake-gui interface for chaning configure options. * `help` - Show list of top level targets diff --git a/cmake/find_llvm.cmake b/cmake/find_llvm.cmake index 0df6b4b5..770fca84 100644 --- a/cmake/find_llvm.cmake +++ b/cmake/find_llvm.cmake @@ -86,7 +86,7 @@ else() "${LLVM_PACKAGE_VERSION}") else() # try x.y pattern - set(_llvm_version_regex "^([0-9]+)\\.([0-9]+)$") + set(_llvm_version_regex "^([0-9]+)\\.([0-9]+)(svn)?$") if ("${LLVM_PACKAGE_VERSION}" MATCHES "${_llvm_version_regex}") string(REGEX REPLACE "${_llvm_version_regex}" diff --git a/include/klee/CommandLine.h b/include/klee/CommandLine.h index cc186db7..6a72692d 100644 --- a/include/klee/CommandLine.h +++ b/include/klee/CommandLine.h @@ -29,6 +29,8 @@ extern llvm::cl::opt<bool> UseForkedCoreSolver; extern llvm::cl::opt<bool> CoreSolverOptimizeDivides; +extern llvm::cl::opt<bool> UseAssignmentValidatingSolver; + ///The different query logging solvers that can switched on/off enum QueryLoggingSolverType { diff --git a/include/klee/Solver.h b/include/klee/Solver.h index 2f613992..32c8cf9e 100644 --- a/include/klee/Solver.h +++ b/include/klee/Solver.h @@ -268,6 +268,12 @@ namespace klee { /// \param oracle - The solver to check query results against. Solver *createValidatingSolver(Solver *s, Solver *oracle); + /// createAssignmentValidatingSolver - Create a solver that when requested + /// for an assignment will check that the computed assignment satisfies + /// the Query. + /// \param s - The underlying solver to use. + Solver *createAssignmentValidatingSolver(Solver *s); + /// createCachingSolver - Create a solver which will cache the queries in /// memory (without eviction). /// diff --git a/include/klee/util/Assignment.h b/include/klee/util/Assignment.h index 5d8aa1ab..55e681de 100644 --- a/include/klee/util/Assignment.h +++ b/include/klee/util/Assignment.h @@ -46,6 +46,7 @@ namespace klee { ref<Expr> evaluate(const Array *mo, unsigned index) const; ref<Expr> evaluate(ref<Expr> e); + void createConstraintsFromAssignment(std::vector<ref<Expr> > &out) const; template<typename InputIterator> bool satisfies(InputIterator begin, InputIterator end); diff --git a/lib/Basic/CmdLineOptions.cpp b/lib/Basic/CmdLineOptions.cpp index e55c4550..82cb01b2 100644 --- a/lib/Basic/CmdLineOptions.cpp +++ b/lib/Basic/CmdLineOptions.cpp @@ -82,6 +82,10 @@ llvm::cl::list<QueryLoggingSolverType> queryLoggingOptions( llvm::cl::CommaSeparated ); +llvm::cl::opt<bool> + UseAssignmentValidatingSolver("debug-assignment-validating-solver", + llvm::cl::init(false)); + #ifdef ENABLE_METASMT #ifdef METASMT_DEFAULT_BACKEND_IS_BTOR diff --git a/lib/Basic/ConstructSolverChain.cpp b/lib/Basic/ConstructSolverChain.cpp index 68e1b08b..d00fcec1 100644 --- a/lib/Basic/ConstructSolverChain.cpp +++ b/lib/Basic/ConstructSolverChain.cpp @@ -37,6 +37,9 @@ Solver *constructSolverChain(Solver *coreSolver, baseSolverQuerySMT2LogPath.c_str()); } + if (UseAssignmentValidatingSolver) + solver = createAssignmentValidatingSolver(solver); + if (UseFastCexSolver) solver = createFastCexSolver(solver); diff --git a/lib/Expr/Assigment.cpp b/lib/Expr/Assigment.cpp index 635362d4..d788785a 100644 --- a/lib/Expr/Assigment.cpp +++ b/lib/Expr/Assigment.cpp @@ -22,4 +22,21 @@ void Assignment::dump() { llvm::errs() << "]\n"; } } + +void Assignment::createConstraintsFromAssignment( + std::vector<ref<Expr> > &out) const { + assert(out.size() == 0 && "out should be empty"); + for (bindings_ty::const_iterator it = bindings.begin(), ie = bindings.end(); + it != ie; ++it) { + const Array *array = it->first; + const std::vector<unsigned char> &values = it->second; + for (unsigned arrayIndex = 0; arrayIndex < array->size; ++arrayIndex) { + unsigned char value = values[arrayIndex]; + out.push_back(EqExpr::create( + ReadExpr::create(UpdateList(array, 0), + ConstantExpr::alloc(arrayIndex, array->getDomain())), + ConstantExpr::alloc(value, array->getRange()))); + } + } +} } diff --git a/lib/Solver/AssignmentValidatingSolver.cpp b/lib/Solver/AssignmentValidatingSolver.cpp new file mode 100644 index 00000000..a4d97f54 --- /dev/null +++ b/lib/Solver/AssignmentValidatingSolver.cpp @@ -0,0 +1,158 @@ +//===-- AssignmentValidatingSolver.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/util/Assignment.h" +#include "klee/Constraints.h" +#include "klee/Solver.h" +#include "klee/SolverImpl.h" +#include <vector> + +namespace klee { + +class AssignmentValidatingSolver : public SolverImpl { +private: + Solver *solver; + void dumpAssignmentQuery(const Query &query, const Assignment &assignment); + +public: + AssignmentValidatingSolver(Solver *_solver) : solver(_solver) {} + ~AssignmentValidatingSolver() { delete solver; } + + bool computeValidity(const Query &, Solver::Validity &result); + bool computeTruth(const Query &, bool &isValid); + bool computeValue(const Query &, ref<Expr> &result); + bool computeInitialValues(const Query &, + const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, + bool &hasSolution); + SolverRunStatus getOperationStatusCode(); + char *getConstraintLog(const Query &); + void setCoreSolverTimeout(double timeout); +}; + +// TODO: use computeInitialValues for all queries for more stress testing +bool AssignmentValidatingSolver::computeValidity(const Query &query, + Solver::Validity &result) { + return solver->impl->computeValidity(query, result); +} +bool AssignmentValidatingSolver::computeTruth(const Query &query, + bool &isValid) { + return solver->impl->computeTruth(query, isValid); +} +bool AssignmentValidatingSolver::computeValue(const Query &query, + ref<Expr> &result) { + return solver->impl->computeValue(query, result); +} + +bool AssignmentValidatingSolver::computeInitialValues( + const Query &query, const std::vector<const Array *> &objects, + std::vector<std::vector<unsigned char> > &values, bool &hasSolution) { + bool success = + solver->impl->computeInitialValues(query, objects, values, hasSolution); + if (!hasSolution) + return success; + + // Use `_allowFreeValues` so that if we are missing an assignment + // we can't compute a constant and flag this as a problem. + Assignment assignment(objects, values, /*_allowFreeValues=*/true); + // Check computed assignment satisfies query + for (ConstraintManager::const_iterator it = query.constraints.begin(), + ie = query.constraints.end(); + it != ie; ++it) { + ref<Expr> constraint = *it; + ref<Expr> constraintEvaluated = assignment.evaluate(constraint); + ConstantExpr *CE = dyn_cast<ConstantExpr>(constraintEvaluated); + if (CE == NULL) { + llvm::errs() << "Constraint did not evalaute to a constant:\n"; + llvm::errs() << "Constraint:\n" << constraint << "\n"; + llvm::errs() << "Evaluated Constraint:\n" << constraintEvaluated << "\n"; + llvm::errs() << "Assignment:\n"; + assignment.dump(); + dumpAssignmentQuery(query, assignment); + abort(); + } + if (CE->isFalse()) { + llvm::errs() << "Constraint evaluated to false when using assignment\n"; + llvm::errs() << "Constraint:\n" << constraint << "\n"; + llvm::errs() << "Assignment:\n"; + assignment.dump(); + dumpAssignmentQuery(query, assignment); + abort(); + } + } + + ref<Expr> queryExprEvaluated = assignment.evaluate(query.expr); + ConstantExpr *CE = dyn_cast<ConstantExpr>(queryExprEvaluated); + if (CE == NULL) { + llvm::errs() << "Query expression did not evalaute to a constant:\n"; + llvm::errs() << "Expression:\n" << query.expr << "\n"; + llvm::errs() << "Evaluated expression:\n" << queryExprEvaluated << "\n"; + llvm::errs() << "Assignment:\n"; + assignment.dump(); + dumpAssignmentQuery(query, assignment); + abort(); + } + // KLEE queries are validity queries. A counter example to + // ∀ x constraints(x) → query(x) + // exists therefore + // ¬∀ x constraints(x) → query(x) + // Which is equivalent to + // ∃ x constraints(x) ∧ ¬ query(x) + // This means for the assignment we get back query expression should evaluate + // to false. + if (CE->isTrue()) { + llvm::errs() + << "Query Expression evaluated to true when using assignment\n"; + llvm::errs() << "Expression:\n" << query.expr << "\n"; + llvm::errs() << "Assignment:\n"; + assignment.dump(); + dumpAssignmentQuery(query, assignment); + abort(); + } + + return success; +} + +void AssignmentValidatingSolver::dumpAssignmentQuery( + const Query &query, const Assignment &assignment) { + // Create a Query that is augmented with constraints that + // enforce the given assignment. + std::vector<ref<Expr> > constraints; + assignment.createConstraintsFromAssignment(constraints); + // Add Constraints from `query` + for (ConstraintManager::const_iterator it = query.constraints.begin(), + ie = query.constraints.end(); + it != ie; ++it) { + constraints.push_back(*it); + } + ConstraintManager augmentedConstraints(constraints); + Query augmentedQuery(augmentedConstraints, query.expr); + + // Ask the solver for the log for this query. + char *logText = solver->getConstraintLog(augmentedQuery); + llvm::errs() << "Query with assignment as constraints:\n" << logText << "\n"; + free(logText); +} + +SolverImpl::SolverRunStatus +AssignmentValidatingSolver::getOperationStatusCode() { + return solver->impl->getOperationStatusCode(); +} + +char *AssignmentValidatingSolver::getConstraintLog(const Query &query) { + return solver->impl->getConstraintLog(query); +} + +void AssignmentValidatingSolver::setCoreSolverTimeout(double timeout) { + return solver->impl->setCoreSolverTimeout(timeout); +} + +Solver *createAssignmentValidatingSolver(Solver *s) { + return new Solver(new AssignmentValidatingSolver(s)); +} +} diff --git a/lib/Solver/CMakeLists.txt b/lib/Solver/CMakeLists.txt index 1302db38..d9c393fb 100644 --- a/lib/Solver/CMakeLists.txt +++ b/lib/Solver/CMakeLists.txt @@ -7,6 +7,7 @@ # #===------------------------------------------------------------------------===# klee_add_component(kleaverSolver + AssignmentValidatingSolver.cpp CachingSolver.cpp CexCachingSolver.cpp ConstantDivision.cpp diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 1e680e5d..c90cbda0 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -111,10 +111,17 @@ ExternalProject_Add_Step(BuildKLEERuntimes RuntimeBuild COMMAND ${ENV_BINARY} MAKEFLAGS="" ${MAKE_BINARY} -f Makefile.cmake.bitcode all ALWAYS ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ${EXTERNAL_PROJECT_ADD_STEP_USES_TERMINAL_ARG} ) -# FIXME: Invoke `make clean` in the bitcode build system -# when the `clean` target is invoked. +# Target for cleaning the bitcode build system +# FIXME: Invoke `make clean` does not invoke this target. It's also weird +# that `ExternalProject` provides no way to do a clean. +add_custom_target(clean_runtime + COMMAND ${ENV_BINARY} MAKEFLAGS="" ${MAKE_BINARY} -f Makefile.cmake.bitcode clean + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} +) ############################################################################### # Runtime install diff --git a/runtime/Makefile.cmake.bitcode.rules b/runtime/Makefile.cmake.bitcode.rules index 8261ce99..2737eb80 100644 --- a/runtime/Makefile.cmake.bitcode.rules +++ b/runtime/Makefile.cmake.bitcode.rules @@ -70,8 +70,15 @@ else all:: build_at_level # Compute the directory to find sources -DIR_SUFFIX := $(subst $(RUNTIME_CMAKE_BINARY_DIR),,$(CURRENT_DIR)) +# Note: Use of $(realpath) is to resolve any symlinks +DIR_SUFFIX := $(subst $(realpath $(RUNTIME_CMAKE_BINARY_DIR)),,$(realpath $(CURRENT_DIR))) SRC_DIR := $(abspath $(ROOT_SRC)/$(DIR_SUFFIX)) +# Sanity check +ifeq ($(realpath $(SRC_DIR)),) +$(error SRC_DIR "$(SRC_DIR)" does not exist) +endif + +# Compute the directory to put build files LOCAL_BUILD_DIR := $(abspath $(ROOT_OBJ)/$(DIR_SUFFIX)) C_SRCS := $(shell echo $(SRC_DIR)/*.c) diff --git a/runtime/POSIX/stubs.c b/runtime/POSIX/stubs.c index b4f31bf7..bb528ad4 100644 --- a/runtime/POSIX/stubs.c +++ b/runtime/POSIX/stubs.c @@ -240,21 +240,27 @@ int strverscmp (__const char *__s1, __const char *__s2) { return strcmp(__s1, __s2); /* XXX no doubt this is bad */ } -unsigned int gnu_dev_major(unsigned long long int __dev) __attribute__((weak)); -unsigned int gnu_dev_major(unsigned long long int __dev) { +#if __GLIBC_PREREQ(2, 25) +#define gnu_dev_type dev_t +#else +#define gnu_dev_type unsigned long long int +#endif + +unsigned int gnu_dev_major(gnu_dev_type __dev) __attribute__((weak)); +unsigned int gnu_dev_major(gnu_dev_type __dev) { return ((__dev >> 8) & 0xfff) | ((unsigned int) (__dev >> 32) & ~0xfff); } -unsigned int gnu_dev_minor(unsigned long long int __dev) __attribute__((weak)); -unsigned int gnu_dev_minor(unsigned long long int __dev) { +unsigned int gnu_dev_minor(gnu_dev_type __dev) __attribute__((weak)); +unsigned int gnu_dev_minor(gnu_dev_type __dev) { return (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff); } -unsigned long long int gnu_dev_makedev(unsigned int __major, unsigned int __minor) __attribute__((weak)); -unsigned long long int gnu_dev_makedev(unsigned int __major, unsigned int __minor) { +gnu_dev_type gnu_dev_makedev(unsigned int __major, unsigned int __minor) __attribute__((weak)); +gnu_dev_type gnu_dev_makedev(unsigned int __major, unsigned int __minor) { return ((__minor & 0xff) | ((__major & 0xfff) << 8) - | (((unsigned long long int) (__minor & ~0xff)) << 12) - | (((unsigned long long int) (__major & ~0xfff)) << 32)); + | (((gnu_dev_type) (__minor & ~0xff)) << 12) + | (((gnu_dev_type) (__major & ~0xfff)) << 32)); } char *canonicalize_file_name (const char *name) __attribute__((weak)); diff --git a/test/lit.cfg b/test/lit.cfg index dd2fbc13..8f399642 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1,4 +1,6 @@ # -*- Python -*- +# vim: set filetype=python: +# vim: ts=2:sts=2:sw=2:et:tw=80: # Configuration file for the 'lit' test runner. @@ -8,10 +10,10 @@ import re import platform try: - import lit.util - import lit.formats + import lit.util + import lit.formats except ImportError: - pass + pass # name: The name of this test suite. config.name = 'KLEE' @@ -31,27 +33,33 @@ klee_obj_root = getattr(config, 'klee_obj_root', None) klee_src_root = getattr(config, 'klee_src_root', None) if klee_obj_root is not None: - config.test_exec_root = os.path.join(klee_obj_root, 'test') + config.test_exec_root = os.path.join(klee_obj_root, 'test') # Tweak the PATH to include the tool dir. 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!') + klee_tools_dir = getattr(config, 'klee_tools_dir', None) + if not klee_tools_dir: + lit.fatal('No KLEE tools dir set!') - # 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!') + # 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 + path = os.path.pathsep.join( + ( + llvm_tools_dir, + klee_tools_dir, + config.environment['PATH'] + ) + ) + config.environment['PATH'] = path # Propogate some environment variable to test environment. def addEnv(name): - if name in os.environ: - config.environment[name] = os.environ[name] + if name in os.environ: + config.environment[name] = os.environ[name] addEnv('HOME') addEnv('PWD') @@ -72,27 +80,37 @@ 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!') + lit.fatal('test execution root not set!') # Add substitutions from lit.site.cfg subs = [ 'llvmgcc', 'llvmgxx', 'cc', 'cxx'] 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)) + value = getattr(config, name, None) + if value == None: + lit.fatal('{0} is not set'.format(name)) + config.substitutions.append( ('%' + name, value)) # Add a substitution for lli. -config.substitutions.append( ('%lli', os.path.join(llvm_tools_dir, 'lli')) ) +config.substitutions.append( + ('%lli', os.path.join(llvm_tools_dir, 'lli')) +) # Add a substitution for llvm-as -config.substitutions.append( ('%llvmas', os.path.join(llvm_tools_dir, 'llvm-as')) ) +config.substitutions.append( + ('%llvmas', os.path.join(llvm_tools_dir, 'llvm-as')) +) # Add a substitution for llvm-ar -config.substitutions.append( ('%llvmar', os.path.join(llvm_tools_dir, 'llvm-ar')) ) +config.substitutions.append( + ('%llvmar', os.path.join(llvm_tools_dir, 'llvm-ar')) +) # Add a substition for libkleeruntest -config.substitutions.append( ('%libkleeruntestdir', os.path.dirname(config.libkleeruntest)) ) -config.substitutions.append( ('%libkleeruntest', config.libkleeruntest) ) +config.substitutions.append( + ('%libkleeruntestdir', os.path.dirname(config.libkleeruntest)) +) +config.substitutions.append( + ('%libkleeruntest', config.libkleeruntest) +) # Get KLEE and Kleaver specific parameters passed on llvm-lit cmd line # e.g. llvm-lit --param klee_opts=--help @@ -106,9 +124,13 @@ else: 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)) + 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)) + 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), @@ -116,17 +138,23 @@ subs = [ ('%kleaver', 'kleaver', kleaver_extra_params), ('%ktest-tool', 'ktest-tool', '') ] for s,basename,extra_args in subs: - config.substitutions.append( ( s, - "{0} {1}".format( os.path.join(klee_tools_dir, basename), extra_args ).strip() - ) - ) - -config.substitutions.append( ('%gentmp', os.path.join(klee_src_root, 'scripts/genTempFiles.sh')) ) + config.substitutions.append( + ( s, + "{0} {1}".format( + os.path.join(klee_tools_dir, basename), + extra_args + ).strip() + ) + ) + +config.substitutions.append( + ('%gentmp', os.path.join(klee_src_root, 'scripts/genTempFiles.sh')) +) # LLVM < 3.0 doesn't Support %T directive if int(config.llvm_version_major) == 2: - # This is a hack - config.substitutions.append(('%T','Output')) + # This is a hack + config.substitutions.append(('%T','Output')) # Add feature for the LLVM version in use, so it can be tested in REQUIRES and # XFAIL checks. We also add "not-XXX" variants, for the same reason. @@ -135,8 +163,12 @@ current_llvm_version = "%s.%s" % (config.llvm_version_major, config.llvm_version_minor) config.available_features.add("llvm-" + current_llvm_version) for version in known_llvm_versions: - if version != current_llvm_version: - config.available_features.add("not-llvm-" + version) + if version != current_llvm_version: + config.available_features.add("not-llvm-" + version) + if current_llvm_version >= version: + config.available_features.add("geq-llvm-" + version) + else: + config.available_features.add("lt-llvm-" + version) # Solver features if config.enable_stp: |