From 8087d7fb20df3610a75bf3bea71e7d6de7a10766 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Mon, 12 Aug 2024 22:58:44 +0200 Subject: [PATCH 01/40] wip: --- .github/workflows/build.yaml | 24 +- CMakeLists.txt | 12 +- Dockerfile | 2 +- build.sh | 6 +- include/klee/Expr/Expr.h | 8 +- include/klee/Solver/IncompleteSolver.h | 2 +- include/klee/Solver/Solver.h | 3 +- include/klee/Solver/SolverCmdLine.h | 12 +- include/klee/Solver/SolverImpl.h | 4 +- include/klee/Support/OptionCategories.h | 5 + include/klee/Support/PrintContext.h | 12 +- lib/Core/AddressSpace.h | 2 + lib/Core/ExecutionState.h | 1 + lib/Core/Executor.cpp | 224 ++++++++++---- lib/Core/Executor.h | 25 +- lib/Core/ExternalDispatcher.cpp | 21 +- lib/Core/GetElementPtrTypeIterator.h | 23 +- lib/Core/Memory.cpp | 1 + lib/Core/Memory.h | 1 + lib/Core/MemoryManager.cpp | 6 +- lib/Core/SeedInfo.cpp | 12 +- lib/Core/SpecialFunctionHandler.cpp | 61 ++-- lib/Core/SpecialFunctionHandler.h | 31 -- lib/Core/StatsTracker.cpp | 6 +- lib/Core/TargetedExecutionManager.cpp | 6 +- lib/Core/TimingSolver.h | 3 +- lib/Core/UserSearcher.cpp | 4 +- lib/Expr/Expr.cpp | 29 +- lib/Module/CMakeLists.txt | 14 +- lib/Module/FunctionAlias.cpp | 9 +- lib/Module/Instrument.cpp | 19 ++ lib/Module/InstrumentLegacy.cpp | 160 ++++++++++ lib/Module/IntrinsicCleaner.cpp | 19 +- lib/Module/KModule.cpp | 170 ++--------- lib/Module/LowerSwitch.cpp | 12 +- lib/Module/ModuleHelper.h | 46 +++ lib/Module/Optimize.cpp | 245 +-------------- lib/Module/OptimizeLegacy.cpp | 278 ++++++++++++++++++ lib/Module/RaiseAsm.cpp | 6 + lib/Solver/AlphaEquivalenceSolver.cpp | 4 +- lib/Solver/AssignmentValidatingSolver.cpp | 9 +- lib/Solver/BitwuzlaSolver.cpp | 4 +- lib/Solver/CachingSolver.cpp | 4 +- lib/Solver/CexCachingSolver.cpp | 24 +- lib/Solver/ConcretizingSolver.cpp | 4 +- lib/Solver/IncompleteSolver.cpp | 2 +- lib/Solver/IndependentSolver.cpp | 4 +- lib/Solver/MetaSMTSolver.cpp | 11 +- lib/Solver/MetaSMTSolver.h | 2 +- lib/Solver/QueryLoggingSolver.cpp | 2 +- lib/Solver/QueryLoggingSolver.h | 2 +- lib/Solver/STPSolver.cpp | 11 +- lib/Solver/STPSolver.h | 2 +- lib/Solver/Solver.cpp | 2 +- lib/Solver/SolverCmdLine.cpp | 15 +- lib/Solver/ValidatingSolver.cpp | 4 +- lib/Solver/Z3Solver.cpp | 31 +- lib/Solver/Z3Solver.h | 4 + runtime/POSIX/fd.c | 38 +-- runtime/Sanitizer/ubsan/ubsan_checks.inc | 10 - runtime/Sanitizer/ubsan/ubsan_handlers.cpp | 28 -- runtime/klee-libc/memchr.c | 5 +- scripts/build/p-clang-linux-ubuntu-22.04.inc | 4 - scripts/build/p-klee.inc | 1 + scripts/build/patches/llvm90.patch | 114 ------- test/ArrayOpt/test_feasible.c | 1 + test/CXX/LandingPad.cpp | 2 + test/CXX/symex/libc++/atexit.cpp | 2 +- test/CXX/symex/libc++/can_catch_test.cpp | 2 +- test/CXX/symex/libc++/catch_recover.cpp | 2 +- .../catch_with_adjusted_exception_pointer.cpp | 2 +- test/CXX/symex/libc++/cout.cpp | 2 +- test/CXX/symex/libc++/cout_sym.cpp | 2 +- test/CXX/symex/libc++/dynamic_cast.cpp | 2 +- test/CXX/symex/libc++/exception.cpp | 2 +- .../symex/libc++/exception_inheritance.cpp | 2 +- test/CXX/symex/libc++/general_catch.cpp | 2 +- test/CXX/symex/libc++/landingpad.cpp | 2 +- test/CXX/symex/libc++/multi_throw.cpp | 2 +- test/CXX/symex/libc++/multi_unwind.cpp | 2 +- test/CXX/symex/libc++/nested.cpp | 2 +- test/CXX/symex/libc++/nested_fail.cpp | 4 +- test/CXX/symex/libc++/rethrow.cpp | 2 +- test/CXX/symex/libc++/simple_exception.cpp | 2 +- .../symex/libc++/simple_exception_fail.cpp | 4 +- test/CXX/symex/libc++/symbolic_exception.cpp | 2 +- test/CXX/symex/libc++/throw_specifiers.cpp | 2 +- .../libc++/throwing_exception_destructor.cpp | 2 +- test/CXX/symex/libc++/uncaught_exception.cpp | 2 +- test/CXX/symex/libc++/vector.cpp | 2 +- test/lit.cfg | 15 +- test/lit.site.cfg.in | 5 +- tools/kleaver/main.cpp | 6 +- tools/klee/main.cpp | 33 +-- unittests/Ref/RefTest.cpp | 3 + unittests/Solver/Z3SolverTest.cpp | 5 +- 96 files changed, 1030 insertions(+), 955 deletions(-) create mode 100644 lib/Module/Instrument.cpp create mode 100644 lib/Module/InstrumentLegacy.cpp create mode 100644 lib/Module/ModuleHelper.h create mode 100644 lib/Module/OptimizeLegacy.cpp delete mode 100644 scripts/build/patches/llvm90.patch diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index adf65c7c58..ca9bd0411e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -17,7 +17,7 @@ env: ENABLE_DOXYGEN: 0 ENABLE_OPTIMIZED: 1 ENABLE_DEBUG: 1 - ENABLE_WARNINGS_AS_ERRORS: 1 + ENABLE_WARNINGS_AS_ERRORS: 0 GTEST_VERSION: 1.11.0 KLEE_RUNTIME_BUILD: "Debug+Asserts" LLVM_VERSION: 11 @@ -26,7 +26,7 @@ env: SOLVERS: BITWUZLA:Z3:STP STP_VERSION: 2.3.3 TCMALLOC_VERSION: 2.9.1 - UCLIBC_VERSION: klee_uclibc_v1.3 + UCLIBC_VERSION: klee_uclibc_v1.4 USE_TCMALLOC: 1 USE_LIBCXX: 1 Z3_VERSION: 4.8.15 @@ -41,12 +41,12 @@ jobs: strategy: matrix: name: [ + "LLVM 16", + "LLVM 15", "LLVM 14", "LLVM 13", "LLVM 12", "LLVM 11, Doxygen", - "LLVM 10", - "LLVM 9", "ASan", "UBSan", "MSan", @@ -59,6 +59,12 @@ jobs: "No TCMalloc, optimised runtime", ] include: + - name: "LLVM 16" + env: + LLVM_VERSION: 16 + - name: "LLVM 15" + env: + LLVM_VERSION: 15 - name: "LLVM 14" env: LLVM_VERSION: 14 @@ -72,12 +78,6 @@ jobs: env: LLVM_VERSION: 11 ENABLE_DOXYGEN: 1 - - name: "LLVM 10" - env: - LLVM_VERSION: 10 - - name: "LLVM 9" - env: - LLVM_VERSION: 9 # Sanitizer builds. Do unoptimized build otherwise the optimizer # might remove problematic code - name: "ASan" @@ -133,6 +133,10 @@ jobs: SOLVERS: STP USE_TCMALLOC: 0 KLEE_RUNTIME_BUILD: "Release+Debug+Asserts" + # Check we can build without warnings + - name: "Warnings as errors" + env: + ENABLE_WARNINGS_AS_ERRORS: 1 steps: - name: Checkout KLEE source code uses: actions/checkout@v3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 086d250f4e..e4e4836058 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ project(KLEE CXX C) # Project version ############################################################################### set(KLEE_VERSION_MAJOR 3) -set(KLEE_VERSION_MINOR 0) +set(KLEE_VERSION_MINOR 1) set(KLEE_VERSION "${KLEE_VERSION_MAJOR}.${KLEE_VERSION_MINOR}") # If a patch is needed, we can add KLEE_VERSION_PATCH @@ -317,6 +317,16 @@ if (NOT SQLite3_FOUND) message( FATAL_ERROR "SQLite3 not found, please install" ) endif() +find_program( + SQLITE_CLI + NAMES "sqlite3" + DOC "Path to sqlite3 tool" +) + +if (NOT SQLITE_CLI) + set(SQLITE_CLI "") +endif() + ################################################################################ # Detect libcap ################################################################################ diff --git a/Dockerfile b/Dockerfile index 1376b91664..7055a9d77b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,7 @@ ENV ENABLE_DOXYGEN=1 ENV ENABLE_OPTIMIZED=1 ENV ENABLE_DEBUG=1 ENV DISABLE_ASSERTIONS=0 -ENV ENABLE_WARNINGS_AS_ERRORS=0 +ENV ENABLE_WARNINGS_AS_ERRORS=1 ENV REQUIRES_RTTI=0 ENV SOLVERS=STP:Z3 ENV GTEST_VERSION=1.11.0 diff --git a/build.sh b/build.sh index 01bb2c376e..e4ef6de75f 100755 --- a/build.sh +++ b/build.sh @@ -31,6 +31,7 @@ ENABLE_OPTIMIZED=1 ENABLE_DEBUG=0 DISABLE_ASSERTIONS=1 REQUIRES_RTTI=1 +ENABLE_WARNINGS_AS_ERRORS=1 ## Solvers Required options # SOLVERS=STP @@ -46,7 +47,7 @@ JSON_VERSION=v3.11.3 IMMER_VERSION=v0.8.1 ## UClibC Required options -UCLIBC_VERSION=klee_uclibc_v1.3 +UCLIBC_VERSION=klee_uclibc_v1.4 # LLVM_VERSION is also required for UClibC ## Z3 Required options @@ -64,12 +65,11 @@ if [ "$1" = "--debug" ] || [ "$1" = "-g" ]; then ENABLE_OPTIMIZED=0 ENABLE_DEBUG=1 KLEE_RUNTIME_BUILD="Debug+Asserts" + ENABLE_WARNINGS_AS_ERRORS=0 shift 1 else KEEP_PARSE="false" fi done -ENABLE_WARNINGS_AS_ERRORS=0 - BASE="$BASE" BUILD_SUFFIX="$BUILD_SUFFIX" KLEE_RUNTIME_BUILD=$KLEE_RUNTIME_BUILD COVERAGE=$COVERAGE ENABLE_DOXYGEN=$ENABLE_DOXYGEN USE_TCMALLOC=$USE_TCMALLOC USE_LIBCXX=$USE_LIBCXX LLVM_VERSION=$LLVM_VERSION ENABLE_OPTIMIZED=$ENABLE_OPTIMIZED ENABLE_DEBUG=$ENABLE_DEBUG DISABLE_ASSERTIONS=$DISABLE_ASSERTIONS REQUIRES_RTTI=$REQUIRES_RTTI SOLVERS=$SOLVERS GTEST_VERSION=$GTEST_VERSION UCLIBC_VERSION=$UCLIBC_VERSION STP_VERSION=$STP_VERSION MINISAT_VERSION=$MINISAT_VERSION Z3_VERSION=$Z3_VERSION BITWUZLA_VERSION=$BITWUZLA_VERSION SQLITE_VERSION=$SQLITE_VERSION JSON_VERSION=$JSON_VERSION IMMER_VERSION=$IMMER_VERSION SANITIZER_BUILD=$SANITIZER_BUILD SANITIZER_LLVM_VERSION=$SANITIZER_LLVM_VERSION ENABLE_WARNINGS_AS_ERRORS=$ENABLE_WARNINGS_AS_ERRORS ./scripts/build/build.sh klee --install-system-deps diff --git a/include/klee/Expr/Expr.h b/include/klee/Expr/Expr.h index 55bf4755ec..02d7cf3614 100644 --- a/include/klee/Expr/Expr.h +++ b/include/klee/Expr/Expr.h @@ -1592,7 +1592,13 @@ class ConstantExpr : public Expr { } /// isAllOnes - Is this constant all ones. - bool isAllOnes() const { return getAPValue().isAllOnesValue(); } + bool isAllOnes() const { +#if LLVM_VERSION_CODE <= LLVM_VERSION(13, 0) + return getAPValue().isAllOnesValue(); +#else + return getAPValue().isAllOnes(); +#endif + } bool isFloat() const { return mIsFloat; } diff --git a/include/klee/Solver/IncompleteSolver.h b/include/klee/Solver/IncompleteSolver.h index e977569fd1..3bf6a2e192 100644 --- a/include/klee/Solver/IncompleteSolver.h +++ b/include/klee/Solver/IncompleteSolver.h @@ -78,7 +78,7 @@ class StagedSolverImpl : public SolverImpl { bool computeValidityCore(const Query &query, ValidityCore &validityCore, bool &hasSolution); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); }; diff --git a/include/klee/Solver/Solver.h b/include/klee/Solver/Solver.h index 12702c8937..addb9f55c6 100644 --- a/include/klee/Solver/Solver.h +++ b/include/klee/Solver/Solver.h @@ -17,6 +17,7 @@ #include "klee/System/Time.h" #include +#include #include namespace klee { @@ -189,7 +190,7 @@ class Solver { virtual std::pair, ref> getRange(const Query &, time::Span timeout = time::Span()); - virtual char *getConstraintLog(const Query &query); + virtual std::string getConstraintLog(const Query &query); virtual void setCoreSolverTimeout(time::Span timeout); /// @brief Notify the solver that the state with specified id has been diff --git a/include/klee/Solver/SolverCmdLine.h b/include/klee/Solver/SolverCmdLine.h index 874eced979..ba389a34dc 100644 --- a/include/klee/Solver/SolverCmdLine.h +++ b/include/klee/Solver/SolverCmdLine.h @@ -17,6 +17,8 @@ #include "llvm/Support/CommandLine.h" +#include + namespace klee { extern llvm::cl::opt UseFastCexSolver; @@ -92,12 +94,12 @@ extern llvm::cl::opt MetaSMTBackend; class KCommandLine { public: - /// Hide all options in the specified category - static void HideOptions(llvm::cl::OptionCategory &Category); - - /// Hide all options except the ones in the specified category - static void HideUnrelatedOptions(llvm::cl::OptionCategory &Category); + /// Keep only the options in the provided categories, + /// together with --help, --help-list, --version and --color + static void + KeepOnlyCategories(std::set const &categories); }; + } // namespace klee #endif /* KLEE_SOLVERCMDLINE_H */ diff --git a/include/klee/Solver/SolverImpl.h b/include/klee/Solver/SolverImpl.h index bbdd262832..016711ba4d 100644 --- a/include/klee/Solver/SolverImpl.h +++ b/include/klee/Solver/SolverImpl.h @@ -115,9 +115,9 @@ class SolverImpl { /// status code static const char *getOperationStatusString(SolverRunStatus statusCode); - virtual char *getConstraintLog(const Query &) { + virtual std::string getConstraintLog(const Query &query) { // dummy - return nullptr; + return {}; } virtual void setCoreSolverTimeout(time::Span) {} diff --git a/include/klee/Support/OptionCategories.h b/include/klee/Support/OptionCategories.h index 773800edfe..834c743ac6 100644 --- a/include/klee/Support/OptionCategories.h +++ b/include/klee/Support/OptionCategories.h @@ -20,10 +20,15 @@ namespace klee { extern llvm::cl::OptionCategory TestCompCat; extern llvm::cl::OptionCategory ExecCat; extern llvm::cl::OptionCategory DebugCat; +extern llvm::cl::OptionCategory ExprCat; +extern llvm::cl::OptionCategory ExtCallsCat; +extern llvm::cl::OptionCategory MemoryCat; extern llvm::cl::OptionCategory MiscCat; extern llvm::cl::OptionCategory ModuleCat; +extern llvm::cl::OptionCategory SearchCat; extern llvm::cl::OptionCategory SeedingCat; extern llvm::cl::OptionCategory SolvingCat; +extern llvm::cl::OptionCategory StatsCat; extern llvm::cl::OptionCategory TerminationCat; extern llvm::cl::OptionCategory TestGenCat; } // namespace klee diff --git a/include/klee/Support/PrintContext.h b/include/klee/Support/PrintContext.h index 74024f5a4d..48476d0b50 100644 --- a/include/klee/Support/PrintContext.h +++ b/include/klee/Support/PrintContext.h @@ -30,9 +30,9 @@ class PrintContext { std::string newline; /// This is used to keep track of the stack of indentations used by - /// \sa breakLineI() - /// \sa pushIndent() - /// \sa popIndent() + /// \sa breakLineI() + /// \sa pushIndent() + /// \sa popIndent() std::stack indentStack; public: @@ -54,14 +54,14 @@ class PrintContext { } /// Break line using the indent on the top of the indent stack - /// \return The PrintContext object so the method is chainable + /// \return The PrintContext object so the method is chainable PrintContext &breakLineI() { breakLine(indentStack.top()); return *this; } /// Add the current position on the line to the top of the indent stack - /// \return The PrintContext object so the method is chainable + /// \return The PrintContext object so the method is chainable PrintContext &pushIndent() { indentStack.push(pos); return *this; @@ -70,7 +70,7 @@ class PrintContext { llvm::raw_ostream &getStream() { return os; } /// Pop the top off the indent stack - /// \return The PrintContext object so the method is chainable + /// \return The PrintContext object so the method is chainable PrintContext &popIndent() { indentStack.pop(); return *this; diff --git a/lib/Core/AddressSpace.h b/lib/Core/AddressSpace.h index bb844561c4..6d92f6594f 100644 --- a/lib/Core/AddressSpace.h +++ b/lib/Core/AddressSpace.h @@ -175,6 +175,8 @@ class AddressSpace { /// @param mo The MemoryObject to update /// @param os The associated memory state containing the actual data /// @param src_address the address to copy from + /// @param concretize fully concretize the object representation if changed + /// externally /// @return bool copyInConcrete(const MemoryObject *mo, const ObjectState *os, uint64_t src_address, const Assignment &assignment); diff --git a/lib/Core/ExecutionState.h b/lib/Core/ExecutionState.h index 29b49b62b7..54728a5e25 100644 --- a/lib/Core/ExecutionState.h +++ b/lib/Core/ExecutionState.h @@ -60,6 +60,7 @@ struct KInstruction; class MemoryObject; class PTreeNode; class Target; +struct InstructionInfo; llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const MemoryMap &mm); diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 9c37230634..81db1fcd7d 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -91,15 +91,22 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" -#include "llvm/Support/Casting.h" +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) +#include "llvm/IR/GetElementPtrTypeIterator.h" +#endif #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/TypeSize.h" #include "llvm/Support/raw_ostream.h" #include #include +#include +#include +#include +#include #include #include #include @@ -306,9 +313,11 @@ cl::opt OnlyOutputMakeSymbolicArrays( /*** External call policy options ***/ enum class ExternalCallPolicy { - None, // No external calls allowed - Concrete, // Only external calls with concrete arguments allowed - All, // All external calls allowed + None, // No external calls allowed + Concrete, // Only external calls with concrete arguments allowed + All, // All external calls allowed, symbolic arguments concretized + OverApprox, // All external calls allowed, symbolic inputs are not constrained + // by the call }; cl::opt ExternalCalls( @@ -324,19 +333,29 @@ cl::opt ExternalCalls( "allowed (default)"), clEnumValN(ExternalCallPolicy::All, "all", "All external function calls are allowed. This concretizes " - "any symbolic arguments in calls to external functions.")), + "any symbolic arguments in calls to external functions."), + clEnumValN(ExternalCallPolicy::OverApprox, "over-approx", + "All external function calls are allowed. This concretizes " + "any symbolic arguments in calls to external functions but" + "the concretization is ignored after the call (see docs).")), cl::init(ExternalCallPolicy::Concrete), cl::cat(ExtCallsCat)); -cl::opt SuppressExternalWarnings( - "suppress-external-warnings", cl::init(false), - cl::desc("Supress warnings about calling external functions."), - cl::cat(ExtCallsCat)); +/*** External call warnings options ***/ + +enum class ExtCallWarnings { + None, // Never warn on external calls + OncePerFunction, // Only warn once per function on external calls + All, // Always warn on external calls +}; -cl::opt AllExternalWarnings( - "all-external-warnings", cl::init(false), - cl::desc("Issue a warning everytime an external call is made, " - "as opposed to once per function (default=false)"), - cl::cat(ExtCallsCat)); +cl::opt ExternalCallWarnings( + "external-call-warnings", + cl::desc("Specify when to warn about external calls"), + cl::values(clEnumValN(ExtCallWarnings::None, "none", "Never warn"), + clEnumValN(ExtCallWarnings::OncePerFunction, "once-per-function", + "Warn once per external function (default)"), + clEnumValN(ExtCallWarnings::All, "all", "Always warn")), + cl::init(ExtCallWarnings::OncePerFunction), cl::cat(ExtCallsCat)); /*** Seeding options ***/ @@ -1725,20 +1744,18 @@ ref Executor::toUnique(const ExecutionState &state, ref e) { return result; } -/* Concretize the given expression, and return a possible constant value. - 'reason' is just a documentation string stating the reason for - concretization. */ ref Executor::toConstant(ExecutionState &state, ref e, - const char *reason) { + const std::string &reason) { e = Simplificator::simplifyExpr(state.constraints.cs(), e).simplified; if (ConstantExpr *CE = dyn_cast(e)) return CE; - ref value; - bool success = - solver->getValue(state.constraints.cs(), e, value, state.queryMetaData); - assert(success && "FIXME: Unhandled solver failure"); - (void)success; + ref value = getValueFromSeeds(state, e); + if (!value) { + [[maybe_unused]] bool success = + solver->getValue(state.constraints.cs(), e, value, state.queryMetaData); + assert(success && "FIXME: Unhandled solver failure"); + } std::string str; llvm::raw_string_ostream os(str); @@ -1746,16 +1763,29 @@ ref Executor::toConstant(ExecutionState &state, ref e, << " to value " << value << " (" << state.pc->getSourceFilepath() << ":" << state.pc->getLine() << ")"; - if (AllExternalWarnings) + if (ExternalCallWarnings == ExtCallWarnings::All) klee_warning("%s", os.str().c_str()); else - klee_warning_once(reason, "%s", os.str().c_str()); - - addConstraint(state, EqExpr::create(e, value)); + klee_warning_once(reason.c_str(), "%s", os.str().c_str()); return value; } +ref Executor::getValueFromSeeds(ExecutionState &state, + ref e) { + auto found = seedMap->find(&state); + if (found == seedMap->end()) + return nullptr; + + auto seeds = found->second; + for (auto const &seed : seeds) { + auto value = seed.assignment.evaluate(e); + if (isa(value)) + return value; + } + return nullptr; +} + ref Executor::toConstantPointer(ExecutionState &state, ref e, const char *reason) { @@ -1775,7 +1805,7 @@ Executor::toConstantPointer(ExecutionState &state, ref e, << " to value " << pointer << " (" << state.pc->getSourceFilepath() << ":" << state.pc->getLine() << ")"; - if (AllExternalWarnings) + if (ExternalCallWarnings == ExtCallWarnings::All) klee_warning("%s", os.str().c_str()); else klee_warning_once(reason, "%s", os.str().c_str()); @@ -2558,12 +2588,8 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, argWidth = arguments[k]->getWidth(); } -#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0) MaybeAlign ma = cb.getParamAlign(k); unsigned alignment = ma ? ma->value() : 0; -#else - unsigned alignment = cb.getParamAlignment(k); -#endif if (WordSize == Expr::Int32 && !alignment) alignment = 4; @@ -2815,7 +2841,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { unwindToNextLandingpad(state); } else { // a clause (or a catch-all clause or filter clause) matches: - // remember the stack index and switch to cleanup phase + // remember the stack index and switch to clean-up phase state.unwindingInformation = std::make_unique( sui->exceptionObject, cast(result), @@ -3201,8 +3227,12 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { if (f) { const FunctionType *fType = f->getFunctionType(); +#if LLVM_VERSION_MAJOR >= 15 + const FunctionType *fpType = cb.getFunctionType(); +#else const FunctionType *fpType = dyn_cast(fp->getType()->getPointerElementType()); +#endif // special case the call with a bitcast case if (fType != fpType) { @@ -3804,7 +3834,11 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { llvm::APFloat Arg(*fpWidthToSemantics(arg->getWidth()), arg->getAPValue()); uint64_t value = 0; bool isExact = true; +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + auto valueRef = llvm::MutableArrayRef(value); +#else auto valueRef = makeMutableArrayRef(value); +#endif Arg.convertToInteger(valueRef, resultType, false, llvm::APFloat::rmTowardZero, &isExact); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); @@ -3822,7 +3856,11 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { uint64_t value = 0; bool isExact = true; +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + auto valueRef = llvm::MutableArrayRef(value); +#else auto valueRef = makeMutableArrayRef(value); +#endif Arg.convertToInteger(valueRef, resultType, true, llvm::APFloat::rmTowardZero, &isExact); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); @@ -4188,11 +4226,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { return; } uint64_t iIdx = cIdx->getZExtValue(); -#if LLVM_VERSION_MAJOR >= 11 const auto *vt = cast(iei->getType()); -#else - const llvm::VectorType *vt = iei->getType(); -#endif unsigned EltBits = getWidthForLLVMType(vt->getElementType()); if (iIdx >= vt->getNumElements()) { @@ -4231,11 +4265,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { return; } uint64_t iIdx = cIdx->getZExtValue(); -#if LLVM_VERSION_MAJOR >= 11 const auto *vt = cast(eei->getVectorOperandType()); -#else - const llvm::VectorType *vt = eei->getVectorOperandType(); -#endif unsigned EltBits = getWidthForLLVMType(vt->getElementType()); if (iIdx >= vt->getNumElements()) { @@ -4361,10 +4391,17 @@ template void Executor::computeOffsetsSeqTy(KGEPInstruction *kgepi, ref &constantOffset, uint64_t index, const TypeIt it) { +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) assert(it->getNumContainedTypes() == 1 && "Sequential type must contain one subtype"); uint64_t elementSize = kmodule->targetData->getTypeStoreSize(it->getContainedType(0)); +#else + assert(it.isSequential() && "Called with non-sequential type"); + // Get the size of a single element + std::uint64_t elementSize = + kmodule->targetData->getTypeStoreSize(it.getIndexedType()); +#endif const Value *operand = it.getOperand(); if (const Constant *c = dyn_cast(operand)) { auto expr = evalConstant(c, llvm::APFloat::rmNearestTiesToEven); @@ -4395,13 +4432,21 @@ void Executor::computeOffsets(KGEPInstruction *kgepi, TypeIt ib, TypeIt ie) { ConstantExpr::alloc(0, Context::get().getPointerWidth()); uint64_t index = 1; for (TypeIt ii = ib; ii != ie; ++ii) { +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) if (StructType *st = dyn_cast(*ii)) { +#else + if (StructType *st = ii.getStructTypeOrNull()) { +#endif const StructLayout *sl = kmodule->targetData->getStructLayout(st); const ConstantInt *ci = cast(ii.getOperand()); uint64_t addend = sl->getElementOffset((unsigned)ci->getZExtValue()); constantOffset = constantOffset->Add( ConstantExpr::alloc(addend, Context::get().getPointerWidth())); +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) } else if (ii->isArrayTy() || ii->isVectorTy() || ii->isPointerTy()) { +#else + } else if (ii.isSequential()) { +#endif computeOffsetsSeqTy(kgepi, constantOffset, index, ii); } else assert("invalid type" && 0); @@ -4413,15 +4458,55 @@ void Executor::computeOffsets(KGEPInstruction *kgepi, TypeIt ib, TypeIt ie) { void Executor::bindInstructionConstants(KInstruction *KI) { if (GetElementPtrInst *gepi = dyn_cast(KI->inst())) { KGEPInstruction *kgepi = static_cast(KI); - computeOffsets(kgepi, gep_type_begin(gepi), gep_type_end(gepi)); +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) + computeOffsets(kgepi, klee::gep_type_begin(gepi), klee::gep_type_end(gepi)); +#else + computeOffsets(kgepi, llvm::gep_type_begin(gepi), llvm::gep_type_end(gepi)); +#endif } else if (InsertValueInst *ivi = dyn_cast(KI->inst())) { KGEPInstruction *kgepi = static_cast(KI); - computeOffsets(kgepi, iv_type_begin(ivi), iv_type_end(ivi)); - assert(kgepi->indices.empty() && "InsertValue constant offset expected"); + llvm::Value *agg = ivi->getAggregateOperand(); + llvm::Type *current_type = agg->getType(); + std::uint64_t offset = 0; + for (auto index : ivi->indices()) { + if (StructType *st = dyn_cast(current_type)) { + const StructLayout *sl = kmodule->targetData->getStructLayout(st); + std::uint64_t addend = sl->getElementOffset(index); + offset = offset + addend; + } else if (current_type->isArrayTy() || current_type->isVectorTy() || + current_type->isPointerTy()) { + std::uint64_t elementSize = kmodule->targetData->getTypeStoreSize( + current_type->getArrayElementType()); + offset += elementSize * index; + } else { + assert(0 && "Unknown type"); + } + + current_type = GetElementPtrInst::getTypeAtIndex(current_type, index); + } + kgepi->offset = offset; } else if (ExtractValueInst *evi = dyn_cast(KI->inst())) { KGEPInstruction *kgepi = static_cast(KI); - computeOffsets(kgepi, ev_type_begin(evi), ev_type_end(evi)); - assert(kgepi->indices.empty() && "ExtractValue constant offset expected"); + llvm::Value *agg = evi->getAggregateOperand(); + llvm::Type *current_type = agg->getType(); + uint64_t offset = 0; + for (auto index : evi->indices()) { + if (StructType *st = dyn_cast(current_type)) { + const StructLayout *sl = kmodule->targetData->getStructLayout(st); + uint64_t addend = sl->getElementOffset(index); + offset = offset + addend; + } else if (current_type->isArrayTy() || current_type->isVectorTy() || + current_type->isPointerTy()) { + uint64_t elementSize = kmodule->targetData->getTypeStoreSize( + current_type->getArrayElementType()); + offset += elementSize * index; + } else { + assert(0 && "Unknown type"); + } + + current_type = GetElementPtrInst::getTypeAtIndex(current_type, index); + } + kgepi->offset = offset; } } @@ -4611,14 +4696,14 @@ void Executor::seed(ExecutionState &initialState) { klee_message("%d seeds remaining over: %d states", numSeeds, numStates); } } - } - klee_message("seeding done (%d states remain)", - (int)objectManager->getStates().size()); + klee_message("seeding done (%d states remain)", + (int)objectManager->getStates().size()); - if (OnlySeed) { - doDumpStates(); - return; + if (OnlySeed) { + doDumpStates(); + return; + } } } @@ -4923,10 +5008,10 @@ HaltExecution::Reason fromStateTerminationType(StateTerminationType t) { } void Executor::terminateState(ExecutionState &state, - StateTerminationType terminationType) { - state.terminationReasonType = fromStateTerminationType(terminationType); - if (terminationType >= StateTerminationType::MaxDepth && - terminationType <= StateTerminationType::EARLY) { + StateTerminationType reason) { + state.terminationReasonType = fromStateTerminationType(reason); + if (reason >= StateTerminationType::MaxDepth && + reason <= StateTerminationType::EARLY) { SetOfStates states = {&state}; decreaseConfidenceFromStoppedStates(states, state.terminationReasonType); } @@ -4973,6 +5058,7 @@ void Executor::terminateStateEarly(ExecutionState &state, const Twine &message, reason > StateTerminationType::EARLY && reason <= StateTerminationType::EXECERR); } + terminateState(state, reason); } @@ -5181,9 +5267,14 @@ void Executor::terminateStateOnSolverError(ExecutionState &state, } void Executor::terminateStateOnUserError(ExecutionState &state, - const llvm::Twine &message) { + const llvm::Twine &message, + bool writeErr) { ++stats::terminationUserError; - terminateStateOnError(state, message, StateTerminationType::User, ""); + if (writeErr) { + terminateStateOnError(state, message, StateTerminationType::User, ""); + } else { + terminateState(state, StateTerminationType::User); + } } void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, @@ -5316,8 +5407,7 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, errnoValue->getZExtValue(sizeof(*errno_addr) * 8)); #endif - if (!SuppressExternalWarnings) { - + if (ExternalCallWarnings != ExtCallWarnings::None) { std::string TmpStr; llvm::raw_string_ostream os(TmpStr); os << "calling external: " << callable->getName().str() << "("; @@ -5328,7 +5418,7 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, } os << ") at " << state.pc->getSourceLocationString(); - if (AllExternalWarnings) + if (ExternalCallWarnings == ExtCallWarnings::All) klee_warning("%s", os.str().c_str()); else klee_warning_once(callable->unwrap(), "%s", os.str().c_str()); @@ -6360,6 +6450,7 @@ void Executor::executeMemoryOperation( terminateStateOnSolverError(*state, "Query timed out (bounds check)."); return; } + solver->setTimeout(time::Span()); bool mustBeInBounds = !isa(response); if (mustBeInBounds) { @@ -7192,9 +7283,7 @@ void Executor::getConstraintLog(const ExecutionState &state, std::string &res, switch (logFormat) { case STP: { auto query = state.toQuery(); - char *log = solver->getConstraintLog(query); - res = std::string(log); - free(log); + res = solver->getConstraintLog(query); } break; case KQUERY: { @@ -7730,7 +7819,7 @@ size_t Executor::getAllocationAlignment(const llvm::Value *allocSite) const { type = GO->getType(); } } else if (const AllocaInst *AI = dyn_cast(allocSite)) { - alignment = AI->getAlignment(); + alignment = AI->getAlign().value(); type = AI->getAllocatedType(); } else if (isa(allocSite) || isa(allocSite)) { // FIXME: Model the semantics of the call to use the right alignment @@ -7753,7 +7842,12 @@ size_t Executor::getAllocationAlignment(const llvm::Value *allocSite) const { assert(type != NULL); // No specified alignment. Get the alignment for the type. if (type->isSized()) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + alignment = kmodule->targetData->getPrefTypeAlign(type).value(); +#else alignment = kmodule->targetData->getPrefTypeAlignment(type); +#endif + } else { klee_warning_once(allocSite, "Cannot determine memory alignment for " diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index e990524a45..12a6126853 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -579,14 +579,18 @@ class Executor : public Interpreter { /// value). Otherwise return the original expression. ref toUnique(const ExecutionState &state, ref e); - /// Return a constant value for the given expression, forcing it to - /// be constant in the given state by adding a constraint if - /// necessary. Note that this function breaks completeness and - /// should generally be avoided. + /// Return a constant value for the given expression. Note that this function + /// breaks completeness and should generally be avoided. /// - /// \param purpose An identify string to printed in case of concretization. + /// \param reason A documentation string stating the reason for concretization ref toConstant(ExecutionState &state, ref e, - const char *purpose); + const std::string &reason); + + /// Evaluate the given expression under each seed, and return the + /// first one that results in a constant, if such a seed exist. Otherwise, + /// return the non-constant evaluation of the expression under one of the + /// seeds. + ref getValueFromSeeds(ExecutionState &state, ref e); ref toConstantPointer(ExecutionState &state, ref e, @@ -607,9 +611,9 @@ class Executor : public Interpreter { const KInstruction * getLastNonKleeInternalInstruction(const ExecutionState &state) const; - /// Remove state from queue and delete state - void terminateState(ExecutionState &state, - StateTerminationType terminationType); + /// Remove state from queue and delete state. This function should only be + /// used in the termination functions below. + void terminateState(ExecutionState &state, StateTerminationType reason); /// Call exit handler and terminate state normally /// (end of execution path) @@ -670,7 +674,8 @@ class Executor : public Interpreter { /// Call error handler and terminate state for user errors /// (e.g. wrong usage of klee.h API) void terminateStateOnUserError(ExecutionState &state, - const llvm::Twine &message); + const llvm::Twine &message, + bool writeErr = true); void reportProgressTowardsTargets(std::string prefix, const SetOfStates &states) const; diff --git a/lib/Core/ExternalDispatcher.cpp b/lib/Core/ExternalDispatcher.cpp index 9676f21cdc..66a4fbbb0e 100644 --- a/lib/Core/ExternalDispatcher.cpp +++ b/lib/Core/ExternalDispatcher.cpp @@ -10,6 +10,7 @@ #include "ExternalDispatcher.h" #include "CoreStats.h" +#include "klee/Config/Version.h" #include "klee/Module/KCallable.h" #include "klee/Module/KModule.h" @@ -272,7 +273,7 @@ bool ExternalDispatcherImpl::runProtectedCall(Function *f, uint64_t *args) { } // FIXME: This might have been relevant for the old JIT but the MCJIT -// has a completly different implementation so this comment below is +// has a completely different implementation so this comment below is // likely irrelevant and misleading. // // For performance purposes we construct the stub in such a way that the @@ -305,13 +306,20 @@ Function *ExternalDispatcherImpl::createDispatcher(KCallable *target, llvm::IRBuilder<> Builder(dBB); // Get a Value* for &gTheArgsP, as an i64**. +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + auto argI64sp = Builder.CreateIntToPtr( + ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)&gTheArgsP), + PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))), + "argsp"); + auto argI64s = Builder.CreateLoad(Builder.getPtrTy(), argI64sp, "args"); +#else auto argI64sp = Builder.CreateIntToPtr( ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)(void *)&gTheArgsP), PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))), "argsp"); auto argI64s = Builder.CreateLoad( argI64sp->getType()->getPointerElementType(), argI64sp, "args"); - +#endif // Get the target function type. FunctionType *FTy = target->getFunctionType(); @@ -328,6 +336,14 @@ Function *ExternalDispatcherImpl::createDispatcher(KCallable *target, if (argTy->isX86_FP80Ty() && idx & 0x01) idx++; +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + auto argI64p = + Builder.CreateGEP(Builder.getPtrTy(), argI64s, + ConstantInt::get(Type::getInt32Ty(ctx), idx)); + + auto argp = Builder.CreateBitCast(argI64p, PointerType::getUnqual(argTy)); + args[i] = Builder.CreateLoad(argTy, argp); +#else auto argI64p = Builder.CreateGEP(argI64s->getType()->getPointerElementType(), argI64s, ConstantInt::get(Type::getInt32Ty(ctx), idx)); @@ -335,6 +351,7 @@ Function *ExternalDispatcherImpl::createDispatcher(KCallable *target, auto argp = Builder.CreateBitCast(argI64p, PointerType::getUnqual(argTy)); args[i] = Builder.CreateLoad(argp->getType()->getPointerElementType(), argp); +#endif unsigned argSize = argTy->getPrimitiveSizeInBits(); idx += ((!!argSize ? argSize : 64) + 63) / 64; diff --git a/lib/Core/GetElementPtrTypeIterator.h b/lib/Core/GetElementPtrTypeIterator.h index 3d7ae2b2e0..aa3918ef6a 100644 --- a/lib/Core/GetElementPtrTypeIterator.h +++ b/lib/Core/GetElementPtrTypeIterator.h @@ -67,12 +67,7 @@ class generic_gep_type_iterator { llvm::Type *operator*() const { return CurTy; } llvm::Type *getIndexedType() const { -#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0) return llvm::GetElementPtrInst::getTypeAtIndex(CurTy, getOperand()); -#else - llvm::CompositeType *CT = cast(CurTy); - return CT->getTypeAtIndex(getOperand()); -#endif } // This is a non-standard operator->. It allows you to call methods on the @@ -82,15 +77,9 @@ class generic_gep_type_iterator { llvm::Value *getOperand() const { return asValue(*OpIt); } generic_gep_type_iterator &operator++() { // Preincrement -#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0) - if (llvm::isa(CurTy) || - llvm::isa(CurTy) || - llvm::isa(CurTy)) { + if (isa(CurTy) || isa(CurTy) || + isa(CurTy)) { CurTy = llvm::GetElementPtrInst::getTypeAtIndex(CurTy, getOperand()); -#else - if (llvm::CompositeType *CT = dyn_cast(CurTy)) { - CurTy = CT->getTypeAtIndex(getOperand()); -#endif } else if (CurTy->isPointerTy()) { CurTy = CurTy->getPointerElementType(); } else { @@ -145,14 +134,6 @@ inline iv_type_iterator iv_type_end(const llvm::InsertValueInst *IV) { return iv_type_iterator::end(IV->idx_end()); } -inline vce_type_iterator vce_type_begin(const llvm::ConstantExpr *CE) { - return vce_type_iterator::begin(CE->getOperand(0)->getType(), - CE->getIndices().begin()); -} -inline vce_type_iterator vce_type_end(const llvm::ConstantExpr *CE) { - return vce_type_iterator::end(CE->getIndices().end()); -} - template inline generic_gep_type_iterator gep_type_begin(llvm::Type *Op0, ItTy I, ItTy) { diff --git a/lib/Core/Memory.cpp b/lib/Core/Memory.cpp index 157babee2e..acf8228e89 100644 --- a/lib/Core/Memory.cpp +++ b/lib/Core/Memory.cpp @@ -11,6 +11,7 @@ #include "ConstructStorage.h" #include "ExecutionState.h" +#include "Executor.h" #include "MemoryManager.h" #include "klee/ADT/Bits.h" #include "klee/ADT/Ref.h" diff --git a/lib/Core/Memory.h b/lib/Core/Memory.h index 14c0cb16a6..71c3172981 100644 --- a/lib/Core/Memory.h +++ b/lib/Core/Memory.h @@ -34,6 +34,7 @@ namespace klee { class BitArray; class ExecutionState; class KType; +class Executor; class MemoryManager; class Solver; diff --git a/lib/Core/MemoryManager.cpp b/lib/Core/MemoryManager.cpp index 1abfe9d686..5e856e5b0d 100644 --- a/lib/Core/MemoryManager.cpp +++ b/lib/Core/MemoryManager.cpp @@ -17,6 +17,8 @@ #include "klee/Expr/SourceBuilder.h" #include "klee/Support/ErrorHandling.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MathExtras.h" @@ -26,10 +28,12 @@ using namespace klee; -namespace { +namespace klee { llvm::cl::OptionCategory MemoryCat("Memory management options", "These options control memory management."); +} +namespace { llvm::cl::opt DeterministicAllocation( "allocate-determ", llvm::cl::desc("Allocate memory deterministically (default=false)"), diff --git a/lib/Core/SeedInfo.cpp b/lib/Core/SeedInfo.cpp index efd2df7617..cbc1a99b9c 100644 --- a/lib/Core/SeedInfo.cpp +++ b/lib/Core/SeedInfo.cpp @@ -76,22 +76,14 @@ void SeedInfo::patchSeed(const ExecutionState &state, ref condition, std::set> directReads; std::vector> reads; findReads(condition, false, reads); - for (std::vector>::iterator it = reads.begin(), - ie = reads.end(); - it != ie; ++it) { - ReadExpr *re = it->get(); + for (auto const &re : reads) { if (ConstantExpr *CE = dyn_cast(re->index)) { directReads.insert( std::make_pair(re->updates.root, (unsigned)CE->getZExtValue(32))); } } - for (std::set>::iterator - it = directReads.begin(), - ie = directReads.end(); - it != ie; ++it) { - const Array *array = it->first; - unsigned i = it->second; + for (auto const &[array, i] : directReads) { ref read = ReadExpr::create(UpdateList(array, 0), ConstantExpr::alloc(i, Expr::Int32)); diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp index cd64598b69..8031d7320e 100644 --- a/lib/Core/SpecialFunctionHandler.cpp +++ b/lib/Core/SpecialFunctionHandler.cpp @@ -35,6 +35,8 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include +#include #include using namespace llvm; @@ -52,7 +54,7 @@ cl::opt cl::opt SilentKleeAssume("silent-klee-assume", cl::init(false), cl::desc("Silently terminate paths with an infeasible " - "condition given to klee_assume() rather than " + "condition given to klee_assume rather than " "emitting an error (default=false)"), cl::cat(TerminationCat)); @@ -72,21 +74,27 @@ cl::opt CheckOutOfMemory("check-out-of-memory", cl::init(false), // especially things like realloc which have complicated semantics // w.r.t. forking. Among other things this makes delayed query // dispatch easier to implement. -static SpecialFunctionHandler::HandlerInfo handlerInfo[] = { +static constexpr std::array handlerInfo = { #define add(name, handler, ret) \ - { name, &SpecialFunctionHandler::handler, false, ret, false } + SpecialFunctionHandler::HandlerInfo { \ + name, &SpecialFunctionHandler::handler, false, ret, false \ + } #define addDNR(name, handler) \ - { name, &SpecialFunctionHandler::handler, true, false, false } + SpecialFunctionHandler::HandlerInfo { \ + name, &SpecialFunctionHandler::handler, true, false, false \ + } addDNR("__assert_rtn", handleAssertFail), addDNR("__assert_fail", handleAssertFail), addDNR("__assert", handleAssertFail), addDNR("_assert", handleAssert), addDNR("abort", handleAbort), addDNR("_exit", handleExit), - {"exit", &SpecialFunctionHandler::handleExit, true, false, true}, + SpecialFunctionHandler::HandlerInfo{ + "exit", &SpecialFunctionHandler::handleExit, true, false, true}, addDNR("klee_abort", handleAbort), addDNR("klee_silent_exit", handleSilentExit), addDNR("klee_report_error", handleReportError), + add("aligned_alloc", handleMemalign, true), add("calloc", handleCalloc, true), add("free", handleFree, false), add("klee_assume", handleAssume, false), @@ -194,40 +202,12 @@ static SpecialFunctionHandler::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( std::vector &preservedFunctions) { - unsigned N = size(); - - for (unsigned i = 0; i < N; ++i) { - HandlerInfo &hi = handlerInfo[i]; + for (auto &hi : handlerInfo) { Function *f = executor.kmodule->module->getFunction(hi.name); // No need to create if the function doesn't exist, since it cannot @@ -248,10 +228,7 @@ void SpecialFunctionHandler::prepare( } void SpecialFunctionHandler::bind() { - unsigned N = size(); - - for (unsigned i = 0; i < N; ++i) { - HandlerInfo &hi = handlerInfo[i]; + for (auto &hi : handlerInfo) { Function *f = executor.kmodule->module->getFunction(hi.name); if (f && (!hi.doNotOverride || f->isDeclaration())) { @@ -555,12 +532,8 @@ void SpecialFunctionHandler::handleAssume(ExecutionState &state, KInstruction *, state.constraints.cs(), e, res, state.queryMetaData); assert(success && "FIXME: Unhandled solver failure"); if (res) { - if (SilentKleeAssume) { - executor.terminateState(state, StateTerminationType::SilentExit); - } else { - executor.terminateStateOnUserError( - state, "invalid klee_assume call (provably false)"); - } + executor.terminateStateOnUserError( + state, "invalid klee_assume call (provably false)", !SilentKleeAssume); } else { executor.addConstraint(state, e); } diff --git a/lib/Core/SpecialFunctionHandler.h b/lib/Core/SpecialFunctionHandler.h index 217ed1f06a..2c506a3db8 100644 --- a/lib/Core/SpecialFunctionHandler.h +++ b/lib/Core/SpecialFunctionHandler.h @@ -12,7 +12,6 @@ #include "klee/Config/config.h" -#include #include #include #include @@ -48,36 +47,6 @@ class SpecialFunctionHandler { bool doNotOverride; /// Intrinsic should not be used if already defined }; - // const_iterator to iterate over stored HandlerInfo - // FIXME: Implement >, >=, <=, < operators - class const_iterator { - using iterator_category = std::random_access_iterator_tag; - using value_type = HandlerInfo; - using difference_type = ptrdiff_t; - using pointer = void; - using reference = void; - - 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 cc3119109e..d9e5996e95 100644 --- a/lib/Core/StatsTracker.cpp +++ b/lib/Core/StatsTracker.cpp @@ -47,7 +47,7 @@ using namespace llvm; /// -namespace { +namespace klee { cl::OptionCategory StatsCat("Statistics options", "These options control the statistics generated by KLEE."); @@ -98,7 +98,7 @@ cl::opt IStatsWriteAfterInstructions( "Write istats after each n instructions, 0 to disable (default=0)"), cl::cat(StatsCat)); -enum CoverageCheckType { None, TimerBased, InstructionBased }; +enum class CoverageCheckType { None, TimerBased, InstructionBased }; cl::opt UseCovCheck( "use-cov-check", @@ -144,7 +144,7 @@ cl::opt UseCallPaths("use-call-paths", cl::init(true), "level statistics (default=true)"), cl::cat(StatsCat)); -} // namespace +} // namespace klee /// diff --git a/lib/Core/TargetedExecutionManager.cpp b/lib/Core/TargetedExecutionManager.cpp index 2ede8edc64..e1ed78e2a1 100644 --- a/lib/Core/TargetedExecutionManager.cpp +++ b/lib/Core/TargetedExecutionManager.cpp @@ -44,7 +44,7 @@ cl::list ExitOnErrorType( "Stop execution after reaching a specified condition (default=false)"), cl::values( clEnumValN(StateTerminationType::Abort, "Abort", - "The program crashed (reached abort()/klee_abort())"), + "The program reached abort or klee_abort"), clEnumValN(StateTerminationType::Assert, "Assert", "An assertion was hit"), clEnumValN(StateTerminationType::BadVectorAccess, "BadVectorAccess", @@ -85,8 +85,8 @@ cl::list ExitOnErrorType( clEnumValN(StateTerminationType::NullableAttribute, "NullableAttribute", "Violation of nullable attribute detected"), clEnumValN(StateTerminationType::User, "User", - "Wrong klee_* functions invocation")), - cl::cat(TerminationCat)); + "Wrong klee_* function invocation")), + cl::ZeroOrMore, cl::cat(TerminationCat)); cl::opt MaxInstructions("max-instructions", diff --git a/lib/Core/TimingSolver.h b/lib/Core/TimingSolver.h index f3c80591b7..6cff49d410 100644 --- a/lib/Core/TimingSolver.h +++ b/lib/Core/TimingSolver.h @@ -17,6 +17,7 @@ #include "klee/System/Time.h" #include +#include #include #include @@ -45,7 +46,7 @@ class TimingSolver { void setTimeout(time::Span t) { solver->setCoreSolverTimeout(t); } - char *getConstraintLog(const Query &query) { + std::string getConstraintLog(const Query &query) { return solver->getConstraintLog(query); } diff --git a/lib/Core/UserSearcher.cpp b/lib/Core/UserSearcher.cpp index 66fb2a6b17..feb1318bba 100644 --- a/lib/Core/UserSearcher.cpp +++ b/lib/Core/UserSearcher.cpp @@ -19,7 +19,7 @@ using namespace llvm; using namespace klee; -namespace { +namespace klee { llvm::cl::OptionCategory SearchCat("Search options", "These options control the search heuristic."); @@ -87,7 +87,7 @@ cl::opt UseFairSearch( "(default=false)"), cl::init(false), cl::cat(SearchCat)); -} // namespace +} // namespace klee void klee::initializeSearchOptions() { // default values diff --git a/lib/Expr/Expr.cpp b/lib/Expr/Expr.cpp index cdceea707c..e6e4a03ea7 100644 --- a/lib/Expr/Expr.cpp +++ b/lib/Expr/Expr.cpp @@ -649,34 +649,7 @@ ref ConstantExpr::fromMemory(void *address, Width width) { void ConstantExpr::toMemory(void *address) { auto width = getWidth(); - switch (width) { - default: - assert(0 && "invalid type"); - case Expr::Bool: - *((uint8_t *)address) = getZExtValue(1); - break; - case Expr::Int8: - *((uint8_t *)address) = getZExtValue(8); - break; - case Expr::Int16: - *((uint16_t *)address) = getZExtValue(16); - break; - case Expr::Int32: - *((uint32_t *)address) = getZExtValue(32); - break; - case Expr::Int64: - *((uint64_t *)address) = getZExtValue(64); - break; - case Expr::Int128: - case Expr::Int256: - case Expr::Int512: - memcpy(address, value.getRawData(), width / 8); - break; - // FIXME: what about machines without x87 support? - case Expr::Fl80: - *((long double *)address) = *(const long double *)value.getRawData(); - break; - } + std::memcpy(address, value.getRawData(), (width + 7) / 8); } void ConstantExpr::toString(std::string &Res, unsigned radix) const { diff --git a/lib/Module/CMakeLists.txt b/lib/Module/CMakeLists.txt index 3f7651fb44..21840ecbe3 100644 --- a/lib/Module/CMakeLists.txt +++ b/lib/Module/CMakeLists.txt @@ -23,7 +23,6 @@ set(KLEE_MODULE_COMPONENT_SRCS LocalVarDeclarationFinderPass.cpp LowerSwitch.cpp ModuleUtil.cpp - Optimize.cpp OptNone.cpp PhiCleaner.cpp RaiseAsm.cpp @@ -35,6 +34,19 @@ set(KLEE_MODULE_COMPONENT_SRCS TargetForest.cpp ) +if ("${LLVM_VERSION_MAJOR}" LESS 17) + LIST(APPEND KLEE_MODULE_COMPONENT_SRCS + InstrumentLegacy.cpp + OptimizeLegacy.cpp + ) +else () + LIST(APPEND KLEE_MODULE_COMPONENT_SRCS + Instrument.cpp + Optimize.cpp + ) +endif () + + add_library(kleeModule ${KLEE_MODULE_COMPONENT_SRCS} ) diff --git a/lib/Module/FunctionAlias.cpp b/lib/Module/FunctionAlias.cpp index aa80b35d6e..f91fcf3dc0 100644 --- a/lib/Module/FunctionAlias.cpp +++ b/lib/Module/FunctionAlias.cpp @@ -9,6 +9,7 @@ #include "Passes.h" +#include "klee/Config/Version.h" #include "klee/Support/Casting.h" #include "klee/Support/ErrorHandling.h" #include "klee/Support/OptionCategories.h" @@ -134,10 +135,16 @@ bool FunctionAliasPass::runOnModule(Module &M) { } const FunctionType *FunctionAliasPass::getFunctionType(const GlobalValue *gv) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + if (auto *ft = dyn_cast(gv->getType())) + return ft; + return dyn_cast(gv->getValueType()); +#else const Type *type = gv->getType(); while (type->isPointerTy()) type = type->getPointerElementType(); - return cast(type); + return dyn_cast(type); +#endif } bool FunctionAliasPass::checkType(const GlobalValue *match, diff --git a/lib/Module/Instrument.cpp b/lib/Module/Instrument.cpp new file mode 100644 index 0000000000..429be619e7 --- /dev/null +++ b/lib/Module/Instrument.cpp @@ -0,0 +1,19 @@ +//===-- Instrument.cpp ------------------------------------------*- C++ -*-===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModuleHelper.h" + +using namespace klee; + +void klee::checkModule(bool DontVerfify, llvm::Module *module) { assert(0); } + +void klee::instrument(bool CheckDivZero, bool CheckOvershift, + bool WithFPRuntime, llvm::Module *module) { + assert(0); +} diff --git a/lib/Module/InstrumentLegacy.cpp b/lib/Module/InstrumentLegacy.cpp new file mode 100644 index 0000000000..efb84cbdc2 --- /dev/null +++ b/lib/Module/InstrumentLegacy.cpp @@ -0,0 +1,160 @@ +//===-- InstrumentLegacy.cpp ------------------------------------*- C++ -*-===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "ModuleHelper.h" + +#include "Passes.h" +#include "klee/Support/CompilerWarning.h" +#include "klee/Support/ErrorHandling.h" +#include "klee/Support/ModuleUtil.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_DEPRECATED_DECLARATIONS +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/Scalarizer.h" +#include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/Cloning.h" +DISABLE_WARNING_POP + +using namespace llvm; +using namespace klee; + +namespace klee { +extern cl::OptionCategory ModuleCat; +extern cl::opt UseKleeFloatInternals; +extern cl::opt StripUnwantedCalls; +extern cl::opt SplitCalls; +extern cl::opt SplitReturns; +extern cl::opt SwitchType; +} // namespace klee + +void klee::instrument(bool CheckDivZero, bool CheckOvershift, + bool WithFPRuntime, llvm::Module *module) { + // Inject checks prior to optimization... we also perform the + // invariant transformations that we will end up doing later so that + // optimize is seeing what is as close as possible to the final + // module. + legacy::PassManager pm; + pm.add(new RaiseAsmPass()); + + // This pass will scalarize as much code as possible so that the Executor + // does not need to handle operands of vector type for most instructions + // other than InsertElementInst and ExtractElementInst. + // + // NOTE: Must come before division/overshift checks because those passes + // don't know how to handle vector instructions. + pm.add(createScalarizerPass()); + + // This pass will replace atomic instructions with non-atomic operations + pm.add(createLowerAtomicPass()); + if (CheckDivZero) + pm.add(new DivCheckPass()); + if (CheckOvershift) + pm.add(new OvershiftCheckPass()); + + llvm::DataLayout targetData(module); + pm.add(new IntrinsicCleanerPass(targetData, WithFPRuntime)); + pm.run(*module); +} + +void klee::checkModule(bool DontVerify, llvm::Module *module) { + InstructionOperandTypeCheckPass *operandTypeCheckPass = + new InstructionOperandTypeCheckPass(); + + legacy::PassManager pm; + if (!DontVerify) + pm.add(createVerifierPass()); + pm.add(operandTypeCheckPass); + pm.run(*module); + + // Enforce the operand type invariants that the Executor expects. This + // implicitly depends on the "Scalarizer" pass to be run in order to succeed + // in the presence of vector instructions. + if (!operandTypeCheckPass->checkPassed()) { + klee_error("Unexpected instruction operand types detected"); + } +} + +void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, + bool Simplify, + bool WithFPRuntime, SwitchImplType SwitchType, + std::string EntryPoint, + llvm::ArrayRef preservedFunctions, + llvm::Module *module) { + // Preserve all functions containing klee-related function calls from being + // optimised around + if (!OptimiseKLEECall) { + legacy::PassManager pm; + pm.add(new OptNonePass()); + pm.run(*module); + } + + // Use KLEE's internal float classification functions if requested. + if (WithFPRuntime) { + if (UseKleeFloatInternals) { + for (const auto &p : klee::floatReplacements) { + replaceOrRenameFunction(module, p.first.c_str(), + p.second.c_str()); + } + } + } + + if (Optimize) + optimizeModule(module, preservedFunctions); + + // Needs to happen after linking (since ctors/dtors can be modified) + // and optimization (since global optimization can rewrite lists). + injectStaticConstructorsAndDestructors(module, EntryPoint); + + // Finally, run the passes that maintain invariants we expect during + // interpretation. We run the intrinsic cleaner just in case we + // linked in something with intrinsics but any external calls are + // going to be unresolved. We really need to handle the intrinsics + // directly I think? + legacy::PassManager pm3; + + pm3.add(new ReturnLocationFinderPass()); + pm3.add(new LocalVarDeclarationFinderPass()); + + if (Simplify) + pm3.add(createCFGSimplificationPass()); + switch (SwitchType) { + case SwitchImplType::eSwitchTypeInternal: + break; + case SwitchImplType::eSwitchTypeSimple: + pm3.add(new LowerSwitchPass()); + break; + case SwitchImplType::eSwitchTypeLLVM: + pm3.add(createLowerSwitchPass()); + break; + } + + llvm::DataLayout targetData(module); + pm3.add(new IntrinsicCleanerPass(targetData, WithFPRuntime)); + pm3.add(createScalarizerPass()); + pm3.add(new PhiCleanerPass()); + pm3.add(new FunctionAliasPass()); + if (StripUnwantedCalls) + pm3.add(new CallRemover()); + if (SplitCalls) { + pm3.add(new CallSplitter()); + } + if (SplitReturns) { + pm3.add(new ReturnSplitter()); + } + pm3.run(*module); +} diff --git a/lib/Module/IntrinsicCleaner.cpp b/lib/Module/IntrinsicCleaner.cpp index 5bb9f021f5..2ea4fd901b 100644 --- a/lib/Module/IntrinsicCleaner.cpp +++ b/lib/Module/IntrinsicCleaner.cpp @@ -21,6 +21,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/Pass.h" @@ -130,9 +131,14 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) { Builder.CreatePointerCast(dst, i8pp, "vacopy.cast.dst"); auto castedSrc = Builder.CreatePointerCast(src, i8pp, "vacopy.cast.src"); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + auto load = Builder.CreateLoad(Builder.getInt8PtrTy(), castedSrc, + "vacopy.read"); +#else auto load = Builder.CreateLoad(castedSrc->getType()->getPointerElementType(), castedSrc, "vacopy.read"); +#endif Builder.CreateStore(load, castedDst, false /* isVolatile */); } else { assert(WordSize == 8 && "Invalid word size!"); @@ -140,9 +146,13 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) { auto pDst = Builder.CreatePointerCast(dst, i64p, "vacopy.cast.dst"); auto pSrc = Builder.CreatePointerCast(src, i64p, "vacopy.cast.src"); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + auto pSrcType = Builder.getPtrTy(); + auto pDstType = Builder.getPtrTy(); +#else auto pSrcType = pSrc->getType()->getPointerElementType(); auto pDstType = pDst->getType()->getPointerElementType(); - +#endif auto val = Builder.CreateLoad(pSrcType, pSrc); Builder.CreateStore(val, pDst, ii); @@ -386,7 +396,11 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) { #if LLVM_VERSION_CODE >= LLVM_VERSION(12, 0) case Intrinsic::experimental_noalias_scope_decl: #endif +#if LLVM_VERSION_CODE < LLVM_VERSION(16, 0) case Intrinsic::flt_rounds: +#else + case Intrinsic::get_rounding: +#endif case Intrinsic::frameaddress: case Intrinsic::get_dynamic_area_offset: case Intrinsic::invariant_end: @@ -403,9 +417,8 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) { case Intrinsic::ptr_annotation: case Intrinsic::readcyclecounter: case Intrinsic::returnaddress: -#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0) case Intrinsic::roundeven: -#endif + case Intrinsic::sin: case Intrinsic::stackrestore: case Intrinsic::stacksave: case Intrinsic::var_annotation: diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index b1e18690bf..617f25f040 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -9,6 +9,9 @@ #define DEBUG_TYPE "KModule" +#include "klee/Module/KModule.h" + +#include "ModuleHelper.h" #include "Passes.h" #include "klee/Core/Interpreter.h" @@ -22,18 +25,7 @@ #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/AssemblyAnnotationWriter.h" -#include "llvm/IR/CFG.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/ValueSymbolTable.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Linker/Linker.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" @@ -53,9 +45,7 @@ cl::OptionCategory "These options affect the compile-time processing of the code."); } -namespace { -enum SwitchImplType { eSwitchTypeSimple, eSwitchTypeLLVM, eSwitchTypeInternal }; - +namespace klee { cl::opt OutputSource( "output-source", cl::desc( @@ -67,16 +57,6 @@ cl::opt cl::desc("Write the bitcode for the final transformed module"), cl::init(false), cl::cat(ModuleCat)); -cl::opt SwitchType( - "switch-type", - cl::desc("Select the implementation of switch (default=internal)"), - cl::values(clEnumValN(eSwitchTypeSimple, "simple", - "lower to ordered branches"), - clEnumValN(eSwitchTypeLLVM, "llvm", "lower using LLVM"), - clEnumValN(eSwitchTypeInternal, "internal", - "execute switch internally")), - cl::init(eSwitchTypeInternal), cl::cat(ModuleCat)); - cl::opt DebugPrintEscapingFunctions( "debug-print-escaping-functions", cl::desc("Print functions whose address is taken (default=false)"), @@ -109,7 +89,7 @@ cl::opt cl::desc("Split each call in own basic block (default=true)"), cl::init(true), cl::cat(klee::ModuleCat)); -static cl::opt +cl::opt StripUnwantedCalls("strip-unwanted-calls", cl::desc("Strip all unwanted calls (llvm.dbg.* stuff)"), cl::init(false), cl::cat(klee::ModuleCat)); @@ -118,13 +98,20 @@ cl::opt SplitReturns( "split-returns", cl::desc("Split each return in own basic block (default=true)"), cl::init(true), cl::cat(klee::ModuleCat)); -} // namespace -/***/ +cl::opt SwitchType( + "switch-type", + cl::desc("Select the implementation of switch (default=internal)"), + cl::values(clEnumValN(SwitchImplType::eSwitchTypeSimple, "simple", + "lower to ordered branches"), + clEnumValN(SwitchImplType::eSwitchTypeLLVM, "llvm", + "lower using LLVM"), + clEnumValN(SwitchImplType::eSwitchTypeInternal, "internal", + "execute switch internally")), + cl::init(SwitchImplType::eSwitchTypeInternal), cl::cat(ModuleCat)); +} // namespace klee -namespace llvm { -extern void Optimize(Module *, llvm::ArrayRef preservedFunctions); -} +/***/ // what a hack static Function *getStubFunctionForCtorList(Module *m, GlobalVariable *gv, @@ -170,9 +157,8 @@ static Function *getStubFunctionForCtorList(Module *m, GlobalVariable *gv, return fn; } -static void -injectStaticConstructorsAndDestructors(Module *m, - llvm::StringRef entryFunction) { +void klee::injectStaticConstructorsAndDestructors( + Module *m, llvm::StringRef entryFunction) { GlobalVariable *ctors = m->getNamedGlobal("llvm.global_ctors"); GlobalVariable *dtors = m->getNamedGlobal("llvm.global_dtors"); @@ -228,57 +214,13 @@ bool KModule::link(std::vector> &modules, } void KModule::instrument(const Interpreter::ModuleOptions &opts) { - // Inject checks prior to optimization... we also perform the - // invariant transformations that we will end up doing later so that - // optimize is seeing what is as close as possible to the final - // module. - legacy::PassManager pm; - pm.add(new RaiseAsmPass()); - - // This pass will scalarize as much code as possible so that the Executor - // does not need to handle operands of vector type for most instructions - // other than InsertElementInst and ExtractElementInst. - // - // NOTE: Must come before division/overshift checks because those passes - // don't know how to handle vector instructions. - pm.add(createScalarizerPass()); - - // This pass will replace atomic instructions with non-atomic operations - pm.add(createLowerAtomicPass()); - if (opts.CheckDivZero) - pm.add(new DivCheckPass()); - if (opts.CheckOvershift) - pm.add(new OvershiftCheckPass()); - - pm.add(new IntrinsicCleanerPass(*targetData, opts.WithFPRuntime)); - pm.run(*module); - withPosixRuntime = opts.WithPOSIXRuntime; + klee::instrument(opts.CheckDivZero, opts.CheckOvershift, opts.WithFPRuntime, + module.get()); } void KModule::optimiseAndPrepare( const Interpreter::ModuleOptions &opts, llvm::ArrayRef preservedFunctions) { - // Preserve all functions containing klee-related function calls from being - // optimised around - if (!OptimiseKLEECall) { - legacy::PassManager pm; - pm.add(new OptNonePass()); - pm.run(*module); - } - - // Use KLEE's internal float classification functions if requested. - if (opts.WithFPRuntime) { - if (UseKleeFloatInternals) { - for (const auto &p : klee::floatReplacements) { - replaceOrRenameFunction(module.get(), p.first.c_str(), - p.second.c_str()); - } - } - } - - if (opts.Optimize) - Optimize(module.get(), preservedFunctions); - // Add internal functions which are not used to check if instructions // have been already visited if (opts.CheckDivZero) @@ -286,47 +228,9 @@ void KModule::optimiseAndPrepare( if (opts.CheckOvershift) addInternalFunction("klee_overshift_check"); - // Needs to happen after linking (since ctors/dtors can be modified) - // and optimization (since global optimization can rewrite lists). - injectStaticConstructorsAndDestructors(module.get(), opts.EntryPoint); - - // Finally, run the passes that maintain invariants we expect during - // interpretation. We run the intrinsic cleaner just in case we - // linked in something with intrinsics but any external calls are - // going to be unresolved. We really need to handle the intrinsics - // directly I think? - legacy::PassManager pm3; - - pm3.add(new ReturnLocationFinderPass()); - pm3.add(new LocalVarDeclarationFinderPass()); - - if (opts.Simplify) - pm3.add(createCFGSimplificationPass()); - switch (SwitchType) { - case eSwitchTypeInternal: - break; - case eSwitchTypeSimple: - pm3.add(new LowerSwitchPass()); - break; - case eSwitchTypeLLVM: - pm3.add(createLowerSwitchPass()); - break; - default: - klee_error("invalid --switch-type"); - } - pm3.add(new IntrinsicCleanerPass(*targetData, opts.WithFPRuntime)); - pm3.add(createScalarizerPass()); - pm3.add(new PhiCleanerPass()); - pm3.add(new FunctionAliasPass()); - if (StripUnwantedCalls) - pm3.add(new CallRemover()); - if (SplitCalls) { - pm3.add(new CallSplitter()); - } - if (SplitReturns) { - pm3.add(new ReturnSplitter()); - } - pm3.run(*module); + klee::optimiseAndPrepare(OptimiseKLEECall, opts.Optimize, opts.Simplify, opts.WithFPRuntime, + SwitchType, opts.EntryPoint, preservedFunctions, + module.get()); } class InstructionToLineAnnotator : public llvm::AssemblyAnnotationWriter { @@ -367,7 +271,7 @@ void KModule::manifest(InterpreterHandler *ih, if (OutputModule) { std::unique_ptr f(ih->openOutputFile("final.bc")); - WriteBitcodeToFile(*module, *f); + llvm::WriteBitcodeToFile(*module, *f); } { @@ -442,6 +346,12 @@ void KModule::manifest(InterpreterHandler *ih, } } + for (auto &Function : functions) { + if (Function->getName() == "_klee_eh_cxx_personality") { + llvm::errs(); + } + } + if (DebugPrintEscapingFunctions && !escapingFunctions.empty()) { llvm::errs() << "KLEE: escaping functions: ["; std::string delimiter = ""; @@ -466,23 +376,7 @@ std::optional KModule::getAsmLine(const llvm::Instruction *inst) const { return getAsmLine(reinterpret_cast(inst)); } -void KModule::checkModule() { - InstructionOperandTypeCheckPass *operandTypeCheckPass = - new InstructionOperandTypeCheckPass(); - - legacy::PassManager pm; - if (!DontVerify) - pm.add(createVerifierPass(false)); - pm.add(operandTypeCheckPass); - pm.run(*module); - - // Enforce the operand type invariants that the Executor expects. This - // implicitly depends on the "Scalarizer" pass to be run in order to succeed - // in the presence of vector instructions. - if (!operandTypeCheckPass->checkPassed()) { - klee_error("Unexpected instruction operand types detected"); - } -} +void KModule::checkModule() { klee::checkModule(DontVerify, module.get()); } KBlock *KModule::getKBlock(const llvm::BasicBlock *bb) { return functionMap[bb->getParent()]->blockMap[bb]; diff --git a/lib/Module/LowerSwitch.cpp b/lib/Module/LowerSwitch.cpp index a71f8bf4e2..1413a13710 100644 --- a/lib/Module/LowerSwitch.cpp +++ b/lib/Module/LowerSwitch.cpp @@ -65,9 +65,8 @@ void LowerSwitchPass::switchConvert(CaseItr begin, CaseItr end, Value *value, // iterate through all the cases, creating a new BasicBlock for each for (CaseItr it = begin; it < end; ++it) { - BasicBlock *newBlock = BasicBlock::Create(F->getContext(), "NodeBlock"); - Function::iterator FI = origBlock->getIterator(); - F->getBasicBlockList().insert(++FI, newBlock); + BasicBlock *newBlock = BasicBlock::Create(F->getContext(), "NodeBlock", F); + Builder.SetInsertPoint(newBlock); auto cmpValue = Builder.CreateICmpEQ(value, it->value, "case.cmp"); Builder.CreateCondBr(cmpValue, it->block, curHead); @@ -101,10 +100,10 @@ void LowerSwitchPass::processSwitchInst(SwitchInst *SI) { // Create a new, empty default block so that the new hierarchy of // if-then statements go to this and the PHI nodes are happy. - BasicBlock *newDefault = BasicBlock::Create(F->getContext(), "newDefault"); + BasicBlock *newDefault = + BasicBlock::Create(F->getContext(), "newDefault", F, defaultBlock); llvm::IRBuilder<> Builder(newDefault); - F->getBasicBlockList().insert(defaultBlock->getIterator(), newDefault); Builder.CreateBr(defaultBlock); // If there is an entry in any PHI nodes for the default edge, make sure @@ -128,9 +127,8 @@ void LowerSwitchPass::processSwitchInst(SwitchInst *SI) { std::reverse(cases.begin(), cases.end()); switchConvert(cases.begin(), cases.end(), switchValue, origBlock, newDefault); - // We are now done with the switch instruction, so delete it - origBlock->getInstList().erase(SI); + SI->eraseFromParent(); } } // namespace klee diff --git a/lib/Module/ModuleHelper.h b/lib/Module/ModuleHelper.h new file mode 100644 index 0000000000..1eff55ee64 --- /dev/null +++ b/lib/Module/ModuleHelper.h @@ -0,0 +1,46 @@ +//===-- ModuleHelper.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_MODULEHELPER_H +#define KLEE_MODULEHELPER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/Module.h" + +namespace klee { +enum class SwitchImplType { + eSwitchTypeSimple, + eSwitchTypeLLVM, + eSwitchTypeInternal +}; + +void optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, + bool Simplify, + bool WithFPRuntime, SwitchImplType SwitchType, + std::string EntryPoint, + llvm::ArrayRef preservedFunctions, + llvm::Module *module); +void checkModule(bool DontVerfify, llvm::Module *module); +void instrument(bool CheckDivZero, bool CheckOvershift, bool WithFPRuntime, + llvm::Module *module); + +void injectStaticConstructorsAndDestructors(llvm::Module *m, + llvm::StringRef entryFunction); + +void optimizeModule(llvm::Module *M, + llvm::ArrayRef preservedFunctions); + +// Mark function with functionName as part of the KLEE runtime +void addInternalFunction(const char *functionName); +// Replace std functions with KLEE intrinsics +void replaceFunction(const std::unique_ptr &m, + const char *original, const char *replacement); +} // namespace klee + +#endif // KLEE_MODULEHELPER_H diff --git a/lib/Module/Optimize.cpp b/lib/Module/Optimize.cpp index 2db77d17e5..64d3b4694a 100644 --- a/lib/Module/Optimize.cpp +++ b/lib/Module/Optimize.cpp @@ -14,8 +14,7 @@ // //===----------------------------------------------------------------------===// -#include "klee/Config/Version.h" -#include "klee/Support/OptionCategories.h" +#include "ModuleHelper.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/Passes.h" @@ -32,238 +31,14 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Utils.h" +#include "llvm/IR/Module.h" -using namespace llvm; - -static cl::opt - DisableInline("disable-inlining", - cl::desc("Do not run the inliner pass (default=false)"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::opt DisableInternalize( - "disable-internalize", - cl::desc("Do not mark all symbols as internal (default=false)"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::opt VerifyEach("verify-each", - cl::desc("Verify intermediate results of all " - "optimization passes (default=false)"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::alias ExportDynamic("export-dynamic", - cl::aliasopt(DisableInternalize), - cl::desc("Alias for -disable-internalize")); - -static cl::opt - Strip("strip-all", cl::desc("Strip all symbol information from executable"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::alias A0("s", cl::desc("Alias for --strip-all"), - cl::aliasopt(Strip)); - -static cl::opt - StripDebug("strip-debug", - cl::desc("Strip debugger symbol info from executable"), - cl::init(false), cl::cat(klee::ModuleCat)); - -static cl::alias A1("S", cl::desc("Alias for --strip-debug"), - cl::aliasopt(StripDebug)); - -static cl::opt DeleteDeadLoops("delete-dead-loops", - cl::desc("Use LoopDeletionPass"), - cl::init(true), cl::cat(klee::ModuleCat)); - -static cl::opt - OptimizeAggressive("optimize-aggressive", - cl::desc("Use aggressive optimization passes"), - cl::init(true), cl::cat(klee::ModuleCat)); - -// A utility function that adds a pass to the pass manager but will also add -// a verifier pass after if we're supposed to verify. -static inline void addPass(legacy::PassManager &PM, Pass *P) { - // Add the pass to the pass manager... - PM.add(P); - - // If we are verifying all of the intermediate steps, add the verifier... - if (VerifyEach) - PM.add(createVerifierPass()); -} - -namespace llvm { - -static void AddStandardCompilePasses(legacy::PassManager &PM) { - PM.add(createVerifierPass()); // Verify that input is correct - - // If the -strip-debug command line option was specified, do it. - if (StripDebug) - addPass(PM, createStripSymbolsPass(true)); - - addPass(PM, createCFGSimplificationPass()); // Clean up disgusting code - addPass(PM, createPromoteMemoryToRegisterPass()); // Kill useless allocas - addPass(PM, createGlobalOptimizerPass()); // Optimize out global vars - addPass(PM, createGlobalDCEPass()); // Remove unused fns and globs -#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0) - addPass(PM, createSCCPPass()); // Constant prop with SCCP -#else - addPass(PM, createIPConstantPropagationPass()); // IP Constant Propagation -#endif - addPass(PM, createDeadArgEliminationPass()); // Dead argument elimination - addPass(PM, createInstructionCombiningPass()); // Clean up after IPCP & DAE - addPass(PM, createCFGSimplificationPass()); // Clean up after IPCP & DAE - - addPass(PM, createPruneEHPass()); // Remove dead EH info - addPass(PM, createPostOrderFunctionAttrsLegacyPass()); - addPass(PM, - createReversePostOrderFunctionAttrsPass()); // Deduce function attrs - - if (!DisableInline) - addPass(PM, createFunctionInliningPass()); // Inline small functions - addPass(PM, createArgumentPromotionPass()); // Scalarize uninlined fn args - - addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl. - addPass(PM, createJumpThreadingPass()); // Thread jumps. - addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs - addPass(PM, createSROAPass()); // Break up aggregate allocas - addPass(PM, createInstructionCombiningPass()); // Combine silly seq's - - addPass(PM, createTailCallEliminationPass()); // Eliminate tail calls - addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs - addPass(PM, createReassociatePass()); // Reassociate expressions - addPass(PM, createLoopRotatePass()); - addPass(PM, createLICMPass()); // Hoist loop invariants - addPass(PM, createLoopUnswitchPass()); // Unswitch loops. - // FIXME : Removing instcombine causes nestedloop regression. - addPass(PM, createInstructionCombiningPass()); - addPass(PM, createIndVarSimplifyPass()); // Canonicalize indvars - if (DeleteDeadLoops) - addPass(PM, createLoopDeletionPass()); // Delete dead loops - addPass(PM, createLoopUnrollPass()); // Unroll small loops - addPass(PM, createInstructionCombiningPass()); // Clean up after the unroller - addPass(PM, createGVNPass()); // Remove redundancies - addPass(PM, createMemCpyOptPass()); // Remove memcpy / form memset - addPass(PM, createSCCPPass()); // Constant prop with SCCP - - // Run instcombine after redundancy elimination to exploit opportunities - // opened up by them. - addPass(PM, createInstructionCombiningPass()); - - addPass(PM, createDeadStoreEliminationPass()); // Delete dead stores - addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs - addPass(PM, createStripDeadPrototypesPass()); // Get rid of dead prototypes - addPass(PM, createConstantMergePass()); // Merge dup global constants -} - -static void AddNonStandardCompilePasses(legacy::PassManager &Passes) { - - // Propagate constants at call sites into the functions they call. This - // opens opportunities for globalopt (and inlining) by substituting function - // pointers passed as arguments to direct uses of functions. - addPass(Passes, createIPSCCPPass()); - - // Now that we internalized some globals, see if we can hack on them! - addPass(Passes, createGlobalOptimizerPass()); - - // Linking modules together can lead to duplicated global constants, only - // keep one copy of each constant... - addPass(Passes, createConstantMergePass()); - - // Remove unused arguments from functions... - addPass(Passes, createDeadArgEliminationPass()); - - // Reduce the code after globalopt and ipsccp. Both can open up significant - // simplification opportunities, and both can propagate functions through - // function pointers. When this happens, we often have to resolve varargs - // calls, etc, so let instcombine do this. - addPass(Passes, createInstructionCombiningPass()); - - if (!DisableInline) - addPass(Passes, createFunctionInliningPass()); // Inline small functions - - addPass(Passes, createPruneEHPass()); // Remove dead EH info - addPass(Passes, createGlobalOptimizerPass()); // Optimize globals again. - addPass(Passes, createGlobalDCEPass()); // Remove dead functions - - // If we didn't decide to inline a function, check to see if we can - // transform it to pass arguments by value instead of by reference. - addPass(Passes, createArgumentPromotionPass()); - - // The IPO passes may leave cruft around. Clean up after them. - addPass(Passes, createInstructionCombiningPass()); - addPass(Passes, createJumpThreadingPass()); // Thread jumps. - addPass(Passes, createSROAPass()); // Break up allocas - - // Run a few AA driven optimizations here and now, to cleanup the code. - addPass(Passes, createPostOrderFunctionAttrsLegacyPass()); - addPass(Passes, createReversePostOrderFunctionAttrsPass()); // Add nocapture - addPass(Passes, createGlobalsAAWrapperPass()); // IP alias analysis - - addPass(Passes, createLICMPass()); // Hoist loop invariants - addPass(Passes, createGVNPass()); // Remove redundancies - addPass(Passes, createMemCpyOptPass()); // Remove dead memcpy's - addPass(Passes, createDeadStoreEliminationPass()); // Nuke dead stores - - // Cleanup and simplify the code after the scalar optimizations. - addPass(Passes, createInstructionCombiningPass()); - - addPass(Passes, createJumpThreadingPass()); // Thread jumps. - addPass(Passes, createPromoteMemoryToRegisterPass()); // Cleanup jumpthread. - - // Delete basic blocks, which optimization passes may have killed... - addPass(Passes, createCFGSimplificationPass()); - - // Now that we have optimized the program, discard unreachable functions... - addPass(Passes, createGlobalDCEPass()); - - // If the -s or -S command line options were specified, strip the symbols out - // of the resulting program to make it smaller. -s and -S are GNU ld options - // that we are supporting; they alias -strip-all and -strip-debug. - if (Strip || StripDebug) - addPass(Passes, createStripSymbolsPass(StripDebug && !Strip)); - - // The user's passes may leave cruft around; clean up after them. - addPass(Passes, createInstructionCombiningPass()); - addPass(Passes, createCFGSimplificationPass()); - addPass(Passes, createAggressiveDCEPass()); - addPass(Passes, createGlobalDCEPass()); -} - -/// Optimize - Perform link time optimizations. This will run the scalar -/// optimizations, any loaded plugin-optimization modules, and then the -/// inter-procedural optimizations if applicable. -void Optimize(Module *M, llvm::ArrayRef preservedFunctions) { - - // Instantiate the pass manager to organize the passes. - legacy::PassManager Passes; - - // If we're verifying, start off with a verification pass. - if (VerifyEach) - Passes.add(createVerifierPass()); - - // DWD - Run the opt standard pass list as well. - AddStandardCompilePasses(Passes); - - // Now that composite has been compiled, scan through the module, looking - // for a main function. If main is defined, mark all other functions - // internal. - if (!DisableInternalize) { - auto PreserveFunctions = [=](const GlobalValue &GV) { - StringRef GVName = GV.getName(); - - for (const char *fun : preservedFunctions) - if (GVName.equals(fun)) - return true; - - return false; - }; - ModulePass *pass = createInternalizePass(PreserveFunctions); - addPass(Passes, pass); - } - - if (OptimizeAggressive) { - AddNonStandardCompilePasses(Passes); - } - - // Run our queue of passes all at once now, efficiently. - Passes.run(*M); +using namespace klee; +void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, + bool Simplify, + bool WithFPRuntime, SwitchImplType SwitchType, + std::string EntryPoint, + llvm::ArrayRef preservedFunctions, + llvm::Module *module) { + assert(0); } -} // namespace llvm diff --git a/lib/Module/OptimizeLegacy.cpp b/lib/Module/OptimizeLegacy.cpp new file mode 100644 index 0000000000..699008fa1e --- /dev/null +++ b/lib/Module/OptimizeLegacy.cpp @@ -0,0 +1,278 @@ +// FIXME: This file is a bastard child of opt.cpp and llvm-ld's +// Optimize.cpp. This stuff should live in common code. + +//===- Optimize.cpp - Optimize a complete program -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements all optimization of the linked module for llvm-ld. +// +//===----------------------------------------------------------------------===// + +#include "klee/Config/Version.h" +#include "klee/Support/OptionCategories.h" + +#include "klee/Support/CompilerWarning.h" + +#include "ModuleHelper.h" + +DISABLE_WARNING_PUSH +DISABLE_WARNING_DEPRECATED_DECLARATIONS +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/FunctionAttrs.h" +#include "llvm/Transforms/InstCombine/InstCombine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "llvm/Transforms/Utils.h" +DISABLE_WARNING_POP + +using namespace llvm; +using namespace klee; + +namespace { +static cl::opt + DisableInline("disable-inlining", + cl::desc("Do not run the inliner pass (default=false)"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::opt DisableInternalize( + "disable-internalize", + cl::desc("Do not mark all symbols as internal (default=false)"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::opt VerifyEach("verify-each", + cl::desc("Verify intermediate results of all " + "optimization passes (default=false)"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::alias ExportDynamic("export-dynamic", + cl::aliasopt(DisableInternalize), + cl::desc("Alias for -disable-internalize")); + +static cl::opt Strip( + "strip-all", + cl::desc("Strip all symbol information from executable (default=false)"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::opt + StripDebug("strip-debug", + cl::desc("Strip debugger symbol info from executable"), + cl::init(false), cl::cat(klee::ModuleCat)); + +static cl::alias A1("S", cl::desc("Alias for --strip-debug"), + cl::aliasopt(StripDebug)); + +static cl::opt DeleteDeadLoops("delete-dead-loops", + cl::desc("Use LoopDeletionPass"), + cl::init(true), cl::cat(klee::ModuleCat)); + +static cl::opt + OptimizeAggressive("optimize-aggressive", + cl::desc("Use aggressive optimization passes"), + cl::init(true), cl::cat(klee::ModuleCat)); + +// A utility function that adds a pass to the pass manager but will also add +// a verifier pass after if we're supposed to verify. +static inline void addPass(legacy::PassManager &PM, Pass *P) { + // Add the pass to the pass manager... + PM.add(P); + + // If we are verifying all of the intermediate steps, add the verifier... + if (VerifyEach) + PM.add(createVerifierPass()); +} +} // namespace + +static void AddStandardCompilePasses(legacy::PassManager &PM) { + PM.add(createVerifierPass()); // Verify that input is correct + + // If the -strip-debug command line option was specified, do it. + if (StripDebug) + addPass(PM, createStripSymbolsPass(true)); + + addPass(PM, createCFGSimplificationPass()); // Clean up disgusting code + addPass(PM, createPromoteMemoryToRegisterPass()); // Kill useless allocas + addPass(PM, createGlobalOptimizerPass()); // Optimize out global vars + addPass(PM, createGlobalDCEPass()); // Remove unused fns and globs + addPass(PM, createSCCPPass()); // Constant prop with SCCP + addPass(PM, createDeadArgEliminationPass()); // Dead argument elimination + addPass(PM, createInstructionCombiningPass()); // Clean up after IPCP & DAE + addPass(PM, createCFGSimplificationPass()); // Clean up after IPCP & DAE + +#if LLVM_VERSION_CODE <= LLVM_VERSION(15, 0) + addPass(PM, createPruneEHPass()); // Remove dead EH info +#endif + addPass(PM, createPostOrderFunctionAttrsLegacyPass()); + addPass(PM, + createReversePostOrderFunctionAttrsPass()); // Deduce function attrs + + if (!DisableInline) + addPass(PM, createFunctionInliningPass()); // Inline small functions +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) + addPass(PM, createArgumentPromotionPass()); // Scalarize uninlined fn args +#endif + + addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl. + addPass(PM, createJumpThreadingPass()); // Thread jumps. + addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs + addPass(PM, createSROAPass()); // Break up aggregate allocas + addPass(PM, createInstructionCombiningPass()); // Combine silly seq's + + addPass(PM, createTailCallEliminationPass()); // Eliminate tail calls + addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs + addPass(PM, createReassociatePass()); // Reassociate expressions + addPass(PM, createLoopRotatePass()); + addPass(PM, createLICMPass()); // Hoist loop invariants +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) + addPass(PM, createLoopUnswitchPass()); // Unswitch loops. +#endif + // FIXME : Removing instcombine causes nestedloop regression. + addPass(PM, createInstructionCombiningPass()); + addPass(PM, createIndVarSimplifyPass()); // Canonicalize indvars + if (DeleteDeadLoops) + addPass(PM, createLoopDeletionPass()); // Delete dead loops + addPass(PM, createLoopUnrollPass()); // Unroll small loops + addPass(PM, createInstructionCombiningPass()); // Clean up after the unroller + addPass(PM, createGVNPass()); // Remove redundancies + addPass(PM, createMemCpyOptPass()); // Remove memcpy / form memset + addPass(PM, createSCCPPass()); // Constant prop with SCCP + + // Run instcombine after redundancy elimination to exploit opportunities + // opened up by them. + addPass(PM, createInstructionCombiningPass()); + + addPass(PM, createDeadStoreEliminationPass()); // Delete dead stores + addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs + addPass(PM, createStripDeadPrototypesPass()); // Get rid of dead prototypes + addPass(PM, createConstantMergePass()); // Merge dup global constants +} + +static void AddNonStandardCompilePasses(legacy::PassManager &Passes) { + + // Propagate constants at call sites into the functions they call. This + // opens opportunities for globalopt (and inlining) by substituting function + // pointers passed as arguments to direct uses of functions. + addPass(Passes, createIPSCCPPass()); + + // Now that we internalized some globals, see if we can hack on them! + addPass(Passes, createGlobalOptimizerPass()); + + // Linking modules together can lead to duplicated global constants, only + // keep one copy of each constant... + addPass(Passes, createConstantMergePass()); + + // Remove unused arguments from functions... + addPass(Passes, createDeadArgEliminationPass()); + + // Reduce the code after globalopt and ipsccp. Both can open up significant + // simplification opportunities, and both can propagate functions through + // function pointers. When this happens, we often have to resolve varargs + // calls, etc, so let instcombine do this. + addPass(Passes, createInstructionCombiningPass()); + + if (!DisableInline) + addPass(Passes, createFunctionInliningPass()); // Inline small functions + +#if LLVM_VERSION_CODE <= LLVM_VERSION(15, 0) + addPass(Passes, createPruneEHPass()); // Remove dead EH info +#endif + addPass(Passes, createGlobalOptimizerPass()); // Optimize globals again. + addPass(Passes, createGlobalDCEPass()); // Remove dead functions + +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) + // If we didn't decide to inline a function, check to see if we can + // transform it to pass arguments by value instead of by reference. + addPass(Passes, createArgumentPromotionPass()); +#endif + + // The IPO passes may leave cruft around. Clean up after them. + addPass(Passes, createInstructionCombiningPass()); + addPass(Passes, createJumpThreadingPass()); // Thread jumps. + addPass(Passes, createSROAPass()); // Break up allocas + + // Run a few AA driven optimizations here and now, to cleanup the code. + addPass(Passes, createPostOrderFunctionAttrsLegacyPass()); + addPass(Passes, createReversePostOrderFunctionAttrsPass()); // Add nocapture + addPass(Passes, createGlobalsAAWrapperPass()); // IP alias analysis + + addPass(Passes, createLICMPass()); // Hoist loop invariants + addPass(Passes, createGVNPass()); // Remove redundancies + addPass(Passes, createMemCpyOptPass()); // Remove dead memcpy's + addPass(Passes, createDeadStoreEliminationPass()); // Nuke dead stores + + // Cleanup and simplify the code after the scalar optimizations. + addPass(Passes, createInstructionCombiningPass()); + + addPass(Passes, createJumpThreadingPass()); // Thread jumps. + addPass(Passes, createPromoteMemoryToRegisterPass()); // Cleanup jumpthread. + + // Delete basic blocks, which optimization passes may have killed... + addPass(Passes, createCFGSimplificationPass()); + + // Now that we have optimized the program, discard unreachable functions... + addPass(Passes, createGlobalDCEPass()); + + // If the -s or -S command line options were specified, strip the symbols out + // of the resulting program to make it smaller. -s and -S are GNU ld options + // that we are supporting; they alias -strip-all and -strip-debug. + if (Strip || StripDebug) + addPass(Passes, createStripSymbolsPass(StripDebug && !Strip)); + + // The user's passes may leave cruft around; clean up after them. + addPass(Passes, createInstructionCombiningPass()); + addPass(Passes, createCFGSimplificationPass()); + addPass(Passes, createAggressiveDCEPass()); + addPass(Passes, createGlobalDCEPass()); +} + +/// Optimize - Perform link time optimizations. This will run the scalar +/// optimizations, any loaded plugin-optimization modules, and then the +/// inter-procedural optimizations if applicable. +void klee::optimizeModule(llvm::Module *M, + llvm::ArrayRef preservedFunctions) { + // Instantiate the pass manager to organize the passes. + legacy::PassManager Passes; + + // If we're verifying, start off with a verification pass. + if (VerifyEach) + Passes.add(createVerifierPass()); + + // DWD - Run the opt standard pass list as well. + AddStandardCompilePasses(Passes); + + // Now that composite has been compiled, scan through the module, looking + // for a main function. If main is defined, mark all other functions + // internal. + if (!DisableInternalize) { + auto PreserveFunctions = [=](const GlobalValue &GV) { + StringRef GVName = GV.getName(); + + for (const char *fun : preservedFunctions) + if (GVName.equals(fun)) + return true; + + return false; + }; + ModulePass *pass = createInternalizePass(PreserveFunctions); + addPass(Passes, pass); + } + + if (OptimizeAggressive) { + AddNonStandardCompilePasses(Passes); + } + + // Run our queue of passes all at once now, efficiently. + Passes.run(*M); +} diff --git a/lib/Module/RaiseAsm.cpp b/lib/Module/RaiseAsm.cpp index 6869ab2b85..acf67a71ed 100644 --- a/lib/Module/RaiseAsm.cpp +++ b/lib/Module/RaiseAsm.cpp @@ -92,8 +92,14 @@ bool RaiseAsmPass::runOnModule(Module &M) { klee_warning("Warning: unable to select target: %s", Err.c_str()); TLI = 0; } else { +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + TM = Target->createTargetMachine(TargetTriple, "", "", TargetOptions(), + std::nullopt); +#else TM = Target->createTargetMachine(TargetTriple, "", "", TargetOptions(), None); +#endif + TLI = TM->getSubtargetImpl(*(M.begin()))->getTargetLowering(); triple = llvm::Triple(TargetTriple); diff --git a/lib/Solver/AlphaEquivalenceSolver.cpp b/lib/Solver/AlphaEquivalenceSolver.cpp index a265d7d576..8e3df97617 100644 --- a/lib/Solver/AlphaEquivalenceSolver.cpp +++ b/lib/Solver/AlphaEquivalenceSolver.cpp @@ -40,7 +40,7 @@ class AlphaEquivalenceSolver : public SolverImpl { bool computeValidityCore(const Query &query, ValidityCore &validityCore, bool &isValid); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &); void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); ValidityCore changeVersion(const ValidityCore &validityCore, @@ -209,7 +209,7 @@ SolverImpl::SolverRunStatus AlphaEquivalenceSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } -char *AlphaEquivalenceSolver::getConstraintLog(const Query &query) { +std::string AlphaEquivalenceSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/AssignmentValidatingSolver.cpp b/lib/Solver/AssignmentValidatingSolver.cpp index a5fc001145..6363096fed 100644 --- a/lib/Solver/AssignmentValidatingSolver.cpp +++ b/lib/Solver/AssignmentValidatingSolver.cpp @@ -43,7 +43,7 @@ class AssignmentValidatingSolver : public SolverImpl { const std::vector &objects, std::vector> &values); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); }; @@ -174,9 +174,8 @@ void AssignmentValidatingSolver::dumpAssignmentQuery( Query augmentedQuery = query.withConstraints(constraints); // 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); + llvm::errs() << "Query with assignment as constraints:\n" + << solver->getConstraintLog(augmentedQuery) << "\n"; } SolverImpl::SolverRunStatus @@ -184,7 +183,7 @@ AssignmentValidatingSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } -char *AssignmentValidatingSolver::getConstraintLog(const Query &query) { +std::string AssignmentValidatingSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/BitwuzlaSolver.cpp b/lib/Solver/BitwuzlaSolver.cpp index 5e6a2c35d3..b6fcadd567 100644 --- a/lib/Solver/BitwuzlaSolver.cpp +++ b/lib/Solver/BitwuzlaSolver.cpp @@ -263,7 +263,7 @@ class BitwuzlaSolverImpl : public SolverImpl { ValidityCore &validityCore, bool &isValid); public: - char *getConstraintLog(const Query &) final; + std::string getConstraintLog(const Query &) final; SolverImpl::SolverRunStatus getOperationStatusCode() final; void setCoreSolverTimeout(time::Span _timeout) final { timeout = _timeout; } void enableUnsatCore() { @@ -311,7 +311,7 @@ BitwuzlaSolverImpl::BitwuzlaSolverImpl() } } -char *BitwuzlaSolverImpl::getConstraintLog(const Query &query) { +std::string BitwuzlaSolverImpl::getConstraintLog(const Query &query) { std::stringstream outputLog; // We use a different builder here because we don't want to interfere diff --git a/lib/Solver/CachingSolver.cpp b/lib/Solver/CachingSolver.cpp index 4f238f50c2..f14d7bdc7b 100644 --- a/lib/Solver/CachingSolver.cpp +++ b/lib/Solver/CachingSolver.cpp @@ -86,7 +86,7 @@ class CachingSolver : public SolverImpl { bool computeValidityCore(const Query &, ValidityCore &validityCore, bool &isValid); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); }; @@ -293,7 +293,7 @@ SolverImpl::SolverRunStatus CachingSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } -char *CachingSolver::getConstraintLog(const Query &query) { +std::string CachingSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/CexCachingSolver.cpp b/lib/Solver/CexCachingSolver.cpp index 69f347b608..de6809d6ef 100644 --- a/lib/Solver/CexCachingSolver.cpp +++ b/lib/Solver/CexCachingSolver.cpp @@ -46,16 +46,10 @@ cl::opt "before asking the SMT solver (default=false)"), cl::cat(SolvingCat)); -cl::opt CexCacheExperimental( - "cex-cache-exp", cl::init(false), - cl::desc("Optimization for validity queries (default=false)"), - cl::cat(SolvingCat)); - cl::opt CexCacheValidityCores( "cex-cache-validity-cores", cl::init(false), cl::desc("Cache assignment and it's validity cores (default=false)"), cl::cat(SolvingCat)); - } // namespace /// @@ -107,7 +101,7 @@ class CexCachingSolver : public SolverImpl { bool computeValidityCore(const Query &, ValidityCore &validityCore, bool &isValid); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &query); + std::string getConstraintLog(const Query &query) final; void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); }; @@ -332,20 +326,6 @@ bool CexCachingSolver::computeValidity(const Query &query, bool CexCachingSolver::computeTruth(const Query &query, bool &isValid) { TimerStatIncrementer t(stats::cexCacheTime); - // There is a small amount of redundancy here. We only need to know - // truth and do not really need to compute an assignment. This means - // that we could check the cache to see if we already know that - // state ^ query has no assignment. In that case, by the validity of - // state, we know that state ^ !query must have an assignment, and - // so query cannot be true (valid). This does get hits, but doesn't - // really seem to be worth the overhead. - - if (CexCacheExperimental) { - ref a; - if (lookupResponse(query.negateExpr(), a) && isa(a)) - return false; - } - ref a; if (!getResponse(query, a)) return false; @@ -445,7 +425,7 @@ SolverImpl::SolverRunStatus CexCachingSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } -char *CexCachingSolver::getConstraintLog(const Query &query) { +std::string CexCachingSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/ConcretizingSolver.cpp b/lib/Solver/ConcretizingSolver.cpp index 1d2a75047c..9d918d32fe 100644 --- a/lib/Solver/ConcretizingSolver.cpp +++ b/lib/Solver/ConcretizingSolver.cpp @@ -56,7 +56,7 @@ class ConcretizingSolver : public SolverImpl { const Query &query, const std::vector &objects, std::vector> &values, bool &hasSolution); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &); void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); @@ -401,7 +401,7 @@ bool ConcretizingSolver::check(const Query &query, return true; } -char *ConcretizingSolver::getConstraintLog(const Query &query) { +std::string ConcretizingSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/IncompleteSolver.cpp b/lib/Solver/IncompleteSolver.cpp index cfdac3375f..7027ee010e 100644 --- a/lib/Solver/IncompleteSolver.cpp +++ b/lib/Solver/IncompleteSolver.cpp @@ -145,7 +145,7 @@ SolverImpl::SolverRunStatus StagedSolverImpl::getOperationStatusCode() { return secondary->impl->getOperationStatusCode(); } -char *StagedSolverImpl::getConstraintLog(const Query &query) { +std::string StagedSolverImpl::getConstraintLog(const Query &query) { return secondary->impl->getConstraintLog(query); } diff --git a/lib/Solver/IndependentSolver.cpp b/lib/Solver/IndependentSolver.cpp index e0f4e41ade..b5c1d69718 100644 --- a/lib/Solver/IndependentSolver.cpp +++ b/lib/Solver/IndependentSolver.cpp @@ -46,7 +46,7 @@ class IndependentSolver : public SolverImpl { bool computeValidityCore(const Query &query, ValidityCore &validityCore, bool &isValid); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); }; @@ -340,7 +340,7 @@ SolverImpl::SolverRunStatus IndependentSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } -char *IndependentSolver::getConstraintLog(const Query &query) { +std::string IndependentSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/MetaSMTSolver.cpp b/lib/Solver/MetaSMTSolver.cpp index 905a568d65..cff8fc2f3b 100644 --- a/lib/Solver/MetaSMTSolver.cpp +++ b/lib/Solver/MetaSMTSolver.cpp @@ -91,7 +91,7 @@ template class MetaSMTSolverImpl : public SolverImpl { MetaSMTSolverImpl(MetaSMTSolver *solver, bool useForked, bool optimizeDivides); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout) { _timeout = timeout; } void notifyStateTermination(std::uint32_t) {} @@ -138,11 +138,8 @@ MetaSMTSolverImpl::MetaSMTSolverImpl( } template -char *MetaSMTSolverImpl::getConstraintLog(const Query &) { - const char *msg = "Not supported"; - char *buf = new char[strlen(msg) + 1]; - strcpy(buf, msg); - return buf; +std::string MetaSMTSolverImpl::getConstraintLog(const Query &) { + return {"Not supported"}; } template @@ -436,7 +433,7 @@ template MetaSMTSolver::~MetaSMTSolver() {} template -char *MetaSMTSolver::getConstraintLog(const Query &query) { +std::string MetaSMTSolver::getConstraintLog(const Query &query) { return impl->getConstraintLog(query); } diff --git a/lib/Solver/MetaSMTSolver.h b/lib/Solver/MetaSMTSolver.h index 636fb91294..d9e5554ff4 100644 --- a/lib/Solver/MetaSMTSolver.h +++ b/lib/Solver/MetaSMTSolver.h @@ -22,7 +22,7 @@ template class MetaSMTSolver : public Solver { MetaSMTSolver(bool useForked, bool optimizeDivides); virtual ~MetaSMTSolver(); - virtual char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; virtual void setCoreSolverTimeout(time::Span timeout); }; diff --git a/lib/Solver/QueryLoggingSolver.cpp b/lib/Solver/QueryLoggingSolver.cpp index 8527547295..71cf6aa216 100644 --- a/lib/Solver/QueryLoggingSolver.cpp +++ b/lib/Solver/QueryLoggingSolver.cpp @@ -312,7 +312,7 @@ SolverImpl::SolverRunStatus QueryLoggingSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } -char *QueryLoggingSolver::getConstraintLog(const Query &query) { +std::string QueryLoggingSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/QueryLoggingSolver.h b/lib/Solver/QueryLoggingSolver.h index 314f47ab32..b5b3d11439 100644 --- a/lib/Solver/QueryLoggingSolver.h +++ b/lib/Solver/QueryLoggingSolver.h @@ -74,7 +74,7 @@ class QueryLoggingSolver : public SolverImpl { bool computeValidityCore(const Query &query, ValidityCore &validityCore, bool &isValid); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); }; diff --git a/lib/Solver/STPSolver.cpp b/lib/Solver/STPSolver.cpp index 455da3749e..053b34824a 100644 --- a/lib/Solver/STPSolver.cpp +++ b/lib/Solver/STPSolver.cpp @@ -98,7 +98,7 @@ class STPSolverImpl : public SolverImpl { explicit STPSolverImpl(bool useForkedSTP, bool optimizeDivides = true); ~STPSolverImpl() override; - char *getConstraintLog(const Query &) override; + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout) override { this->timeout = timeout; } @@ -201,7 +201,7 @@ STPSolverImpl::~STPSolverImpl() { /***/ -char *STPSolverImpl::getConstraintLog(const Query &query) { +std::string STPSolverImpl::getConstraintLog(const Query &query) { vc_push(vc); for (const auto &constraint : query.constraints.cs()) @@ -214,7 +214,10 @@ char *STPSolverImpl::getConstraintLog(const Query &query) { vc_printQueryStateToBuffer(vc, builder->getFalse(), &buffer, &length, false); vc_pop(vc); - return buffer; + std::string result = buffer; + std::free(buffer); + + return result; } bool STPSolverImpl::computeTruth(const Query &query, bool &isValid) { @@ -476,7 +479,7 @@ SolverImpl::SolverRunStatus STPSolverImpl::getOperationStatusCode() { STPSolver::STPSolver(bool useForkedSTP, bool optimizeDivides) : Solver(std::make_unique(useForkedSTP, optimizeDivides)) {} -char *STPSolver::getConstraintLog(const Query &query) { +std::string STPSolver::getConstraintLog(const Query &query) { return impl->getConstraintLog(query); } diff --git a/lib/Solver/STPSolver.h b/lib/Solver/STPSolver.h index ab4bb700f5..873ed3dbd6 100644 --- a/lib/Solver/STPSolver.h +++ b/lib/Solver/STPSolver.h @@ -27,7 +27,7 @@ class STPSolver : public Solver { /// getConstraintLog - Return the constraint log for the given state in CVC /// format. - virtual char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; /// setCoreSolverTimeout - Set constraint solver timeout delay to the given /// value; 0 diff --git a/lib/Solver/Solver.cpp b/lib/Solver/Solver.cpp index 0050870f5a..98c830f0df 100644 --- a/lib/Solver/Solver.cpp +++ b/lib/Solver/Solver.cpp @@ -34,7 +34,7 @@ const char *Solver::validity_to_str(Validity v) { Solver::Solver(std::unique_ptr impl) : impl(std::move(impl)) {} Solver::~Solver() = default; -char *Solver::getConstraintLog(const Query &query) { +std::string Solver::getConstraintLog(const Query &query) { return impl->getConstraintLog(query); } diff --git a/lib/Solver/SolverCmdLine.cpp b/lib/Solver/SolverCmdLine.cpp index ae2f49d5d8..2f36e881ec 100644 --- a/lib/Solver/SolverCmdLine.cpp +++ b/lib/Solver/SolverCmdLine.cpp @@ -131,15 +131,24 @@ cl::opt " Set to 0 to disable (default=0)"), cl::init(0), cl::cat(SolvingCat)); -void KCommandLine::HideOptions(llvm::cl::OptionCategory &Category) { +void KCommandLine::KeepOnlyCategories( + std::set const &categories) { StringMap &map = cl::getRegisteredOptions(); for (auto &elem : map) { + if (elem.first() == "version" || elem.first() == "color" || + elem.first() == "help" || elem.first() == "help-list") + continue; + + bool keep = false; for (auto &cat : elem.second->Categories) { - if (cat == &Category) { - elem.second->setHiddenFlag(cl::Hidden); + if (categories.find(cat) != categories.end()) { + keep = true; + break; } } + if (!keep) + elem.second->setHiddenFlag(cl::Hidden); } } // namespace klee diff --git a/lib/Solver/ValidatingSolver.cpp b/lib/Solver/ValidatingSolver.cpp index 5681febb58..ce0c3fd437 100644 --- a/lib/Solver/ValidatingSolver.cpp +++ b/lib/Solver/ValidatingSolver.cpp @@ -41,7 +41,7 @@ class ValidatingSolver : public SolverImpl { bool computeValidityCore(const Query &query, ValidityCore &validityCore, bool &isValid); SolverRunStatus getOperationStatusCode(); - char *getConstraintLog(const Query &); + std::string getConstraintLog(const Query &) final; void setCoreSolverTimeout(time::Span timeout); void notifyStateTermination(std::uint32_t id); }; @@ -219,7 +219,7 @@ SolverImpl::SolverRunStatus ValidatingSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } -char *ValidatingSolver::getConstraintLog(const Query &query) { +std::string ValidatingSolver::getConstraintLog(const Query &query) { return solver->impl->getConstraintLog(query); } diff --git a/lib/Solver/Z3Solver.cpp b/lib/Solver/Z3Solver.cpp index caf530b4c9..bf94993bdf 100644 --- a/lib/Solver/Z3Solver.cpp +++ b/lib/Solver/Z3Solver.cpp @@ -257,7 +257,7 @@ class Z3SolverImpl : public SolverImpl { ValidityCore &validityCore, bool &isValid); public: - char *getConstraintLog(const Query &) final; + std::string getConstraintLog(const Query &) final; SolverImpl::SolverRunStatus getOperationStatusCode() final; void setCoreSolverTimeout(time::Span _timeout) final { timeout = _timeout; @@ -348,7 +348,11 @@ Z3SolverImpl::~Z3SolverImpl() { Z3_params_dec_ref(builder->ctx, solverParameters); } -char *Z3SolverImpl::getConstraintLog(const Query &query) { +std::string Z3Solver::getConstraintLog(const Query &query) { + return impl->getConstraintLog(query); +} + +std::string Z3SolverImpl::getConstraintLog(const Query &query) { std::vector assumptions; // We use a different builder here because we don't want to interfere // with the solver's builder because it may change the solver builder's @@ -393,35 +397,26 @@ char *Z3SolverImpl::getConstraintLog(const Query &query) { } } - ::Z3_ast *assumptionsArray = NULL; - int numAssumptions = assumptions.size(); - if (numAssumptions) { - assumptionsArray = (::Z3_ast *)malloc(sizeof(::Z3_ast) * numAssumptions); - for (int index = 0; index < numAssumptions; ++index) { - assumptionsArray[index] = (::Z3_ast)assumptions[index]; - } - } - + std::vector<::Z3_ast> raw_assumptions{assumptions.cbegin(), + assumptions.cend()}; ::Z3_string result = Z3_benchmark_to_smtlib_string( temp_builder->ctx, /*name=*/"Emited by klee::Z3SolverImpl::getConstraintLog()", /*logic=*/"", /*status=*/"unknown", /*attributes=*/"", - /*num_assumptions=*/numAssumptions, - /*assumptions=*/assumptionsArray, + /*num_assumptions=*/raw_assumptions.size(), + /*assumptions=*/raw_assumptions.size() ? raw_assumptions.data() : nullptr, /*formula=*/formula); - if (numAssumptions) - free(assumptionsArray); - // We need to trigger a dereference before the `temp_builder` gets destroyed. // We do this indirectly by emptying `assumptions` and assigning to // `formula`. + raw_assumptions.clear(); assumptions.clear(); formula = Z3ASTHandle(NULL, temp_builder->ctx); - // Client is responsible for freeing the returned C-string - return strdup(result); + + return {result}; } bool Z3SolverImpl::computeTruth(const ConstraintQuery &query, Z3SolverEnv &env, diff --git a/lib/Solver/Z3Solver.h b/lib/Solver/Z3Solver.h index 6b4aca126b..164b1e0a14 100644 --- a/lib/Solver/Z3Solver.h +++ b/lib/Solver/Z3Solver.h @@ -23,6 +23,10 @@ class Z3Solver : public Solver { public: /// Z3Solver - Construct a new Z3Solver. Z3Solver(Z3BuilderType type); + + /// Get the query in SMT-LIBv2 format. + /// \return A C-style string. The caller is responsible for freeing this. + std::string getConstraintLog(const Query &) final; }; class Z3TreeSolver : public Solver { diff --git a/runtime/POSIX/fd.c b/runtime/POSIX/fd.c index 9c7052d5c1..e0ff2a1939 100644 --- a/runtime/POSIX/fd.c +++ b/runtime/POSIX/fd.c @@ -105,34 +105,20 @@ mode_t umask(mode_t mask) { } /* Returns 1 if the process has the access rights specified by 'flags' - to the file with stat 's'. Returns 0 otherwise*/ + to the file with stat 's', and returns 0 otherwise. + We allow access if any user has access to the file, so we ignore + s->st_uid / geteuid() and s->st_gid / getegid(). */ static int has_permission(int flags, struct stat64 *s) { - int write_access, read_access; mode_t mode = s->st_mode; - - if (flags & O_RDONLY || flags & O_RDWR) - read_access = 1; - else - read_access = 0; - - if (flags & O_WRONLY || flags & O_RDWR) - write_access = 1; - else - write_access = 0; - - /* XXX: We don't worry about process uid and gid for now. - We allow access if any user has access to the file. */ -#if 0 - uid_t uid = s->st_uid; - uid_t euid = geteuid(); - gid_t gid = s->st_gid; - gid_t egid = getegid(); -#endif - - if (read_access && ((mode & S_IRUSR) | (mode & S_IRGRP) | (mode & S_IROTH))) - return 0; - - if (write_access && !((mode & S_IWUSR) | (mode & S_IWGRP) | (mode & S_IWOTH))) + int read_request = ((flags & O_RDONLY) | (flags & O_RDWR)) ? 1 : 0; + int write_request = ((flags & O_WRONLY) | (flags & O_RDWR)) ? 1 : 0; + + /* It is important to do this check using only bitwise operators so that we + return 0 a single time in symbolic execution mode. */ + if ((read_request & + !((mode & S_IRUSR) | (mode & S_IRGRP) | (mode & S_IROTH))) | + (write_request & + !((mode & S_IWUSR) | (mode & S_IWGRP) | (mode & S_IWOTH)))) return 0; return 1; diff --git a/runtime/Sanitizer/ubsan/ubsan_checks.inc b/runtime/Sanitizer/ubsan/ubsan_checks.inc index 964dfc99b1..15952675bd 100644 --- a/runtime/Sanitizer/ubsan/ubsan_checks.inc +++ b/runtime/Sanitizer/ubsan/ubsan_checks.inc @@ -26,17 +26,13 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") -#if LLVM_VERSION_MAJOR >= 11 UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use", "nullability-assign") -#endif -#if LLVM_VERSION_MAJOR >= 10 UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow") UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset", "pointer-overflow") UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset", "pointer-overflow") -#endif UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") @@ -49,9 +45,7 @@ UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero", "integer-divide-by-zero") UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero") UBSAN_CHECK(InvalidBuiltin, "invalid-builtin-use", "invalid-builtin-use") -#if LLVM_VERSION_MAJOR >= 11 UBSAN_CHECK(InvalidObjCCast, "invalid-objc-cast", "invalid-objc-cast") -#endif UBSAN_CHECK(ImplicitUnsignedIntegerTruncation, "implicit-unsigned-integer-truncation", "implicit-unsigned-integer-truncation") @@ -75,14 +69,10 @@ UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum") UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function") UBSAN_CHECK(InvalidNullReturn, "invalid-null-return", "returns-nonnull-attribute") -#if LLVM_VERSION_MAJOR >= 11 UBSAN_CHECK(InvalidNullReturnWithNullability, "invalid-null-return", "nullability-return") -#endif UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute") -#if LLVM_VERSION_MAJOR >= 11 UBSAN_CHECK(InvalidNullArgumentWithNullability, "invalid-null-argument", "nullability-arg") -#endif UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr") UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi") diff --git a/runtime/Sanitizer/ubsan/ubsan_handlers.cpp b/runtime/Sanitizer/ubsan/ubsan_handlers.cpp index 0213836bf5..c1f94bebc2 100644 --- a/runtime/Sanitizer/ubsan/ubsan_handlers.cpp +++ b/runtime/Sanitizer/ubsan/ubsan_handlers.cpp @@ -45,14 +45,10 @@ static const char *get_suffix(ErrorType ET) { // It should never happen in KLEE runtime. return "exec.err"; case ErrorType::NullPointerUse: -#if LLVM_VERSION_MAJOR >= 11 case ErrorType::NullPointerUseWithNullability: -#endif -#if LLVM_VERSION_MAJOR >= 10 case ErrorType::NullptrWithOffset: case ErrorType::NullptrWithNonZeroOffset: case ErrorType::NullptrAfterNonZeroOffset: -#endif case ErrorType::PointerOverflow: case ErrorType::MisalignedPointerUse: case ErrorType::AlignmentAssumption: @@ -69,12 +65,10 @@ static const char *get_suffix(ErrorType ET) { return "div.err"; case ErrorType::InvalidBuiltin: return "invalid_builtin_use.err"; -#if LLVM_VERSION_MAJOR >= 11 case ErrorType::InvalidObjCCast: // Option `fsanitize=objc-cast` is not supported due to the requirement for // Darwin system. return "exec.err"; -#endif case ErrorType::ImplicitUnsignedIntegerTruncation: case ErrorType::ImplicitSignedIntegerTruncation: return "implicit_truncation.err"; @@ -101,13 +95,9 @@ static const char *get_suffix(ErrorType ET) { // This check is unsupported return "exec.err"; case ErrorType::InvalidNullReturn: -#if LLVM_VERSION_MAJOR >= 11 case ErrorType::InvalidNullReturnWithNullability: -#endif case ErrorType::InvalidNullArgument: -#if LLVM_VERSION_MAJOR >= 11 case ErrorType::InvalidNullArgumentWithNullability: -#endif return "nullable_attribute.err"; case ErrorType::DynamicTypeMismatch: case ErrorType::CFIBadType: @@ -122,7 +112,6 @@ __attribute__((noreturn)) static void report_error_type(ErrorType ET) { report_error(ConvertTypeToString(ET), get_suffix(ET)); } -#if LLVM_VERSION_MAJOR >= 11 /// Situations in which we might emit a check for the suitability of a /// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in /// clang. @@ -161,20 +150,15 @@ enum TypeCheckKind { /// null or an object within its lifetime. TCK_DynamicOperation }; -#endif static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer) { uptr Alignment = (uptr)1 << Data->LogAlignment; ErrorType ET; if (!Pointer) -#if LLVM_VERSION_MAJOR >= 11 ET = (Data->TypeCheckKind == TCK_NonnullAssign) ? ErrorType::NullPointerUseWithNullability : ErrorType::NullPointerUse; -#else - ET = ErrorType::NullPointerUse; -#endif else if (Pointer & (Alignment - 1)) ET = ErrorType::MisalignedPointerUse; else @@ -440,12 +424,8 @@ extern "C" void __ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) { static void handleNonNullReturn(NonNullReturnData * /*Data*/, SourceLocation * /*LocPtr*/, bool IsAttr) { -#if LLVM_VERSION_MAJOR >= 11 ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn : ErrorType::InvalidNullReturnWithNullability; -#else - ErrorType ET = ErrorType::InvalidNullReturn; -#endif report_error_type(ET); } @@ -471,12 +451,8 @@ __ubsan_handle_nullability_return_v1_abort(NonNullReturnData *Data, } static void handleNonNullArg(NonNullArgData * /*Data*/, bool IsAttr) { -#if LLVM_VERSION_MAJOR >= 11 ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument : ErrorType::InvalidNullArgumentWithNullability; -#else - ErrorType ET = ErrorType::InvalidNullArgument; -#endif report_error_type(ET); } @@ -499,7 +475,6 @@ extern "C" void __ubsan_handle_nullability_arg_abort(NonNullArgData *Data) { static void handlePointerOverflowImpl(PointerOverflowData * /*Data*/, ValueHandle Base, ValueHandle Result) { -#if LLVM_VERSION_MAJOR >= 10 ErrorType ET; if (Base == 0 && Result == 0) ET = ErrorType::NullptrWithOffset; @@ -509,9 +484,6 @@ static void handlePointerOverflowImpl(PointerOverflowData * /*Data*/, ET = ErrorType::NullptrAfterNonZeroOffset; else ET = ErrorType::PointerOverflow; -#else - ErrorType ET = ErrorType::PointerOverflow; -#endif report_error_type(ET); } diff --git a/runtime/klee-libc/memchr.c b/runtime/klee-libc/memchr.c index 927c368ef2..3cd47cdf1c 100644 --- a/runtime/klee-libc/memchr.c +++ b/runtime/klee-libc/memchr.c @@ -36,10 +36,7 @@ #include -void *memchr(s, c, n) const void *s; -int c; -size_t n; -{ +void *memchr(const void *s, int c, size_t n) { if (n != 0) { const unsigned char *p = s; diff --git a/scripts/build/p-clang-linux-ubuntu-22.04.inc b/scripts/build/p-clang-linux-ubuntu-22.04.inc index dc125bd57f..8220b1f823 100644 --- a/scripts/build/p-clang-linux-ubuntu-22.04.inc +++ b/scripts/build/p-clang-linux-ubuntu-22.04.inc @@ -1,8 +1,4 @@ get_docker_config_id_clang() { - if [[ "${LLVM_VERSION_SHORT}" -ge "11" ]]; then echo "" return 0; - else - return 1; - fi } diff --git a/scripts/build/p-klee.inc b/scripts/build/p-klee.inc index 7f84e0a998..df87f94840 100644 --- a/scripts/build/p-klee.inc +++ b/scripts/build/p-klee.inc @@ -25,6 +25,7 @@ build_klee() { "-DENABLE_SYSTEM_TESTS=TRUE" "-DENABLE_DOXYGEN=${ENABLE_DOXYGEN}" "-DLIT_ARGS=\"-v;--time-tests\"" + "-DENABLE_WARNINGS_AS_ERRORS=${ENABLE_WARNINGS_AS_ERRORS}" ) diff --git a/scripts/build/patches/llvm90.patch b/scripts/build/patches/llvm90.patch deleted file mode 100644 index 3ff0dc2904..0000000000 --- a/scripts/build/patches/llvm90.patch +++ /dev/null @@ -1,114 +0,0 @@ -diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc -index 490a04b21..42e43a044 100644 ---- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc -+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc -@@ -366,15 +366,6 @@ static void ioctl_table_fill() { - - #if SANITIZER_LINUX && !SANITIZER_ANDROID - // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE -- _(CYGETDEFTHRESH, WRITE, sizeof(int)); -- _(CYGETDEFTIMEOUT, WRITE, sizeof(int)); -- _(CYGETMON, WRITE, struct_cyclades_monitor_sz); -- _(CYGETTHRESH, WRITE, sizeof(int)); -- _(CYGETTIMEOUT, WRITE, sizeof(int)); -- _(CYSETDEFTHRESH, NONE, 0); -- _(CYSETDEFTIMEOUT, NONE, 0); -- _(CYSETTHRESH, NONE, 0); -- _(CYSETTIMEOUT, NONE, 0); - _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz); - _(EQL_ENSLAVE, WRITE, struct_ifreq_sz); - _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz); -diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc -index b7fa6e8f7..fa981e129 100644 ---- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc -+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc -@@ -126,7 +126,6 @@ typedef struct user_fpregs elf_fpregset_t; - # include - #endif - #include --#include - #include - #include - #include -@@ -437,7 +436,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - - #if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); -- unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor); - #if EV_VERSION > (0x010000) - unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry); - #else -@@ -803,15 +801,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - #endif // SANITIZER_LINUX - - #if SANITIZER_LINUX && !SANITIZER_ANDROID -- unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH; -- unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT; -- unsigned IOCTL_CYGETMON = CYGETMON; -- unsigned IOCTL_CYGETTHRESH = CYGETTHRESH; -- unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT; -- unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH; -- unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT; -- unsigned IOCTL_CYSETTHRESH = CYSETTHRESH; -- unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT; - unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE; - unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE; - unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG; -@@ -1126,8 +1115,9 @@ CHECK_SIZE_AND_OFFSET(ipc_perm, uid); - CHECK_SIZE_AND_OFFSET(ipc_perm, gid); - CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); - CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); --#if !defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21) --/* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */ -+#if !SANITIZER_LINUX || __GLIBC_PREREQ (2, 31) -+/* glibc 2.30 and earlier provided 16-bit mode field instead of 32-bit -+ on many architectures. */ - CHECK_SIZE_AND_OFFSET(ipc_perm, mode); - #endif - -diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h -index f1a4fd7d3..029a209fc 100644 ---- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h -+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h -@@ -203,26 +203,13 @@ namespace __sanitizer { - u64 __unused1; - u64 __unused2; - #elif defined(__sparc__) --#if defined(__arch64__) - unsigned mode; -- unsigned short __pad1; --#else -- unsigned short __pad1; -- unsigned short mode; - unsigned short __pad2; --#endif - unsigned short __seq; - unsigned long long __unused1; - unsigned long long __unused2; --#elif defined(__mips__) || defined(__aarch64__) || defined(__s390x__) -- unsigned int mode; -- unsigned short __seq; -- unsigned short __pad1; -- unsigned long __unused1; -- unsigned long __unused2; - #else -- unsigned short mode; -- unsigned short __pad1; -+ unsigned int mode; - unsigned short __seq; - unsigned short __pad2; - #if defined(__x86_64__) && !defined(_LP64) -diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt -index 901f55c99..7cb78afe5 100644 ---- a/llvm/tools/llvm-shlib/CMakeLists.txt -+++ b/llvm/tools/llvm-shlib/CMakeLists.txt -@@ -44,7 +44,9 @@ if(LLVM_BUILD_LLVM_DYLIB) - endif() - add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB SONAME ${INSTALL_WITH_TOOLCHAIN} ${SOURCES}) - -+ if(LIB_NAMES) - list(REMOVE_DUPLICATES LIB_NAMES) -+ endif() - if(("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") OR (MINGW) OR (HAIKU) - OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") - OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU") diff --git a/test/ArrayOpt/test_feasible.c b/test/ArrayOpt/test_feasible.c index 3427c2d110..0fe736bd02 100644 --- a/test/ArrayOpt/test_feasible.c +++ b/test/ArrayOpt/test_feasible.c @@ -23,6 +23,7 @@ // CHECK-CONST_ARR: const_arr #include "klee/klee.h" +#include #include char array[5] = {0, 1, 0, 1, 0}; diff --git a/test/CXX/LandingPad.cpp b/test/CXX/LandingPad.cpp index 18cad7c8a7..6b6e6748d5 100644 --- a/test/CXX/LandingPad.cpp +++ b/test/CXX/LandingPad.cpp @@ -1,3 +1,5 @@ +// REQUIRES: lt-llvm-15.0 +// Different LLVM IR syntax with opaque ptr - it's a nullptr directly, no constant // RUN: %clangxx %s -emit-llvm -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/atexit.cpp b/test/CXX/symex/libc++/atexit.cpp index fa8df47526..d084958b8a 100644 --- a/test/CXX/symex/libc++/atexit.cpp +++ b/test/CXX/symex/libc++/atexit.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: uclibc -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/can_catch_test.cpp b/test/CXX/symex/libc++/can_catch_test.cpp index 7515ef33d8..f93b69cab6 100644 --- a/test/CXX/symex/libc++/can_catch_test.cpp +++ b/test/CXX/symex/libc++/can_catch_test.cpp @@ -3,7 +3,7 @@ // REQUIRES: uclibc // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c -I "%libcxx_include" -g -nostdinc++ -o %t.bc +// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c %libcxx_includes -g -nostdinc++ -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libcxx --libc=uclibc %t.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/catch_recover.cpp b/test/CXX/symex/libc++/catch_recover.cpp index c77bea9182..8eee326a71 100644 --- a/test/CXX/symex/libc++/catch_recover.cpp +++ b/test/CXX/symex/libc++/catch_recover.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/catch_with_adjusted_exception_pointer.cpp b/test/CXX/symex/libc++/catch_with_adjusted_exception_pointer.cpp index 429da8b69a..c06c632f4b 100644 --- a/test/CXX/symex/libc++/catch_with_adjusted_exception_pointer.cpp +++ b/test/CXX/symex/libc++/catch_with_adjusted_exception_pointer.cpp @@ -3,7 +3,7 @@ // REQUIRES: uclibc // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c -I "%libcxx_include" -g -nostdinc++ -o %t.bc +// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c %libcxx_includes -g -nostdinc++ -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libcxx --libc=uclibc %t.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/cout.cpp b/test/CXX/symex/libc++/cout.cpp index d6d0613a7f..904534d96a 100644 --- a/test/CXX/symex/libc++/cout.cpp +++ b/test/CXX/symex/libc++/cout.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: uclibc -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/cout_sym.cpp b/test/CXX/symex/libc++/cout_sym.cpp index 177c3ed737..69420ac93a 100644 --- a/test/CXX/symex/libc++/cout_sym.cpp +++ b/test/CXX/symex/libc++/cout_sym.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: uclibc -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/dynamic_cast.cpp b/test/CXX/symex/libc++/dynamic_cast.cpp index a2fc8b82ac..f8a039ce06 100644 --- a/test/CXX/symex/libc++/dynamic_cast.cpp +++ b/test/CXX/symex/libc++/dynamic_cast.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: uclibc -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc diff --git a/test/CXX/symex/libc++/exception.cpp b/test/CXX/symex/libc++/exception.cpp index 4d6805f65d..c36db2d939 100644 --- a/test/CXX/symex/libc++/exception.cpp +++ b/test/CXX/symex/libc++/exception.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/exception_inheritance.cpp b/test/CXX/symex/libc++/exception_inheritance.cpp index e24be60da2..b41c851a90 100644 --- a/test/CXX/symex/libc++/exception_inheritance.cpp +++ b/test/CXX/symex/libc++/exception_inheritance.cpp @@ -3,7 +3,7 @@ // REQUIRES: uclibc // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c -I "%libcxx_include" -g -nostdinc++ -o %t.bc +// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c %libcxx_includes -g -nostdinc++ -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libcxx --libc=uclibc %t.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/general_catch.cpp b/test/CXX/symex/libc++/general_catch.cpp index c544f7a3a1..eb045d169e 100644 --- a/test/CXX/symex/libc++/general_catch.cpp +++ b/test/CXX/symex/libc++/general_catch.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/landingpad.cpp b/test/CXX/symex/libc++/landingpad.cpp index 6e8b13bcd6..02be8bcb98 100644 --- a/test/CXX/symex/libc++/landingpad.cpp +++ b/test/CXX/symex/libc++/landingpad.cpp @@ -6,7 +6,7 @@ // REQUIRES: uclibc // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c -I "%libcxx_include" -g -nostdinc++ -o %t.bc +// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c %libcxx_includes -g -nostdinc++ -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libcxx --libc=uclibc %t.bc | FileCheck %s // Expect the following output: diff --git a/test/CXX/symex/libc++/multi_throw.cpp b/test/CXX/symex/libc++/multi_throw.cpp index 52e8d9b982..626585f4bd 100644 --- a/test/CXX/symex/libc++/multi_throw.cpp +++ b/test/CXX/symex/libc++/multi_throw.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/multi_unwind.cpp b/test/CXX/symex/libc++/multi_unwind.cpp index cf29422cda..ab8d7a5c1b 100644 --- a/test/CXX/symex/libc++/multi_unwind.cpp +++ b/test/CXX/symex/libc++/multi_unwind.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/nested.cpp b/test/CXX/symex/libc++/nested.cpp index 2122264246..1273a3b9e2 100644 --- a/test/CXX/symex/libc++/nested.cpp +++ b/test/CXX/symex/libc++/nested.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/nested_fail.cpp b/test/CXX/symex/libc++/nested_fail.cpp index d0b8ca0936..fe2df4c996 100644 --- a/test/CXX/symex/libc++/nested_fail.cpp +++ b/test/CXX/symex/libc++/nested_fail.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s @@ -24,4 +24,4 @@ int main(int argc, char **args) { } return 0; } -// CHECK: terminating with uncaught exception of type char* +// CHECK: terminating {{.*}} uncaught exception of type char* diff --git a/test/CXX/symex/libc++/rethrow.cpp b/test/CXX/symex/libc++/rethrow.cpp index febdf0b3e9..9e150d3858 100644 --- a/test/CXX/symex/libc++/rethrow.cpp +++ b/test/CXX/symex/libc++/rethrow.cpp @@ -3,7 +3,7 @@ // REQUIRES: uclibc // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c -I "%libcxx_include" -g -nostdinc++ -o %t.bc +// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c %libcxx_includes -g -nostdinc++ -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libcxx --libc=uclibc %t.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/simple_exception.cpp b/test/CXX/symex/libc++/simple_exception.cpp index 0196e1eb18..0ca8f8edf8 100644 --- a/test/CXX/symex/libc++/simple_exception.cpp +++ b/test/CXX/symex/libc++/simple_exception.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/simple_exception_fail.cpp b/test/CXX/symex/libc++/simple_exception_fail.cpp index bda2cd333f..c3e295c22a 100644 --- a/test/CXX/symex/libc++/simple_exception_fail.cpp +++ b/test/CXX/symex/libc++/simple_exception_fail.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s @@ -11,4 +11,4 @@ int main(int argc, char **args) { throw std::runtime_error("foo"); } -// CHECK: terminating with uncaught exception of type std::runtime_error: foo \ No newline at end of file +// CHECK: terminating {{.*}} uncaught exception of type std::runtime_error: foo \ No newline at end of file diff --git a/test/CXX/symex/libc++/symbolic_exception.cpp b/test/CXX/symex/libc++/symbolic_exception.cpp index 3f29fa04db..50d682ba1a 100644 --- a/test/CXX/symex/libc++/symbolic_exception.cpp +++ b/test/CXX/symex/libc++/symbolic_exception.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/throw_specifiers.cpp b/test/CXX/symex/libc++/throw_specifiers.cpp index 6eae7f3abd..a2ccbb76c6 100644 --- a/test/CXX/symex/libc++/throw_specifiers.cpp +++ b/test/CXX/symex/libc++/throw_specifiers.cpp @@ -5,7 +5,7 @@ // REQUIRES: uclibc // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c -I "%libcxx_include" -g -nostdinc++ -o %t.bc +// RUN: %clangxx %s -emit-llvm %O0opt -std=c++11 -c %libcxx_includes -g -nostdinc++ -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libcxx --libc=uclibc %t.bc | FileCheck %s diff --git a/test/CXX/symex/libc++/throwing_exception_destructor.cpp b/test/CXX/symex/libc++/throwing_exception_destructor.cpp index f1e0e5d447..e5e071984d 100644 --- a/test/CXX/symex/libc++/throwing_exception_destructor.cpp +++ b/test/CXX/symex/libc++/throwing_exception_destructor.cpp @@ -4,7 +4,7 @@ // REQUIRES: uclibc // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm -O0 -std=c++11 -c -I "%libcxx_include" -g -nostdinc++ -o %t.bc +// RUN: %clangxx %s -emit-llvm -O0 -std=c++11 -c %libcxx_includes -g -nostdinc++ -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libcxx --libc=uclibc --exit-on-error %t.bc diff --git a/test/CXX/symex/libc++/uncaught_exception.cpp b/test/CXX/symex/libc++/uncaught_exception.cpp index 848013a0f0..4f9444a610 100644 --- a/test/CXX/symex/libc++/uncaught_exception.cpp +++ b/test/CXX/symex/libc++/uncaught_exception.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: eh-cxx -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/CXX/symex/libc++/vector.cpp b/test/CXX/symex/libc++/vector.cpp index 6f69ad6539..33821b9e99 100644 --- a/test/CXX/symex/libc++/vector.cpp +++ b/test/CXX/symex/libc++/vector.cpp @@ -2,7 +2,7 @@ // Disabling msan because it times out on CI // REQUIRES: libcxx // REQUIRES: uclibc -// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 -I "%libcxx_include" -g -nostdinc++ -o %t1.bc +// RUN: %clangxx %s -emit-llvm %O0opt -c -std=c++11 %libcxx_includes -g -nostdinc++ -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libc=uclibc --libcxx %t1.bc 2>&1 | FileCheck %s diff --git a/test/lit.cfg b/test/lit.cfg index daac992334..66bbc05298 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -141,6 +141,11 @@ config.substitutions.append( ('%libkleeruntest', config.libkleeruntest) ) +# Add a substition for sqlite3 +config.substitutions.append( + ('%sqlite3', os.path.abspath(config.sqlite3)) +) + # Get KLEE and Kleaver specific parameters passed on llvm-lit cmd line # e.g. llvm-lit --param klee_opts=--help klee_extra_params = lit_config.params.get('klee_opts',"") @@ -181,6 +186,8 @@ config.substitutions.append( ('%gentmp', os.path.join(klee_src_root, 'scripts/genTempFiles.sh')) ) +# Prepare the full include expression, i.e. for all given paths. For example, ["path1","path2"] +# becomes "-I path1 -I path2" config.substitutions.append( ('%replay', os.path.join(klee_src_root, 'scripts/replay.sh')) ) @@ -194,7 +201,8 @@ config.substitutions.append( ) config.substitutions.append( - ('%libcxx_include', getattr(config, 'libcxx_include_dir', None))) + ('%libcxx_includes', " ".join( ["-I "+ p for p in getattr(config, 'libcxx_include_dirs', [])] )) + ) config.substitutions.append( ('%gcov-options', '--coverage -dumpbase "" -dumpdir ""') @@ -206,7 +214,7 @@ config.substitutions.append( # 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. -known_llvm_versions = { "9.0", "10.0", "11.0", "11.1", "12.0", "13.0", "14.0" } +known_llvm_versions = { "11.0", "11.1", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0" } current_llvm_version_tuple = (int(config.llvm_version_major), int(config.llvm_version_minor)) current_llvm_version = "%s.%s" % current_llvm_version_tuple @@ -304,3 +312,6 @@ if config.have_asan or config.have_ubsan or config.have_msan: config.available_features.add('san') else: config.available_features.add('not-san') + +# SQLite +config.available_features.add('{}sqlite3'.format('' if config.have_sqlite3 else 'not-')) diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 17ad995b8d..bb3ac9cbcb 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -9,7 +9,7 @@ config.klee_obj_root = "@KLEE_BINARY_DIR@" config.klee_tools_dir = "@KLEE_TOOLS_DIR@" config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.libcxx_include_dir = "@KLEE_LIBCXX_INCLUDE_DIR@" +config.libcxx_include_dirs = ["@KLEE_LIBCXX_INCLUDE_DIR@"] # Needed to check if a hack needs to be applied config.llvm_version_major = "@LLVM_VERSION_MAJOR@" @@ -42,6 +42,8 @@ config.cxx = "@NATIVE_CXX@" # test/Concrete/CMakeLists.txt config.O0opt = "-O0 -Xclang -disable-O0-optnone" +config.sqlite3 = "@SQLITE_CLI@" + # Features config.enable_uclibc = True if @SUPPORT_KLEE_UCLIBC@ == 1 else False config.enable_posix_runtime = True if @ENABLE_POSIX_RUNTIME@ == 1 else False @@ -59,6 +61,7 @@ config.have_asan = True if @IS_ASAN_BUILD@ == 1 else False config.have_ubsan = True if @IS_UBSAN_BUILD@ == 1 else False config.have_msan = True if @IS_MSAN_BUILD@ == 1 else False config.have_32bit_support = True if @M32_SUPPORTED@ == 1 else False +config.have_sqlite3 = True if "@SQLITE_CLI@".strip() != "" else False # Add sanitizer list config.environment['LSAN_OPTIONS'] = "suppressions=@KLEE_UTILS_DIR@/sanitizers/lsan.txt" diff --git a/tools/kleaver/main.cpp b/tools/kleaver/main.cpp index 45b59e3b24..98cf20dcf9 100644 --- a/tools/kleaver/main.cpp +++ b/tools/kleaver/main.cpp @@ -386,11 +386,7 @@ static bool printInputAsSMTLIBv2(const char *Filename, } int main(int argc, char **argv) { -#if LLVM_VERSION_CODE >= LLVM_VERSION(13, 0) - KCommandLine::HideOptions(llvm::cl::getGeneralCategory()); -#else - KCommandLine::HideOptions(llvm::cl::GeneralCategory); -#endif + KCommandLine::KeepOnlyCategories({&ExprCat, &SolvingCat}); bool success = true; diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp index 9cd06abbf7..d020fa9eb2 100644 --- a/tools/klee/main.cpp +++ b/tools/klee/main.cpp @@ -283,12 +283,12 @@ cl::OptionCategory ReplayCat("Replaying options", cl::list ReplayKTestFile("replay-ktest-file", - cl::desc("Specify a ktest file to use for replay"), - cl::value_desc("ktest file"), cl::cat(ReplayCat)); + cl::desc("Specify a .ktest file to use for replay"), + cl::value_desc(".ktest file"), cl::cat(ReplayCat)); cl::list ReplayKTestDir("replay-ktest-dir", - cl::desc("Specify a directory to replay ktest files from"), + cl::desc("Specify a directory to replay .ktest files from"), cl::value_desc("output directory"), cl::cat(ReplayCat)); cl::opt ReplayPathFile("replay-path", @@ -1491,6 +1491,7 @@ static int run_klee_on_function(int pArgc, char **pArgv, char **pEnvp, // Assume with early exit a bug finding mode and otherwise coverage if (UseGuidedSearch == Interpreter::GuidanceKind::ErrorGuidance) *meta_file << "\tCOVER( init(main()), FQL(COVER " + "EDGES(@CALL(__VERIFIER_error))) )\n"; else *meta_file << "\tCOVER( init(main()), FQL(COVER " @@ -1902,23 +1903,12 @@ tryResolveEntryFunction(llvm::Module *mod, } int main(int argc, char **argv, char **envp) { - if (theInterpreter) { - theInterpreter = nullptr; - } - interrupted = false; - - klee::klee_warning_file = nullptr; - klee::klee_message_file = nullptr; - klee::ContextInitialized = false; - - atexit(llvm_shutdown); // Call llvm_shutdown() on exit. - -#if LLVM_VERSION_CODE >= LLVM_VERSION(13, 0) - KCommandLine::HideOptions(llvm::cl::getGeneralCategory()); -#else - KCommandLine::HideOptions(llvm::cl::GeneralCategory); -#endif + atexit(llvm_shutdown); // Call llvm_shutdown() on exit + KCommandLine::KeepOnlyCategories( + {&ChecksCat, &DebugCat, &ExtCallsCat, &ExprCat, &LinkCat, &MemoryCat, + &MiscCat, &ModuleCat, &ReplayCat, &SearchCat, &SeedingCat, &SolvingCat, + &StartCat, &StatsCat, &TerminationCat, &TestCaseCat, &TestGenCat}); llvm::InitializeNativeTarget(); parseArguments(argc, argv); @@ -1993,8 +1983,13 @@ int main(int argc, char **argv, char **envp) { sys::SetInterruptFunction(interrupt_handle); + // Load the bytecode... std::string errorMsg; LLVMContext ctx; +#if LLVM_VERSION_CODE == LLVM_VERSION(15, 0) + // We have to force the upgrade to opaque pointer explicitly for LLVM 15. + ctx.setOpaquePointers(true); +#endif // Load the bytecode... std::vector> loadedUserModules; diff --git a/unittests/Ref/RefTest.cpp b/unittests/Ref/RefTest.cpp index c9ca495f71..64c3956606 100644 --- a/unittests/Ref/RefTest.cpp +++ b/unittests/Ref/RefTest.cpp @@ -94,8 +94,11 @@ TEST(RefTest, SelfMove) { struct Expr *r_e = new Expr(); ref r(r_e); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wself-move" // Check self move r = std::move(r); +#pragma GCC diagnostic pop finished = 1; } EXPECT_EQ(1, finished_counter); diff --git a/unittests/Solver/Z3SolverTest.cpp b/unittests/Solver/Z3SolverTest.cpp index 97d110b209..cdc2ea2808 100644 --- a/unittests/Solver/Z3SolverTest.cpp +++ b/unittests/Solver/Z3SolverTest.cpp @@ -57,10 +57,9 @@ TEST_F(Z3SolverTest, GetConstraintLog) { // Ensure this is not buggy as fixed in https://github.com/klee/klee/pull/1235 // If the bug is still present this fail due to an internal assertion - char *ConstraintsString = Z3Solver_->getConstraintLog(TheQuery); + std::string ConstraintsString = Z3Solver_->getConstraintLog(TheQuery); const char *ExpectedArraySelection = "(= (select constant00"; const char *Occurence = - std::strstr(ConstraintsString, ExpectedArraySelection); + std::strstr(ConstraintsString.c_str(), ExpectedArraySelection); ASSERT_STRNE(Occurence, nullptr); - free(ConstraintsString); } From dc775f8703ade1a508495dd932704a241846c5ac Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 10:51:13 +0200 Subject: [PATCH 02/40] wip: --- .cirrus.yml | 2 +- tools/ktest-randgen/ktest-randgen.cpp | 1 - unittests/Searcher/CMakeLists.txt | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 8cf8a8383f..816eeba2cb 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,7 +10,7 @@ task: build_script: - mkdir build - cd build - - cmake -DLLVM_DIR=/usr/local/llvm13 -DMAKE_BINARY=/usr/local/bin/gmake -DJSON_SRC_DIR=/usr/local -DIMMER_SRC_DIR=/usr/local -DENABLE_TCMALLOC:BOOL=true -DENABLE_POSIX_RUNTIME:BOOL=ON -DENABLE_SOLVER_Z3:BOOL=true -DENABLE_SYSTEM_TESTS:BOOL=ON .. + - cmake -DLLVM_DIR=/usr/local/llvm13 -DMAKE_BINARY=/usr/local/bin/gmake -DJSON_SRC_DIR=/usr/local -DIMMER_SRC_DIR=/usr/local -DENABLE_TCMALLOC:BOOL=true -DENABLE_POSIX_RUNTIME:BOOL=ON -DENABLE_SOLVER_Z3:BOOL=true -DENABLE_SYSTEM_TESTS:BOOL=ON -DENABLE_WARNINGS_AS_ERRORS=0 .. - gmake test_script: - sed -i.bak -e 's/lit\./lit13\./' test/lit.cfg diff --git a/tools/ktest-randgen/ktest-randgen.cpp b/tools/ktest-randgen/ktest-randgen.cpp index 1b94c820e7..ed2ca431f8 100644 --- a/tools/ktest-randgen/ktest-randgen.cpp +++ b/tools/ktest-randgen/ktest-randgen.cpp @@ -122,7 +122,6 @@ void create_stat(size_t size, struct stat *s) { if (write(fd, memset(buf, 0, size), size) != (int)size) { free(buf); - free(filename); error_exit("%s:%d: Error writing %s\n", __FILE__, __LINE__, filename); } #if defined(__has_feature) diff --git a/unittests/Searcher/CMakeLists.txt b/unittests/Searcher/CMakeLists.txt index c35b407f96..7132f1d617 100644 --- a/unittests/Searcher/CMakeLists.txt +++ b/unittests/Searcher/CMakeLists.txt @@ -1,8 +1,8 @@ add_klee_unit_test(SearcherTest SearcherTest.cpp) -target_link_libraries(SearcherTest PRIVATE kleeCore) +target_link_libraries(SearcherTest PRIVATE kleeCore ${SQLite3_LIBRARIES}) target_include_directories(SearcherTest BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/lib") target_compile_options(SearcherTest PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(SearcherTest PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) -target_include_directories(SearcherTest PRIVATE ${KLEE_INCLUDE_DIRS}) \ No newline at end of file +target_include_directories(SearcherTest PRIVATE ${KLEE_INCLUDE_DIRS} ${SQLite3_INCLUDE_DIRS}) From a0cbfa7b662aadc8118c0a7bde62f26e468a0289 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 10:52:51 +0200 Subject: [PATCH 03/40] ci: --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ca9bd0411e..7aa9493ebf 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -5,7 +5,7 @@ on: pull_request: branches: [main, utbot-main] push: - branches: [main, utbot-main] + branches: [main, utbot-main, misonijnik/rebase-3.1-inner] # Defaults for building KLEE env: From 6237339c5a9916d07acca788212eab7292983ec7 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 11:02:48 +0200 Subject: [PATCH 04/40] wip: --- test/Concrete/CMakeLists.txt | 4 + test/Concrete/ConstantExpr.ll | 29 +-- test/Concrete/ConstantExprOld.ll | 166 ++++++++++++++++++ test/Concrete/Makefile.cmake.test.in | 6 +- test/Concrete/_testingUtils.c | 4 +- test/Expr/ReadExprConsistency.c | 4 +- .../BFSSearcherAndDFSSearcherInterleaved.c | 2 +- test/Feature/ByteSwap.c | 2 +- test/Feature/CheckMemoryAccess.c | 2 +- test/Feature/CompressedExprLogging.c | 2 +- test/Feature/ConcretizeSymbolicExternals.c | 35 ++++ test/Feature/CopyOnWrite.c | 2 +- test/Feature/DanglingConcreteReadExpr.c | 1 + test/Feature/DoubleFree.c | 6 +- test/Feature/Envp.c | 3 +- test/Feature/ExtCall.c | 23 +++ test/Feature/ExtCallOverapprox.c | 26 +++ test/Feature/ExtCallWarnings.c | 26 +++ test/Feature/GetValue.c | 2 +- test/Feature/InAndOutOfBounds.c | 2 + test/Feature/IndirectCallToExternal.c | 2 +- test/Feature/IsSymbolic.c | 2 +- test/Feature/KleeReportError.c | 1 + test/Feature/KleeStats.c | 2 +- test/Feature/LowerSwitch.c | 2 +- test/Feature/MakeSymbolicAPI.c | 3 +- test/Feature/MakeSymbolicName.c | 2 +- test/Feature/Memalign.c | 4 +- test/Feature/SeedConcretizeExtendFP.c | 0 test/Feature/SeedConcretizeExternalCall.c | 0 test/Feature/SeedConcretizeFP.c | 0 test/Feature/SeedConcretizeMalloc.c | 0 test/Feature/SeedExtension.c | 0 test/Feature/SingleObjectResolution.c | 0 test/Feature/VarArgByValOld.c | 0 test/Feature/WriteExecutionTree.c | 0 test/Feature/consecutive_divide_by_zero.c | 2 + test/Feature/const_array_opt1.c | 1 + test/Feature/left-overshift-sym-conc.c | 1 + .../logical-right-overshift-sym-conc.c | 1 + 40 files changed, 318 insertions(+), 52 deletions(-) create mode 100644 test/Concrete/ConstantExprOld.ll create mode 100644 test/Feature/ConcretizeSymbolicExternals.c create mode 100644 test/Feature/ExtCall.c create mode 100644 test/Feature/ExtCallOverapprox.c create mode 100644 test/Feature/ExtCallWarnings.c create mode 100644 test/Feature/SeedConcretizeExtendFP.c create mode 100644 test/Feature/SeedConcretizeExternalCall.c create mode 100644 test/Feature/SeedConcretizeFP.c create mode 100644 test/Feature/SeedConcretizeMalloc.c create mode 100644 test/Feature/SeedExtension.c create mode 100644 test/Feature/SingleObjectResolution.c create mode 100644 test/Feature/VarArgByValOld.c create mode 100644 test/Feature/WriteExecutionTree.c diff --git a/test/Concrete/CMakeLists.txt b/test/Concrete/CMakeLists.txt index e7cf2416ee..a073482ce8 100644 --- a/test/Concrete/CMakeLists.txt +++ b/test/Concrete/CMakeLists.txt @@ -8,4 +8,8 @@ #===------------------------------------------------------------------------===# set(OZERO_OPT "-O0 -Xclang -disable-O0-optnone") +if ("${LLVM_VERSION_MAJOR}" EQUAL 15) + set(LLVM_AS_FLAGS "-opaque-pointers") + set(LLVM_LINK_FLAGS "-opaque-pointers") +endif () configure_file(Makefile.cmake.test.in Makefile.cmake.test @ONLY) diff --git a/test/Concrete/ConstantExpr.ll b/test/Concrete/ConstantExpr.ll index efe9f14154..b85ce36ab1 100644 --- a/test/Concrete/ConstantExpr.ll +++ b/test/Concrete/ConstantExpr.ll @@ -1,3 +1,4 @@ +; REQUIRES: geq-llvm-15.0 ; RUN: %S/ConcreteTest.py --klee='%klee' --lli=%lli %s ; Most of the test below use the *address* of gInt as part of their computation, @@ -86,32 +87,6 @@ define void @"test_simple_arith"() { ret void } - -define void @"test_div_and_mod"() { - %t1 = add i32 udiv(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 - %t2 = add i32 urem(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 - %t3 = add i32 sdiv(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 - %t4 = add i32 srem(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 - - %p = ptrtoint i32* @gInt to i32 - - %i1 = udiv i32 %p, 13 - %i2 = urem i32 %p, 13 - %i3 = sdiv i32 %p, 13 - %i4 = srem i32 %p, 13 - - %x1 = sub i32 %t1, %i1 - %x2 = sub i32 %t2, %i2 - %x3 = sub i32 %t3, %i3 - %x4 = sub i32 %t4, %i4 - - call void @print_i32(i32 %x1) - call void @print_i32(i32 %x2) - call void @print_i32(i32 %x3) - call void @print_i32(i32 %x4) - - ret void -} define void @test_cmp() { %t1 = add i8 zext(i1 icmp ult (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 @@ -142,8 +117,6 @@ define void @test_cmp() { define i32 @main() { call void @test_simple_arith() - call void @test_div_and_mod() - call void @test_cmp() call void @test_int_to_ptr() diff --git a/test/Concrete/ConstantExprOld.ll b/test/Concrete/ConstantExprOld.ll new file mode 100644 index 0000000000..974247f506 --- /dev/null +++ b/test/Concrete/ConstantExprOld.ll @@ -0,0 +1,166 @@ +; REQUIRES: lt-llvm-15.0 +; RUN: %S/ConcreteTest.py --klee='%klee' --lli=%lli %s + +; Most of the test below use the *address* of gInt as part of their computation, +; and then perform some operation (like x | ~x) which makes the result +; deterministic. They do, however, assume that the sign bit of the address as a +; 64-bit value will never be set. +@gInt = global i32 10 +@gIntWithConstant = global i32 sub(i32 ptrtoint(i32* @gInt to i32), + i32 ptrtoint(i32* @gInt to i32)) + +define void @"test_int_to_ptr"() { + %t1 = add i8 ptrtoint(i8* inttoptr(i32 100 to i8*) to i8), 0 + %t2 = add i32 ptrtoint(i32* inttoptr(i8 100 to i32*) to i32), 0 + %t3 = add i32 ptrtoint(i32* inttoptr(i64 100 to i32*) to i32), 0 + %t4 = add i64 ptrtoint(i8* inttoptr(i32 100 to i8*) to i64), 0 + + call void @print_i8(i8 %t1) + call void @print_i32(i32 %t2) + call void @print_i32(i32 %t3) + call void @print_i64(i64 %t4) + + ret void +} + +define void @"test_constant_ops"() { + %t1 = add i8 trunc(i64 add(i64 ptrtoint(i32* @gInt to i64), i64 -10) to i8), 10 + %t2 = and i64 sub(i64 sext(i32 ptrtoint(i32* @gInt to i32) to i64), i64 ptrtoint(i32* @gInt to i64)), 4294967295 + %t3 = and i64 sub(i64 zext(i32 ptrtoint(i32* @gInt to i32) to i64), i64 ptrtoint(i32* @gInt to i64)), 4294967295 + + %t4 = icmp eq i8 trunc(i64 ptrtoint(i32* @gInt to i64) to i8), %t1 + %t5 = zext i1 %t4 to i8 + + call void @print_i8(i8 %t5) + call void @print_i64(i64 %t2) + call void @print_i64(i64 %t3) + + ret void +} + +define void @"test_logical_ops"() { + %t1 = add i32 -10, and(i32 ptrtoint(i32* @gInt to i32), i32 xor(i32 ptrtoint(i32* @gInt to i32), i32 -1)) + %t2 = add i32 -10, or(i32 ptrtoint(i32* @gInt to i32), i32 xor(i32 ptrtoint(i32* @gInt to i32), i32 -1)) + %t3 = add i32 -10, xor(i32 xor(i32 ptrtoint(i32* @gInt to i32), i32 1024), i32 ptrtoint(i32* @gInt to i32)) + + call void @print_i32(i32 %t1) + call void @print_i32(i32 %t2) + call void @print_i32(i32 %t3) + + ; or the address with 1 to ensure the addresses will differ in 'ne' below + %t4 = shl i64 lshr(i64 or(i64 ptrtoint(i32* @gInt to i64), i64 1), i64 8), 8 + %t5 = shl i64 ashr(i64 or(i64 ptrtoint(i32* @gInt to i64), i64 1), i64 8), 8 + %t6 = lshr i64 shl(i64 or(i64 ptrtoint(i32* @gInt to i64), i64 1), i64 8), 8 + + %t7 = icmp eq i64 %t4, %t5 + %t8 = icmp ne i64 %t4, %t6 + + %t9 = zext i1 %t7 to i8 + %t10 = zext i1 %t8 to i8 + + call void @print_i8(i8 %t9) + call void @print_i8(i8 %t10) + + ret void +} + +%test.struct.type = type { i32, i32 } +@test_struct = global %test.struct.type { i32 0, i32 10 } + +define void @"test_misc"() { + ; probability that @gInt == 100 is very very low + %t1 = add i32 select(i1 icmp eq (i32* @gInt, i32* inttoptr(i32 100 to i32*)), i32 10, i32 0), 0 + call void @print_i32(i32 %t1) + + %t2 = load i32, i32* getelementptr(%test.struct.type, %test.struct.type* @test_struct, i32 0, i32 1) + call void @print_i32(i32 %t2) + + ret void +} + +define void @"test_simple_arith"() { + %t1 = add i32 add(i32 ptrtoint(i32* @gInt to i32), i32 0), 0 + %t2 = add i32 sub(i32 0, i32 ptrtoint(i32* @gInt to i32)), %t1 + %t3 = mul i32 mul(i32 ptrtoint(i32* @gInt to i32), i32 10), %t2 + + call void @print_i32(i32 %t3) + + ret void +} + +define void @"test_div_and_mod"() { + %t1 = add i32 udiv(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + %t2 = add i32 urem(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + %t3 = add i32 sdiv(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + %t4 = add i32 srem(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + + %p = ptrtoint i32* @gInt to i32 + + %i1 = udiv i32 %p, 13 + %i2 = urem i32 %p, 13 + %i3 = sdiv i32 %p, 13 + %i4 = srem i32 %p, 13 + + %x1 = sub i32 %t1, %i1 + %x2 = sub i32 %t2, %i2 + %x3 = sub i32 %t3, %i3 + %x4 = sub i32 %t4, %i4 + + call void @print_i32(i32 %x1) + call void @print_i32(i32 %x2) + call void @print_i32(i32 %x3) + call void @print_i32(i32 %x4) + + ret void +} + +define void @test_cmp() { + %t1 = add i8 zext(i1 icmp ult (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t2 = add i8 zext(i1 icmp ule (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t3 = add i8 zext(i1 icmp uge (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t4 = add i8 zext(i1 icmp ugt (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t5 = add i8 zext(i1 icmp slt (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t6 = add i8 zext(i1 icmp sle (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t7 = add i8 zext(i1 icmp sge (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t8 = add i8 zext(i1 icmp sgt (i64 ptrtoint(i32* @gInt to i64), i64 0) to i8), 1 + %t9 = add i8 zext(i1 icmp eq (i64 ptrtoint(i32* @gInt to i64), i64 10) to i8), 1 + %t10 = add i8 zext(i1 icmp ne (i64 ptrtoint(i32* @gInt to i64), i64 10) to i8), 1 + + call void @print_i1(i8 %t1) + call void @print_i1(i8 %t2) + call void @print_i1(i8 %t3) + call void @print_i1(i8 %t4) + call void @print_i1(i8 %t5) + call void @print_i1(i8 %t6) + call void @print_i1(i8 %t7) + call void @print_i1(i8 %t8) + call void @print_i1(i8 %t9) + call void @print_i1(i8 %t10) + + ret void +} + +define i32 @main() { + call void @test_simple_arith() + + call void @test_div_and_mod() + + call void @test_cmp() + + call void @test_int_to_ptr() + + call void @test_constant_ops() + + call void @test_logical_ops() + + call void @test_misc() + + ret i32 0 +} + +; defined in print_int.c +declare void @print_i1(i8) +declare void @print_i8(i8) +declare void @print_i16(i16) +declare void @print_i32(i32) +declare void @print_i64(i64) diff --git a/test/Concrete/Makefile.cmake.test.in b/test/Concrete/Makefile.cmake.test.in index 2282bb0837..765ea690fe 100644 --- a/test/Concrete/Makefile.cmake.test.in +++ b/test/Concrete/Makefile.cmake.test.in @@ -14,6 +14,8 @@ LLVMCC := @LLVMCC@ LLVMAS := @LLVM_AS@ LLVMLINK := @LLVM_LINK@ LLVMCC.CFlags := @OZERO_OPT@ -Wall +LLVMAS.Flags := @LLVM_AS_FLAGS@ +LLVMLINK.Flags := @LLVM_LINK_FLAGS@ # Make sure source files can match the pattern rules VPATH := @CMAKE_CURRENT_SOURCE_DIR@ @@ -28,7 +30,7 @@ Output/%.bc: %.c Output/.dir $(LLVMCC) -emit-llvm -c $(LLVMCC.CFlags) $< -o $@ Output/%.bc: %.ll $(LLVMAS) Output/.dir - $(LLVMAS) -f $< -o $@ + $(LLVMAS) $(LLVMAS.Flags) -f $< -o $@ # We build a separate testingUtils bitcode for each test, to make sure parallel # tests don't interact with one another. @@ -36,7 +38,7 @@ Output/%_testingUtils.bc: _testingUtils.c Output/.dir $(LLVMCC) -emit-llvm -c $(LLVMCC.CFlags) $< -o $@ Output/linked_%.bc: Output/%.bc Output/%_testingUtils.bc - $(LLVMLINK) $< Output/$*_testingUtils.bc -o $@ + $(LLVMLINK) $(LLVMLINK.Flags) $< Output/$*_testingUtils.bc -o $@ .PRECIOUS: Output/.dir diff --git a/test/Concrete/_testingUtils.c b/test/Concrete/_testingUtils.c index bbb377dfee..218700d161 100644 --- a/test/Concrete/_testingUtils.c +++ b/test/Concrete/_testingUtils.c @@ -66,11 +66,11 @@ int main(int argc, char *argv[]) { printf("print_i1(0)\n"); print_i1(0); // CHECK: i1(0) - // CHECK_NEXT: 0 + // CHECK-NEXT: 0 printf("print_i1(1)\n"); print_i1(1); // CHECK: i1(1) - // CHECK_NEXT: 1 + // CHECK-NEXT: 1 } #endif diff --git a/test/Expr/ReadExprConsistency.c b/test/Expr/ReadExprConsistency.c index 016e45962a..661c64e2c2 100644 --- a/test/Expr/ReadExprConsistency.c +++ b/test/Expr/ReadExprConsistency.c @@ -2,8 +2,9 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error %t.bc 2>%t.log // RUN: cat %t.log | FileCheck %s - +#include "klee/klee.h" #include +#include /* This tests checks ensures that only relevant updates are present when doing @@ -15,7 +16,6 @@ See https://github.com/klee/klee/pull/1061 */ -void klee_print_expr(const char *, char); int main() { char arr[3]; char symbolic; diff --git a/test/Feature/BFSSearcherAndDFSSearcherInterleaved.c b/test/Feature/BFSSearcherAndDFSSearcherInterleaved.c index 88d49548cf..8e4859a3b4 100644 --- a/test/Feature/BFSSearcherAndDFSSearcherInterleaved.c +++ b/test/Feature/BFSSearcherAndDFSSearcherInterleaved.c @@ -13,7 +13,7 @@ // RUN: FileCheck -input-file=%t-dfs-bfs.out %s #include "klee/klee.h" - +#include int main() { int x, y, z; klee_make_symbolic(&x, sizeof(x), "x"); diff --git a/test/Feature/ByteSwap.c b/test/Feature/ByteSwap.c index 1009a0999b..bc65ef0735 100644 --- a/test/Feature/ByteSwap.c +++ b/test/Feature/ByteSwap.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=klee --exit-on-error %t1.bc - +#include "klee/klee.h" #include #include diff --git a/test/Feature/CheckMemoryAccess.c b/test/Feature/CheckMemoryAccess.c index 3ecf0b09d0..9854f98350 100644 --- a/test/Feature/CheckMemoryAccess.c +++ b/test/Feature/CheckMemoryAccess.c @@ -3,7 +3,7 @@ // RUN: %klee --output-dir=%t.klee-out %t.bc > %t.log // RUN: grep -q "good" %t.log // RUN: not grep -q "bad" %t.log - +#include "klee/klee.h" #include #include #include diff --git a/test/Feature/CompressedExprLogging.c b/test/Feature/CompressedExprLogging.c index 462fc613ad..e43456d06d 100644 --- a/test/Feature/CompressedExprLogging.c +++ b/test/Feature/CompressedExprLogging.c @@ -10,7 +10,7 @@ // RUN: %klee --output-dir=%t.klee-out2 --use-cex-cache=false --compress-query-log --use-query-log=all:kquery %t1.bc // RUN: gunzip -d %t.klee-out2/all-queries.kquery.gz // RUN: diff %t.klee-out/all-queries.kquery %t.klee-out/all-queries.kquery - +#include "klee/klee.h" #include int constantArr[16] = {1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, diff --git a/test/Feature/ConcretizeSymbolicExternals.c b/test/Feature/ConcretizeSymbolicExternals.c new file mode 100644 index 0000000000..52c00bdf97 --- /dev/null +++ b/test/Feature/ConcretizeSymbolicExternals.c @@ -0,0 +1,35 @@ +// Check for calling external functions using symbolic parameters. +// Externals calls might modify memory objects that have been previously fully symbolic. +// The constant modifications should be propagated back. +// RUN: %clang %s -emit-llvm -g -c -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out -external-calls=all %t.bc > %t.log +// RUN: FileCheck -input-file=%t.log %s +// REQUIRES: not-darwin +#include "klee/klee.h" +#include + +int main() { + + int a; + int b; + int c; + + // Symbolize argument that gets concretized by the external call + klee_make_symbolic(&a, sizeof(a), "a"); + klee_make_symbolic(&b, sizeof(b), "b"); + klee_make_symbolic(&c, sizeof(c), "c"); + if (a == 2 && b == 3) { + // Constrain fully symbolic `a` and `b` to concrete values + + // Although a and b are not character vectors, explicitly constraining them to `2` and `3` + // leads to the most significant bits of the int (e.g. bit 8 to 31 of 32bit) set to `\0`. + // This leads to an actual null-termination of the character vector, which makes it safe + // to use by an external function. + printf("%s%s%n\n", (char *)&a, (char *)&b, &c); + printf("after: a = %d b = %d c = %d\n", a, b, c); + // CHECK: after: a = 2 b = 3 c = 2 + } + + return 0; +} diff --git a/test/Feature/CopyOnWrite.c b/test/Feature/CopyOnWrite.c index e98267dd21..711a7d10ca 100644 --- a/test/Feature/CopyOnWrite.c +++ b/test/Feature/CopyOnWrite.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm -g -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --search=random-state --exit-on-error %t1.bc - +#include "klee/klee.h" #include #define N 5 diff --git a/test/Feature/DanglingConcreteReadExpr.c b/test/Feature/DanglingConcreteReadExpr.c index 1f8a5a347a..94dcd95cb2 100644 --- a/test/Feature/DanglingConcreteReadExpr.c +++ b/test/Feature/DanglingConcreteReadExpr.c @@ -3,6 +3,7 @@ // RUN: %klee --optimize=false --output-dir=%t.klee-out %t1.bc // RUN: grep "total queries = 1" %t.klee-out/info +#include "klee/klee.h" #include int main() { diff --git a/test/Feature/DoubleFree.c b/test/Feature/DoubleFree.c index 96cf9bcd97..8c4a373500 100644 --- a/test/Feature/DoubleFree.c +++ b/test/Feature/DoubleFree.c @@ -3,10 +3,12 @@ // RUN: %klee --output-dir=%t.klee-out %t1.bc 2>&1 | FileCheck %s // RUN: test -f %t.klee-out/test000001.ptr.err +#include + int main() { - int *x = malloc(4); + int *x = malloc(sizeof(*x)); free(x); - // CHECK: memory error: invalid pointer: free + // CHECK: memory error: double free free(x); return 0; } diff --git a/test/Feature/Envp.c b/test/Feature/Envp.c index b793d0017a..cacc0c4db7 100644 --- a/test/Feature/Envp.c +++ b/test/Feature/Envp.c @@ -1,8 +1,9 @@ // RUN: %clang %s -emit-llvm -g -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error %t1.bc - #include +#include +#include int main(int argc, char **argv, char **envp) { unsigned i; diff --git a/test/Feature/ExtCall.c b/test/Feature/ExtCall.c new file mode 100644 index 0000000000..e38f92d948 --- /dev/null +++ b/test/Feature/ExtCall.c @@ -0,0 +1,23 @@ +// This test checks that symbolic arguments to a function call are correctly concretized +// RUN: %clang %s -emit-llvm %O0opt -g -c -o %t.bc + +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --external-calls=all --exit-on-error %t.bc 2>&1 | FileCheck %s + +#include "klee/klee.h" + +#include +#include +#include + +int main() { + int x; + klee_make_symbolic(&x, sizeof(x), "x"); + klee_assume(x >= 0); + + int y = abs(x); + printf("y = %d\n", y); + // CHECK: calling external: abs((ReadLSB w32 0 x)) + + assert(x == y); +} diff --git a/test/Feature/ExtCallOverapprox.c b/test/Feature/ExtCallOverapprox.c new file mode 100644 index 0000000000..76ae319dcd --- /dev/null +++ b/test/Feature/ExtCallOverapprox.c @@ -0,0 +1,26 @@ +// This test checks that under using the over-approximate external call policy, the symbolic arguments are left unconstrained by the external call + +// RUN: %clang %s -emit-llvm %O0opt -g -c -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --external-calls=over-approx %t.bc 2>&1 | FileCheck %s + +#include "klee/klee.h" + +#include +#include +#include + +int main() { + int x; + klee_make_symbolic(&x, sizeof(x), "x"); + + printf("%d\n", x); + // CHECK: calling external: printf + if (x > 0) { + printf("Yes\n"); + // CHECK-DAG: Yes + } else { + printf("No\n"); + // CHECK-DAG: No + } +} diff --git a/test/Feature/ExtCallWarnings.c b/test/Feature/ExtCallWarnings.c new file mode 100644 index 0000000000..6ee3f3711e --- /dev/null +++ b/test/Feature/ExtCallWarnings.c @@ -0,0 +1,26 @@ +// RUN: %clang %s -emit-llvm %O0opt -g -c -o %t.bc + +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --external-call-warnings=none %t.bc 2>&1 | FileCheck --check-prefix=CHECK-NONE %s + +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --external-call-warnings=once-per-function %t.bc 2>&1 | FileCheck --check-prefix=CHECK-ONCE %s + +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --external-call-warnings=all %t.bc 2>&1 | FileCheck --check-prefix=CHECK-ALL %s + +#include "klee/klee.h" +#include +#include + +int main() { + return abs(-5) + abs(6); + // CHECK-NONE-NOT: calling external + + // CHECK-ONCE: calling external + // CHECK-ONCE-NOT: calling external + + // CHECK-ALL: calling external + // CHECK-ALL: calling external + // CHECK-ALL-NOT: calling external +} diff --git a/test/Feature/GetValue.c b/test/Feature/GetValue.c index acff2300f8..c652658f9c 100644 --- a/test/Feature/GetValue.c +++ b/test/Feature/GetValue.c @@ -1,7 +1,7 @@ // RUN: %clang -emit-llvm -c -o %t1.bc %s // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error %t1.bc - +#include "klee/klee.h" #include #include diff --git a/test/Feature/InAndOutOfBounds.c b/test/Feature/InAndOutOfBounds.c index 39ed83220a..37c30e8fa7 100644 --- a/test/Feature/InAndOutOfBounds.c +++ b/test/Feature/InAndOutOfBounds.c @@ -4,6 +4,8 @@ // RUN: test -f %t.klee-out/test000001.ptr.err -o -f %t.klee-out/test000002.ptr.err // RUN: not test -f %t.klee-out/test000001.ptr.err -a -f %t.klee-out/test000002.ptr.err // RUN: not test -f %t.klee-out/test000003.ktest +#include "klee/klee.h" +#include unsigned klee_urange(unsigned start, unsigned end) { unsigned x; diff --git a/test/Feature/IndirectCallToExternal.c b/test/Feature/IndirectCallToExternal.c index 49bbd75ac3..b254953425 100644 --- a/test/Feature/IndirectCallToExternal.c +++ b/test/Feature/IndirectCallToExternal.c @@ -8,7 +8,7 @@ #include int main() { - int (*scmp)(char *, char *) = strcmp; + int (*scmp)(const char *, const char *) = strcmp; assert(scmp("hello", "hi") < 0); diff --git a/test/Feature/IsSymbolic.c b/test/Feature/IsSymbolic.c index 033d9d6a4d..266dd23f43 100644 --- a/test/Feature/IsSymbolic.c +++ b/test/Feature/IsSymbolic.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc - +#include "klee/klee.h" #include int main() { diff --git a/test/Feature/KleeReportError.c b/test/Feature/KleeReportError.c index f406696f24..afd447f573 100644 --- a/test/Feature/KleeReportError.c +++ b/test/Feature/KleeReportError.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --emit-all-errors %t2.bc 2>&1 | FileCheck %s // RUN: ls %t.klee-out/ | grep .my.err | wc -l | grep 2 +#include "klee/klee.h" #include #include diff --git a/test/Feature/KleeStats.c b/test/Feature/KleeStats.c index 336525a75e..851ce61296 100644 --- a/test/Feature/KleeStats.c +++ b/test/Feature/KleeStats.c @@ -29,7 +29,7 @@ int main() { // First check we find a line with the expected format // CHECK-STATS: Path,Instrs,Time(s),ICov(%),BCov(%),ICount,TSolver(%),ActiveStates,MaxActiveStates,Mem(MiB),MaxMem(MiB) // Check there is a line with .klee-out dir, non zero instruction, less than 1 second execution time and 100 ICov. -// CHECK-STATS: {{.*\.klee-out,[1-9]+,[0-9]+\.([0-9]+),100\.00}} +// CHECK-STATS: {{.*\.klee-out,[1-9][0-9]+,[0-9]+\.([0-9]+),100\.00}} // Check other formats // CHECK-STATS-ABS-TIMES: Path,Time(s),TUser(s),TResolve(s),TCex(s),TSolver(s),TFork(s) diff --git a/test/Feature/LowerSwitch.c b/test/Feature/LowerSwitch.c index 8fff0295ed..cea734981d 100644 --- a/test/Feature/LowerSwitch.c +++ b/test/Feature/LowerSwitch.c @@ -6,7 +6,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --switch-type=simple %t.bc // RUN: test -f %t.klee-out/test000010.ktest - +#include "klee/klee.h" #include int main(int argc, char **argv) { diff --git a/test/Feature/MakeSymbolicAPI.c b/test/Feature/MakeSymbolicAPI.c index 0b1405a029..b7a30dcf6c 100644 --- a/test/Feature/MakeSymbolicAPI.c +++ b/test/Feature/MakeSymbolicAPI.c @@ -1,9 +1,8 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t1.bc +// RUN: %clang %s -std=c89 -emit-llvm -g -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc 2> %t.stderr.log // RUN: FileCheck %s -check-prefix=CHECK-WRN --input-file=%t.klee-out/warnings.txt // RUN: FileCheck %s -check-prefix=CHECK-ERR --input-file=%t.stderr.log - int main() { unsigned a, b, c; char *p; diff --git a/test/Feature/MakeSymbolicName.c b/test/Feature/MakeSymbolicName.c index 533614477e..caf8e04782 100644 --- a/test/Feature/MakeSymbolicName.c +++ b/test/Feature/MakeSymbolicName.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm -g -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --search=random-state --exit-on-error %t1.bc - +#include "klee/klee.h" #include int main() { diff --git a/test/Feature/Memalign.c b/test/Feature/Memalign.c index e5d09f6cdd..524e257def 100644 --- a/test/Feature/Memalign.c +++ b/test/Feature/Memalign.c @@ -1,9 +1,9 @@ +// REQUIRES: not-darwin // RUN: %clang -emit-llvm -g -c %s -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error %t.bc > %t.log - +#include #include - int main(int argc, char *argv[]) { int *a = (int *)memalign(8, sizeof(int) * 5); for (int i = 0; i < 5; ++i) { diff --git a/test/Feature/SeedConcretizeExtendFP.c b/test/Feature/SeedConcretizeExtendFP.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/SeedConcretizeExternalCall.c b/test/Feature/SeedConcretizeExternalCall.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/SeedConcretizeFP.c b/test/Feature/SeedConcretizeFP.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/SeedConcretizeMalloc.c b/test/Feature/SeedConcretizeMalloc.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/SeedExtension.c b/test/Feature/SeedExtension.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/SingleObjectResolution.c b/test/Feature/SingleObjectResolution.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/VarArgByValOld.c b/test/Feature/VarArgByValOld.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/WriteExecutionTree.c b/test/Feature/WriteExecutionTree.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Feature/consecutive_divide_by_zero.c b/test/Feature/consecutive_divide_by_zero.c index 535efd4f87..9f7486c422 100644 --- a/test/Feature/consecutive_divide_by_zero.c +++ b/test/Feature/consecutive_divide_by_zero.c @@ -8,6 +8,8 @@ * only one test case is generated EVEN IF THERE ARE MULTIPLE * DISTINCT ERRORS! */ + +#include "klee/klee.h" int main() { unsigned int a = 15; unsigned int b = 15; diff --git a/test/Feature/const_array_opt1.c b/test/Feature/const_array_opt1.c index a70223e36d..4e69a048d9 100644 --- a/test/Feature/const_array_opt1.c +++ b/test/Feature/const_array_opt1.c @@ -10,6 +10,7 @@ this takes under 2 seconds w/ the optimization and almost 6 minutes w/o. So we kill it in 10 sec and check if it has finished successfully. */ +#include "klee/klee.h" #include #include diff --git a/test/Feature/left-overshift-sym-conc.c b/test/Feature/left-overshift-sym-conc.c index 64a254326a..4091ecad84 100644 --- a/test/Feature/left-overshift-sym-conc.c +++ b/test/Feature/left-overshift-sym-conc.c @@ -3,6 +3,7 @@ // RUN: %klee --output-dir=%t.klee-out -use-cex-cache=1 -check-overshift=0 %t.bc // RUN: not grep "ASSERTION FAIL" %t.klee-out/messages.txt // RUN: grep "KLEE: done: explored paths = 1" %t.klee-out/info +#include "klee/klee.h" #include #include diff --git a/test/Feature/logical-right-overshift-sym-conc.c b/test/Feature/logical-right-overshift-sym-conc.c index 21ec733012..406a157af5 100644 --- a/test/Feature/logical-right-overshift-sym-conc.c +++ b/test/Feature/logical-right-overshift-sym-conc.c @@ -3,6 +3,7 @@ // RUN: %klee --output-dir=%t.klee-out -use-cex-cache=1 -check-overshift=0 %t.bc // RUN: not grep "ASSERTION FAIL" %t.klee-out/messages.txt // RUN: grep "KLEE: done: explored paths = 1" %t.klee-out/info +#include "klee/klee.h" #include #include From 52700ca459cd840d6d57e0e19ee315369726c28d Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 11:04:28 +0200 Subject: [PATCH 05/40] wip: --- NEWS | 38 +++++ test/Feature/MultiMkSym.c | 2 +- test/Feature/MultipleFreeResolution.c | 8 +- test/Feature/MultipleReadResolution.c | 4 +- test/Feature/MultipleReallocResolution.c | 2 +- test/Feature/MultipleWriteResolution.c | 4 +- test/Feature/NamedSeedMatching.c | 2 +- test/Feature/NoExternalCallsAllowed.c | 2 +- test/Feature/OneFreeError.c | 6 +- test/Feature/OneOutOfBounds.c | 1 + test/Feature/Optimize.c | 1 + test/Feature/OverlappedError.c | 2 +- test/Feature/PreferCex.c | 5 +- test/Feature/ReplayPath.c | 2 +- test/Feature/Searchers.c | 2 +- test/Feature/SeedConcretizeExtendFP.c | 37 +++++ test/Feature/SeedConcretizeExternalCall.c | 28 ++++ test/Feature/SeedConcretizeFP.c | 31 +++++ test/Feature/SeedConcretizeMalloc.c | 36 +++++ test/Feature/SeedExtension.c | 39 ++++++ test/Feature/SetForking.c | 2 +- test/Feature/SilentKleeAssume.c | 1 + test/Feature/SingleObjectResolution.c | 66 +++++++++ test/Feature/SolverTimeout.c | 2 +- test/Feature/TargetMismatch.c | 1 - test/Feature/VarArgByValOld.c | 131 ++++++++++++++++++ test/Feature/WriteCov.c | 2 +- test/Feature/WriteExecutionTree.c | 78 +++++++++++ test/Feature/srem.c | 1 + test/InlineAsm/asm_lifting.ll | 2 +- .../replay_cex_after_assumed_malloc.c | 1 + test/Runtime/FreeStanding/memcpy_chk_err.c | 4 +- test/Runtime/POSIX/FDNumbers.c | 2 +- test/Runtime/POSIX/Fcntl.c | 2 +- test/Runtime/POSIX/FilePerm.c | 11 +- test/Runtime/POSIX/FreeArgv.c | 3 +- test/Runtime/POSIX/Getenv.c | 5 +- test/Runtime/POSIX/Openat.c | 3 +- test/Runtime/POSIX/Replay.c | 1 + test/Runtime/POSIX/SeedAndFail.c | 2 +- test/Runtime/POSIX/Stdin.c | 3 +- test/Runtime/POSIX/Write1.c | 2 + test/Runtime/POSIX/Write2.c | 2 +- .../2008-03-04-libc-atexit-uses-dso-handle.c | 1 + ...plying_nonzero_offset_to_nonnull_pointer.c | 4 +- ...-applying_nonzero_offset_to_null_pointer.c | 2 - ...low-applying_zero_offset_to_null_pointer.c | 2 - test/VarArgs/VarArgByVal.c | 4 +- test/VectorInstructions/insert_element.c | 1 + .../{oob-read-llvm-geq11.c => oob-read.c} | 3 +- .../{oob-write-llvm-geq11.c => oob-write.c} | 2 - ...invalid-stp-array-binding-to-objectstate.c | 1 + test/regression/2007-07-30-unflushed-byte.c | 2 +- ...08-01-cache-unclear-on-overwrite-flushed.c | 1 + test/regression/2007-08-06-64bit-shift.c | 1 + .../regression/2007-08-06-access-after-free.c | 2 + .../2007-08-16-invalid-constant-value.c | 4 +- .../2007-08-16-valid-write-to-freed-object.c | 2 + test/regression/2007-10-11-free-of-alloca.c | 2 +- ...-11-illegal-access-after-free-and-branch.c | 6 +- ...07-10-12-failed-make-symbolic-after-copy.c | 2 +- test/regression/2008-03-04-free-of-global.c | 3 +- .../2008-03-11-free-of-malloc-zero.c | 2 +- test/regression/2008-04-10-bad-alloca-free.c | 1 + .../2014-07-04-unflushed-error-report.c | 2 + test/regression/2015-08-05-invalid-fork.c | 1 + .../regression/2015-08-30-empty-constraints.c | 2 + test/regression/2015-08-30-sdiv-1.c | 2 + test/regression/2017-02-21-pathOS-id.c | 6 + .../2017-11-01-test-with-empty-varname.c | 1 + test/regression/2018-10-30-llvm-pr39177.ll | 4 +- test/regression/2020-04-27-stp-array-names.c | 2 +- test/regression/2023-11-20-solver.c | 36 +++++ 73 files changed, 621 insertions(+), 62 deletions(-) rename test/VectorInstructions/{oob-read-llvm-geq11.c => oob-read.c} (96%) rename test/VectorInstructions/{oob-write-llvm-geq11.c => oob-write.c} (97%) create mode 100644 test/regression/2023-11-20-solver.c diff --git a/NEWS b/NEWS index 4af44e3c9e..fea55f387b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,41 @@ +KLEE 3.1, 29 February 2024 +========================== + +Incorporating changes from 8 June 2023 to 29 February 2024. +Maintainers during this time span: @ccadar, @MartinNowack, @251. +Documentation at http://klee.github.io/releases/docs/v3.1 + +== Major features and important changes == +- New execution tree implementation and klee-exec-tree tool (@251) +- KDAlloc is now the default allocator in KLEE (KDAlloc was introduced in KLEE 3.0) +- Resolve memory reads/writes to single objects in more cases (@tkuchta) +- Concretize values based on seeds when available (@ccadar) +- Fixed some interactions with external code (@ccadar, @MartinNowack, mishok2503) + +== LLVM support == +- Current recommended version is still LLVM 13 +- Added support for LLVM 15 and 16 (@MartinNowack) +- Removed support for LLVM <11 (@danielschemmel) +- KLEE 3.1 will be the last version with support for LLVM <13 + +== Options, scripts and KLEE intrinsics added, changed or removed == +- New klee-exec-tree tool (@251) +- New --write-exec-tree and --exec-tree-batch-size options (@251) +- Renamed --compress-process-tree to --compress-exec-tree (@ccadar) +- PTree is now called ExecutionTree in the code (@ccadar) +- KDAlloc (--kdalloc) is now enabled by default (@ccadar) +- Replaced --suppress-external-warnings and --all-external-warnings with --external-call-warnings=none|once-per-function|all (@ccadar) +- Keep in the KLEE and Kleaver help menus only the KLEE/Kleaver option categories (@ccadar) +- Removed --cex-cache-exp, a broken experimental optimisation for validity (@ccadar) +- Removed --zero-seed-extension, and merge it with --allow-seed-extension (@ccadar) + +== Other changes == +- Improvements to KDAlloc (@danielschemmel) +- Avoid generating array names in solver builders that could accidently collide (@MartinNowack) +- Function has_permission in the POSIX model now returns permission error a single time in symbolic execution mode (@ccadar) +- Smaller refactorings, fixes and improvements, test cases, maintenance, comments, web version, website, etc. (@251, @ccadar, @dependabot, @danielschemmel, @davidtr1037, @jbuening, @marco6, @MartinNowack, @McSinyx, @sp1ff) + + KLEE 3.0, 7 June 2023 ===================== diff --git a/test/Feature/MultiMkSym.c b/test/Feature/MultiMkSym.c index 941d5860ee..796bd0a563 100644 --- a/test/Feature/MultiMkSym.c +++ b/test/Feature/MultiMkSym.c @@ -6,7 +6,7 @@ // RUN: grep "(array (w64 100) (makeSymbolic a 0))" %t1 | wc -l | grep 2 /* Tests that the Array factory correctly distinguishes between arrays created at the same location but with different sizes */ - +#include "klee/klee.h" #include #include diff --git a/test/Feature/MultipleFreeResolution.c b/test/Feature/MultipleFreeResolution.c index a938e87ce0..be094e477e 100644 --- a/test/Feature/MultipleFreeResolution.c +++ b/test/Feature/MultipleFreeResolution.c @@ -4,6 +4,8 @@ // RUN: ls %t.klee-out/ | grep .ktest | wc -l | grep 4 // RUN: ls %t.klee-out/ | grep .err | wc -l | grep 3 +#include "klee/klee.h" + #include #include @@ -34,9 +36,9 @@ int main() { free(buf[s]); for (i = 0; i < 3; i++) { - // CHECK: MultipleFreeResolution.c:[[@LINE+3]]: memory error: out of bound pointer - // CHECK: MultipleFreeResolution.c:[[@LINE+2]]: memory error: out of bound pointer - // CHECK: MultipleFreeResolution.c:[[@LINE+1]]: memory error: out of bound pointer + // CHECK: MultipleFreeResolution.c:[[@LINE+3]]: memory error: use after free + // CHECK: MultipleFreeResolution.c:[[@LINE+2]]: memory error: use after free + // CHECK: MultipleFreeResolution.c:[[@LINE+1]]: memory error: use after free printf("*buf[%d] = %d\n", i, *buf[i]); } diff --git a/test/Feature/MultipleReadResolution.c b/test/Feature/MultipleReadResolution.c index 587ba862c7..a16cb563d1 100644 --- a/test/Feature/MultipleReadResolution.c +++ b/test/Feature/MultipleReadResolution.c @@ -10,8 +10,10 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-timestamps=false --use-merged-pointer-dereference=false %t1.bc > %t1.log // RUN: diff %t1.res %t1.log -#include +#include "klee/klee.h" +#include +#include unsigned klee_urange(unsigned start, unsigned end) { unsigned x; klee_make_symbolic(&x, sizeof x, "x"); diff --git a/test/Feature/MultipleReallocResolution.c b/test/Feature/MultipleReallocResolution.c index 1401e7bc36..9e2770b3b7 100644 --- a/test/Feature/MultipleReallocResolution.c +++ b/test/Feature/MultipleReallocResolution.c @@ -3,7 +3,7 @@ // RUN: %klee --use-guided-search=none --output-dir=%t.klee-out %t1.bc // RUN: ls %t.klee-out/ | grep .err | wc -l | grep 2 // RUN: ls %t.klee-out/ | grep .ptr.err | wc -l | grep 2 - +#include "klee/klee.h" #include #include #include diff --git a/test/Feature/MultipleWriteResolution.c b/test/Feature/MultipleWriteResolution.c index 70cb841d2f..86b56cd362 100644 --- a/test/Feature/MultipleWriteResolution.c +++ b/test/Feature/MultipleWriteResolution.c @@ -10,9 +10,9 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-timestamps=false --use-merged-pointer-dereference=false %t1.bc > %t1.log // RUN: diff %t1.res %t1.log - +#include "klee/klee.h" #include - +#include unsigned klee_urange(unsigned start, unsigned end) { unsigned x; klee_make_symbolic(&x, sizeof x, "x"); diff --git a/test/Feature/NamedSeedMatching.c b/test/Feature/NamedSeedMatching.c index 0c619cac1d..197def219d 100644 --- a/test/Feature/NamedSeedMatching.c +++ b/test/Feature/NamedSeedMatching.c @@ -10,7 +10,7 @@ // RUN: grep -q "b==4" %t.log // RUN: grep -q "c==5" %t.log // RUN: grep -q "x==6" %t.log - +#include "klee/klee.h" #include #include diff --git a/test/Feature/NoExternalCallsAllowed.c b/test/Feature/NoExternalCallsAllowed.c index 3042033011..dd38a695ba 100644 --- a/test/Feature/NoExternalCallsAllowed.c +++ b/test/Feature/NoExternalCallsAllowed.c @@ -2,8 +2,8 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --external-calls=none %t1.bc 2>&1 | FileCheck %s // RUN: test %t.klee-out/test000001.user.err - #include +#include int main(int argc, char **argv) { // CHECK: Disallowed call to external function: abs diff --git a/test/Feature/OneFreeError.c b/test/Feature/OneFreeError.c index 7eed722ad1..c8c44c168e 100644 --- a/test/Feature/OneFreeError.c +++ b/test/Feature/OneFreeError.c @@ -3,10 +3,12 @@ // RUN: %klee --output-dir=%t.klee-out %t1.bc 2>&1 | FileCheck %s // RUN: test -f %t.klee-out/test000001.ptr.err +#include + int main() { - int *x = malloc(4); + int *x = malloc(sizeof(*x)); free(x); - // CHECK: OneFreeError.c:[[@LINE+1]]: memory error: out of bound pointer + // CHECK: OneFreeError.c:[[@LINE+1]]: memory error: use after free x[0] = 1; return 0; } diff --git a/test/Feature/OneOutOfBounds.c b/test/Feature/OneOutOfBounds.c index a3e6db1f2e..0dfee6d6eb 100644 --- a/test/Feature/OneOutOfBounds.c +++ b/test/Feature/OneOutOfBounds.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc 2>&1 | FileCheck %s // RUN: test -f %t.klee-out/test000001.ptr.err +#include int main() { int *x = malloc(sizeof(int)); diff --git a/test/Feature/Optimize.c b/test/Feature/Optimize.c index 13cb5a8382..cb9f0e14d8 100644 --- a/test/Feature/Optimize.c +++ b/test/Feature/Optimize.c @@ -6,6 +6,7 @@ // RUN: diff %t3.log %t3.good // should complete by 100 instructions if opt is on +#include int main() { int i, res = 0; diff --git a/test/Feature/OverlappedError.c b/test/Feature/OverlappedError.c index 2f87dde2df..c4c3ea39a4 100644 --- a/test/Feature/OverlappedError.c +++ b/test/Feature/OverlappedError.c @@ -3,7 +3,7 @@ // RUN: %klee --output-dir=%t.klee-out --use-timestamps=false %t1.bc // RUN: ls %t.klee-out/ | grep .ktest | wc -l | grep 4 // RUN: ls %t.klee-out/ | grep .ptr.err | wc -l | grep 2 - +#include "klee/klee.h" #include int main() { diff --git a/test/Feature/PreferCex.c b/test/Feature/PreferCex.c index 5045dc61b0..fd5cd870ba 100644 --- a/test/Feature/PreferCex.c +++ b/test/Feature/PreferCex.c @@ -2,10 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error %t1.bc // RUN: %ktest-tool %t.klee-out/test000001.ktest | FileCheck %s - -#include -#include -#include +#include "klee/klee.h" int main() { char buf[4]; diff --git a/test/Feature/ReplayPath.c b/test/Feature/ReplayPath.c index 390405ed41..cfe0c291ee 100644 --- a/test/Feature/ReplayPath.c +++ b/test/Feature/ReplayPath.c @@ -6,7 +6,7 @@ // RUN: rm -rf %t.klee-out-2 // RUN: %klee --output-dir=%t.klee-out-2 --replay-path %t.klee-out/test000001.path %t2.bc > %t3.log // RUN: diff %t3.log %t3.good - +#include "klee/klee.h" #include #include diff --git a/test/Feature/Searchers.c b/test/Feature/Searchers.c index e8606e99bb..12ab82ce3b 100644 --- a/test/Feature/Searchers.c +++ b/test/Feature/Searchers.c @@ -31,7 +31,7 @@ /* this test is basically just for coverage and doesn't really do any correctness check (aside from testing that the various combinations don't crash) */ - +#include "klee/klee.h" #include int validate(char *buf, int N) { diff --git a/test/Feature/SeedConcretizeExtendFP.c b/test/Feature/SeedConcretizeExtendFP.c index e69de29bb2..4a281912da 100644 --- a/test/Feature/SeedConcretizeExtendFP.c +++ b/test/Feature/SeedConcretizeExtendFP.c @@ -0,0 +1,37 @@ +/* This test checks the case where the seed needs to be patched on re-run */ + +// RUN: %clang -emit-llvm -c %O0opt -g %s -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc +// RUN: test -f %t.klee-out/test000001.ktest +// RUN: not test -f %t.klee-out/test000002.ktest + +// RUN: rm -rf %t.klee-out-2 +// RUN: %klee --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest --allow-seed-extension %t.bc 2>&1 | FileCheck %s +// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s + +#include "klee/klee.h" + +#include +#include +#include + +void TestGen() { + uint16_t x; + klee_make_symbolic(&x, sizeof(x), "x"); + klee_assume(x == 1234); +} + +int main() { + uint32_t i; + klee_make_symbolic(&i, sizeof(i), "i"); + + if (i < 5000) { + double d = i; + // CHECK: concretizing (reason: floating point) + assert((unsigned)d < 5001); + } + + // CHECK-STATS: 3 + // These is similar to SeedConcretizeFP.c (1 query) plus the extra queries due to an incomplete seed +} diff --git a/test/Feature/SeedConcretizeExternalCall.c b/test/Feature/SeedConcretizeExternalCall.c index e69de29bb2..1898417075 100644 --- a/test/Feature/SeedConcretizeExternalCall.c +++ b/test/Feature/SeedConcretizeExternalCall.c @@ -0,0 +1,28 @@ +// RUN: %clang -emit-llvm -c -g %s -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc +// RUN: test -f %t.klee-out/test000001.ktest +// RUN: not test -f %t.klee-out/test000002.ktest + +// RUN: rm -rf %t.klee-out-2 +// RUN: %klee --external-calls=all --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest %t.bc +// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s + +#include "klee/klee.h" + +#include +#include + +void TestGen() { + int x; + klee_make_symbolic(&x, sizeof(x), "x"); + klee_assume(x == 12345678); +} + +int main() { + int x; + klee_make_symbolic(&x, sizeof(x), "x"); + assert(abs(x) == 12345678); + + // CHECK-STATS: 1 +} diff --git a/test/Feature/SeedConcretizeFP.c b/test/Feature/SeedConcretizeFP.c index e69de29bb2..3d55cd53ae 100644 --- a/test/Feature/SeedConcretizeFP.c +++ b/test/Feature/SeedConcretizeFP.c @@ -0,0 +1,31 @@ +// RUN: %clang -emit-llvm -c -g %s -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc +// RUN: test -f %t.klee-out/test000001.ktest +// RUN: not test -f %t.klee-out/test000002.ktest + +// RUN: rm -rf %t.klee-out-2 +// RUN: %klee --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest %t.bc 2>&1 | FileCheck %s +// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s + +#include "klee/klee.h" + +#include +#include + +void TestGen() { + unsigned x; + klee_make_symbolic(&x, sizeof(x), "x"); + klee_assume(x == 12345678); +} + +int main() { + unsigned i; + klee_make_symbolic(&i, sizeof(i), "i"); + double d = i; + // CHECK: concretizing (reason: floating point) + assert((unsigned)d == 12345678); + + // CHECK-STATS: 1 + // This one query involves the constraint that i == 12345678 +} diff --git a/test/Feature/SeedConcretizeMalloc.c b/test/Feature/SeedConcretizeMalloc.c index e69de29bb2..3a6598b2e5 100644 --- a/test/Feature/SeedConcretizeMalloc.c +++ b/test/Feature/SeedConcretizeMalloc.c @@ -0,0 +1,36 @@ +// RUN: %clang -emit-llvm -c -g %s -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --entry-point=SeedGen %t.bc +// RUN: test -f %t.klee-out/test000001.ktest +// RUN: not test -f %t.klee-out/test000002.ktest + +// RUN: rm -rf %t.klee-out-2 +// RUN: %klee --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest %t.bc | FileCheck --allow-empty %s +// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s + +#include "klee/klee.h" + +#include +#include +#include + +void SeedGen() { + size_t x; + klee_make_symbolic(&x, sizeof(x), "x"); + klee_assume(x == 100); +} + +int main(int argc, char **argv) { + size_t s; + klee_make_symbolic(&s, sizeof(s), "size"); + char *p = (char *)malloc(s); + if (!p) + return 0; + + if (s != 100) + printf("Error\n"); + // CHECK-NOT: Error + + // CHECK-STATS: 4 + // These queries are due to the explicit constraint asserting that s is 100 and the implicit one checking if we have a huge malloc +} diff --git a/test/Feature/SeedExtension.c b/test/Feature/SeedExtension.c index e69de29bb2..04f6d7a6cc 100644 --- a/test/Feature/SeedExtension.c +++ b/test/Feature/SeedExtension.c @@ -0,0 +1,39 @@ +/* This test checks the case where the seed needs to be patched on re-run */ + +// RUN: %clang -emit-llvm -c %O0opt -g %s -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc +// RUN: test -f %t.klee-out/test000001.ktest +// RUN: not test -f %t.klee-out/test000002.ktest + +// RUN: rm -rf %t.klee-out-2 +// RUN: %klee --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest --allow-seed-extension %t.bc 2>&1 | FileCheck %s + +#include "klee/klee.h" + +#include +#include +#include + +void TestGen() { + int x; + klee_make_symbolic(&x, sizeof(x), "x"); + klee_assume(x == 12345678); +} + +int main() { + int i; + klee_make_symbolic(&i, sizeof(i), "i"); + double d = i; + // CHECK: concretizing (reason: floating point) + assert((unsigned)d == 12345678); + + int j; + klee_make_symbolic(&j, sizeof(j), "j"); + if (j) + printf("Yes\n"); + // CHECK-DAG: Yes + else + printf("No\n"); + // CHECK-DAG: No +} diff --git a/test/Feature/SetForking.c b/test/Feature/SetForking.c index 8a8033ebdb..29611245f9 100644 --- a/test/Feature/SetForking.c +++ b/test/Feature/SetForking.c @@ -5,7 +5,7 @@ // RUN: grep "1 A" %t.uniq.log // RUN: grep "1 B" %t.uniq.log // RUN: grep "1 C" %t.uniq.log - +#include "klee/klee.h" #include int main() { diff --git a/test/Feature/SilentKleeAssume.c b/test/Feature/SilentKleeAssume.c index 668a2409ab..38d6bae623 100644 --- a/test/Feature/SilentKleeAssume.c +++ b/test/Feature/SilentKleeAssume.c @@ -6,6 +6,7 @@ // RUN: not %klee --output-dir=%t.klee-out --exit-on-error %t.bc > %t.default-klee-assume.log 2>&1 // RUN: FileCheck -input-file=%t.default-klee-assume.log -check-prefix=CHECK-DEFAULT-KLEE-ASSUME %s +#include "klee/klee.h" #include #include diff --git a/test/Feature/SingleObjectResolution.c b/test/Feature/SingleObjectResolution.c index e69de29bb2..c1de4185ee 100644 --- a/test/Feature/SingleObjectResolution.c +++ b/test/Feature/SingleObjectResolution.c @@ -0,0 +1,66 @@ +// RUN: %clang %s -g -emit-llvm %O0opt -c -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --search=dfs --output-dir=%t.klee-out --single-object-resolution %t.bc > %t.log 2>&1 +// RUN: FileCheck %s -input-file=%t.log + +#include "klee/klee.h" +#include + +struct A { + long long int y; + long long int y2; + int z; +}; + +struct B { + long long int x; + struct A y[20]; + struct A *y1; + struct A *y2; + int z; +}; + +int bar(int *pointer, int selector) { + int *ptr = 0; + if (selector) + ptr = pointer + 123; + else + ptr = pointer + 124; + // CHECK: SingleObjectResolution.c:[[@LINE+1]]: memory error: out of bound pointer + return *ptr; +} + +int foo() { + size_t x; + int y; + struct B b; + + // create a lot of memory objects + int *ptrs[1024]; + for (int i = 0; i < 1024; i++) { + ptrs[i] = malloc(23); + } + + klee_make_symbolic(&x, sizeof(x), "x"); + klee_make_symbolic(&y, sizeof(y), "y"); + + b.y1 = malloc(20 * sizeof(struct A)); + + // dereference of a pointer within a struct + int *tmp = &b.y1[x].z; + + int z = bar(tmp, y); + // cleanup test for heap + free(b.y1); + + tmp = &b.y[x].z; // this is to test the cleanup for stack vars + z = bar(tmp, y); + return z; +} + +int main(int argc, char *argv[]) { + // CHECK: KLEE: done: completed paths = 2 + // CHECK: KLEE: done: partially completed paths = 2 + // CHECK: KLEE: done: generated tests = 3 + return foo(); +} diff --git a/test/Feature/SolverTimeout.c b/test/Feature/SolverTimeout.c index 41049f5b34..b7ac1f4aee 100644 --- a/test/Feature/SolverTimeout.c +++ b/test/Feature/SolverTimeout.c @@ -3,7 +3,7 @@ // RUN: %klee --output-dir=%t.klee-out --max-solver-time=1 %t.bc 2>&1 | FileCheck %s // // Note: This test occasionally fails when using Z3 4.4.1 - +#include "klee/klee.h" #include int main() { diff --git a/test/Feature/TargetMismatch.c b/test/Feature/TargetMismatch.c index aae7fda6fc..e0e896bc69 100644 --- a/test/Feature/TargetMismatch.c +++ b/test/Feature/TargetMismatch.c @@ -1,4 +1,3 @@ -// REQUIRES: not-darwin // RUN: %clang %s -m32 -emit-llvm %O0opt -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error > %t2.out 2>&1 || true diff --git a/test/Feature/VarArgByValOld.c b/test/Feature/VarArgByValOld.c index e69de29bb2..011046d835 100644 --- a/test/Feature/VarArgByValOld.c +++ b/test/Feature/VarArgByValOld.c @@ -0,0 +1,131 @@ +// REQUIRES: lt-llvm-15.0 +/* This test checks that KLEE correctly handles variadic arguments with the + byval attribute */ + +// RUN: %clang %s -emit-llvm %O0opt -c -g -o %t1.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --exit-on-error --output-dir=%t.klee-out %t1.bc +// RUN: FileCheck %s --input-file=%t.klee-out/assembly.ll +// +// TODO: Make noundef unconditional when LLVM 14 is the oldest supported version. +// CHECK: @test1({{.*}}, i32 {{(noundef )?}}-1, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval +// CHECK: @test2({{.*}}, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval +#include +#include +#include + +struct foo { + char f1; + long long f2; + long long f3; + char f4; + long f5; + int f6; + char f7; +}; + +struct bar { + long long int f1; + char f2; + long long f3; + char f4; + long f5; +}; + +struct foo test1(int x, ...) { + va_list ap; + va_start(ap, x); + assert(x == -1); + + struct foo f = va_arg(ap, struct foo); + assert(f.f1 == 1); + assert(f.f2 == 2); + assert(f.f3 == 3); + assert(f.f4 == 4); + assert(f.f5 == 5); + assert(f.f6 == 6); + assert(f.f7 == 7); + + struct bar b = va_arg(ap, struct bar); + assert(b.f1 == 11); + assert(b.f2 == 12); + assert(b.f3 == 13); + assert(b.f4 == 14); + assert(b.f5 == 15); + + va_end(ap); + + f.f1++; + return f; +} + +struct foo test2(int x, long long int l, ...) { + va_list ap; + va_start(ap, l); + assert(x == 10); + assert(l == 1000); + + int i = va_arg(ap, int); + assert(i == 10); + + struct foo f = va_arg(ap, struct foo); + assert(f.f1 == 1); + assert(f.f2 == 2); + assert(f.f3 == 3); + assert(f.f4 == 4); + assert(f.f5 == 5); + assert(f.f6 == 6); + assert(f.f7 == 7); + + l = va_arg(ap, long long int); + assert(l == 1000); + + struct bar b = va_arg(ap, struct bar); + assert(b.f1 == 11); + assert(b.f2 == 12); + assert(b.f3 == 13); + assert(b.f4 == 14); + assert(b.f5 == 15); + + f = va_arg(ap, struct foo); + assert(f.f1 == 10); + assert(f.f2 == 20); + assert(f.f3 == 30); + assert(f.f4 == 40); + assert(f.f5 == 50); + assert(f.f6 == 60); + assert(f.f7 == 70); + + b = va_arg(ap, struct bar); + assert(b.f1 == 1); + assert(b.f2 == 3); + assert(b.f3 == 5); + assert(b.f4 == 7); + assert(b.f5 == 9); + + va_end(ap); + + f.f1++; + return f; +} + +int main() { + struct foo f = {1, 2, 3, 4, 5, 6, 7}; + struct bar b = {11, 12, 13, 14, 15}; + struct foo res = test1(-1, f, b); + assert(res.f1 == 2); + assert(res.f2 == 2); + assert(res.f3 == 3); + assert(res.f4 == 4); + assert(res.f5 == 5); + assert(res.f6 == 6); + assert(res.f7 == 7); + // check that f was not modified, as it's passed by value + assert(f.f1 == 1); + + int i = 10; + long long int l = 1000; + struct foo f2 = {10, 20, 30, 40, 50, 60, 70}; + struct bar b2 = {1, 3, 5, 7, 9}; + test2(i, l, i, f, l, b, f2, b2); +} diff --git a/test/Feature/WriteCov.c b/test/Feature/WriteCov.c index b31a320568..b8027fc2fd 100644 --- a/test/Feature/WriteCov.c +++ b/test/Feature/WriteCov.c @@ -7,7 +7,7 @@ // RUN: grep %t.klee-out/test000001.cov:1 %t3.txt // RUN: grep %t.klee-out/test000002.cov:0 %t3.txt // RUN: grep %t.klee-out/test000002.cov:1 %t3.txt - +#include "klee/klee.h" #include #include diff --git a/test/Feature/WriteExecutionTree.c b/test/Feature/WriteExecutionTree.c index e69de29bb2..42f531a5fe 100644 --- a/test/Feature/WriteExecutionTree.c +++ b/test/Feature/WriteExecutionTree.c @@ -0,0 +1,78 @@ +// RUN: %clang %s -emit-llvm %O0opt -g -c -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee -write-exec-tree --output-dir=%t.klee-out %t.bc +// RUN: %klee-exec-tree branches %t.klee-out/exec_tree.db | FileCheck --check-prefix=CHECK-BRANCH %s +// RUN: %klee-exec-tree depths %t.klee-out | FileCheck --check-prefix=CHECK-DEPTH %s +// RUN: %klee-exec-tree instructions %t.klee-out | FileCheck --check-prefix=CHECK-INSTR %s +// RUN: %klee-exec-tree terminations %t.klee-out | FileCheck --check-prefix=CHECK-TERM %s +// RUN: %klee-exec-tree tree-dot %t.klee-out | FileCheck --check-prefix=CHECK-DOT %s +// RUN: %klee-exec-tree tree-info %t.klee-out | FileCheck --check-prefix=CHECK-TINFO %s +// RUN: not %klee-exec-tree dot %t.klee-out/exec-tree-doesnotexist.db + +#include "klee/klee.h" + +#include + +int main(void) { + int a = 42; + int c0, c1, c2, c3; + klee_make_symbolic(&c0, sizeof(c0), "c0"); + klee_make_symbolic(&c1, sizeof(c1), "c1"); + klee_make_symbolic(&c2, sizeof(c2), "c2"); + klee_make_symbolic(&c3, sizeof(c3), "c3"); + + if (c0) { + a += 17; + } else { + a -= 4; + } + + if (c1) { + klee_assume(!c1); + } else if (c2) { + char *p = NULL; + p[4711] = '!'; + } else if (c3) { + klee_silent_exit(0); + } else { + return a; + } + + return 0; +} + +// CHECK-BRANCH: branch type,count +// CHECK-BRANCH: Conditional,7 + +// CHECK-DEPTH: depth,count +// CHECK-DEPTH: 3,2 +// CHECK-DEPTH: 4,2 +// CHECK-DEPTH: 5,4 + +// CHECK-INSTR: asm line,branches,terminations,termination types +// CHECK-INSTR-DAG: {{[0-9]+}},0,2,User(2) +// CHECK-INSTR-DAG: {{[0-9]+}},0,2,Ptr(2) +// CHECK-INSTR-DAG: {{[0-9]+}},0,2,SilentExit(2) +// CHECK-INSTR-DAG: {{[0-9]+}},0,2,Exit(2) + +// CHECK-TERM: termination type,count +// CHECK-TERM-DAG: Exit,2 +// CHECK-TERM-DAG: Ptr,2 +// CHECK-TERM-DAG: User,2 +// CHECK-TERM-DAG: SilentExit,2 + +// CHECK-DOT: strict digraph ExecutionTree { +// CHECK-DOT: node[shape=point,width=0.15,color=darkgrey]; +// CHECK-DOT: edge[color=darkgrey]; +// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="Conditional\nnode: {{[0-9]+}}\nstate: 0\nasm: {{[0-9]+}}"]; +// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="Exit\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=green]; +// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="SilentExit\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=orange]; +// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="Ptr\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=red]; +// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="User\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=blue]; +// CHECK-DOT-DAG: N{{[0-9]+}}->{N{{[0-9]+}} N{{[0-9]+}}}; +// CHECK-DOT-DAG: } + +// CHECK-TINFO: nodes: 15 +// CHECK-TINFO: leaf nodes: 8 +// CHECK-TINFO: max. depth: 5 +// CHECK-TINFO: avg. depth: 4.2 diff --git a/test/Feature/srem.c b/test/Feature/srem.c index a4fec8ca9a..39011e56d5 100644 --- a/test/Feature/srem.c +++ b/test/Feature/srem.c @@ -4,6 +4,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --klee-call-optimisation=false --optimize %t.bc 2>&1 | FileCheck %s +#include "klee/klee.h" #include #include diff --git a/test/InlineAsm/asm_lifting.ll b/test/InlineAsm/asm_lifting.ll index 246ae881c7..27b8851a4e 100644 --- a/test/InlineAsm/asm_lifting.ll +++ b/test/InlineAsm/asm_lifting.ll @@ -20,7 +20,7 @@ entry: %1 = getelementptr inbounds [47 x i8], [47 x i8]* %0, i64 0, i64 0 ; Make sure memory barrier with function arguments is kept %2 = call i8* asm sideeffect "", "=r,0,~{memory},~{dirflag},~{fpsr},~{flags}"(i8* nonnull %1) - ; CHECK: %2 = call i8* asm sideeffect "", "=r,0,~{memory},~{dirflag},~{fpsr},~{flags}"(i8* nonnull %1) + ; CHECK: %2 = call {{.*}} asm sideeffect "", "=r,0,~{memory},~{dirflag},~{fpsr},~{flags}"({{.*}} nonnull %1) ret i32 0 } diff --git a/test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c b/test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c index beb7700652..ecae795e12 100644 --- a/test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c +++ b/test/Replay/libkleeruntest/replay_cex_after_assumed_malloc.c @@ -3,6 +3,7 @@ // RUN: %klee --output-dir=%t.klee-out %t.ll // KLEE just must not fail #include "klee/klee.h" +#include int main() { char i; diff --git a/test/Runtime/FreeStanding/memcpy_chk_err.c b/test/Runtime/FreeStanding/memcpy_chk_err.c index 490d3f1d24..997499ec13 100644 --- a/test/Runtime/FreeStanding/memcpy_chk_err.c +++ b/test/Runtime/FreeStanding/memcpy_chk_err.c @@ -1,9 +1,7 @@ // This test checks that __memcpy_chk find the kind of errors it was // designed to find -// It requires clang >= 10 and not FreeBSD, otherwise a direct call to -// memcpy is emitted instead of to __memcpy_chk -// REQUIRES: geq-llvm-10.0 +// On FreeBSD, a direct call to memcpy is emitted instead of to __memcpy_chk // REQUIRES: not-freebsd // RUN: %clang %s -emit-llvm -O2 -g -c -D_FORTIFY_SOURCE=1 -o %t2.bc diff --git a/test/Runtime/POSIX/FDNumbers.c b/test/Runtime/POSIX/FDNumbers.c index f87394256a..2aa197be5e 100644 --- a/test/Runtime/POSIX/FDNumbers.c +++ b/test/Runtime/POSIX/FDNumbers.c @@ -1,10 +1,10 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t2.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 - #include #include #include +#include int main(int argc, char **argv) { int fd = open("A", O_TRUNC); diff --git a/test/Runtime/POSIX/Fcntl.c b/test/Runtime/POSIX/Fcntl.c index e75a1edaf7..30f12cf532 100644 --- a/test/Runtime/POSIX/Fcntl.c +++ b/test/Runtime/POSIX/Fcntl.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t2.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 - +#include "klee/klee.h" #include #include diff --git a/test/Runtime/POSIX/FilePerm.c b/test/Runtime/POSIX/FilePerm.c index a6d9886872..b63bf5c384 100644 --- a/test/Runtime/POSIX/FilePerm.c +++ b/test/Runtime/POSIX/FilePerm.c @@ -1,14 +1,19 @@ +/* This test checks that when opening a symbolic file in R/W mode, we return exactly twice: + once successfully, and the other time with a permission error */ + // RUN: %clang %s -emit-llvm %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-files 1 10 --sym-stdout 2>%t.log +// RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-files 1 10 | FileCheck %s // RUN: test -f %t.klee-out/test000001.ktest // RUN: test -f %t.klee-out/test000002.ktest -// RUN: test -f %t.klee-out/test000003.ktest +// RUN: not test -f %t.klee-out/test000003.ktest #include #include #include #include +#include int main(int argc, char **argv) { int fd = open("A", O_RDWR); @@ -17,6 +22,10 @@ int main(int argc, char **argv) { else fprintf(stderr, "Cannot open file 'A'\n"); + printf("File 'A' opened successfully\n"); + // CHECK-DAG: File 'A' opened successfully + else printf("Cannot open file 'A'\n"); + // CHECK-DAG: Cannot open file 'A' if (fd != -1) close(fd); } diff --git a/test/Runtime/POSIX/FreeArgv.c b/test/Runtime/POSIX/FreeArgv.c index 93ed697e2b..cdc5487f06 100644 --- a/test/Runtime/POSIX/FreeArgv.c +++ b/test/Runtime/POSIX/FreeArgv.c @@ -4,7 +4,8 @@ // RUN: test -f %t.klee-out/test000001.free.err // RUN: test -f %t.klee-out/test000002.free.err // RUN: test -f %t.klee-out/test000003.free.err - +#include "klee/klee.h" +#include int main(int argc, char **argv) { switch (klee_range(0, 3, "range")) { case 0: diff --git a/test/Runtime/POSIX/Getenv.c b/test/Runtime/POSIX/Getenv.c index ddd9978922..f3f32883e3 100644 --- a/test/Runtime/POSIX/Getenv.c +++ b/test/Runtime/POSIX/Getenv.c @@ -1,9 +1,10 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t2.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=klee --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 - #include - +#include +#include +#include int main(int argc, char **argv) { char *g = getenv("PWD"); if (g) { diff --git a/test/Runtime/POSIX/Openat.c b/test/Runtime/POSIX/Openat.c index c0bf2e71ed..2d25e6252c 100644 --- a/test/Runtime/POSIX/Openat.c +++ b/test/Runtime/POSIX/Openat.c @@ -2,9 +2,10 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 // RUN: test -f %t.klee-out/test000001.ktest - +#include "klee/klee.h" #include #include +#include int main(int argc, char **argv) { int fd = openat(AT_FDCWD, "A", O_RDWR | O_TRUNC); diff --git a/test/Runtime/POSIX/Replay.c b/test/Runtime/POSIX/Replay.c index 1259854fcd..18ba964c66 100644 --- a/test/Runtime/POSIX/Replay.c +++ b/test/Runtime/POSIX/Replay.c @@ -8,6 +8,7 @@ // REPLAY: Yes #ifdef KLEE_EXECUTION +#include "klee/klee.h" #define EXIT klee_silent_exit #else #include diff --git a/test/Runtime/POSIX/SeedAndFail.c b/test/Runtime/POSIX/SeedAndFail.c index cbf63ed0c1..10541cb1fa 100644 --- a/test/Runtime/POSIX/SeedAndFail.c +++ b/test/Runtime/POSIX/SeedAndFail.c @@ -2,7 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --libc=uclibc --posix-runtime %t.bc --sym-files 1 10 2>%t.log // RUN: rm -rf %t.klee-out-2 -// RUN: %klee --output-dir=%t.klee-out-2 --seed-dir=%t.klee-out --zero-seed-extension --libc=uclibc --posix-runtime %t.bc --sym-files 1 10 --max-fail 1 +// RUN: %klee --output-dir=%t.klee-out-2 --seed-dir=%t.klee-out --allow-seed-extension --libc=uclibc --posix-runtime %t.bc --sym-files 1 10 --max-fail 1 // RUN: ls %t.klee-out-2 | grep -c assert | grep 4 #include diff --git a/test/Runtime/POSIX/Stdin.c b/test/Runtime/POSIX/Stdin.c index 1d0dd817a2..4506533c80 100644 --- a/test/Runtime/POSIX/Stdin.c +++ b/test/Runtime/POSIX/Stdin.c @@ -9,11 +9,12 @@ // RUN: grep "mode:lnk" %t.log // RUN: grep "read:sym:yes" %t.log // RUN: grep "read:sym:no" %t.log - #include #include #include +#include #include +#include int main(int argc, char **argv) { struct stat stats; diff --git a/test/Runtime/POSIX/Write1.c b/test/Runtime/POSIX/Write1.c index 2becd54788..48aa87ee4d 100644 --- a/test/Runtime/POSIX/Write1.c +++ b/test/Runtime/POSIX/Write1.c @@ -2,8 +2,10 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libc=uclibc --posix-runtime %t.bc --sym-files 1 10 --sym-stdout 2>%t.log +#include "klee/klee.h" #include #include +#include int main(int argc, char **argv) { char buf[32]; diff --git a/test/Runtime/POSIX/Write2.c b/test/Runtime/POSIX/Write2.c index 229fa51d53..d898cda820 100644 --- a/test/Runtime/POSIX/Write2.c +++ b/test/Runtime/POSIX/Write2.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libc=uclibc --posix-runtime %t.bc --sym-files 1 10 --sym-stdout 2>%t.log - +#include "klee/klee.h" #include #include diff --git a/test/Runtime/Uclibc/2008-03-04-libc-atexit-uses-dso-handle.c b/test/Runtime/Uclibc/2008-03-04-libc-atexit-uses-dso-handle.c index 3b66dd21ed..26bb1dcec9 100644 --- a/test/Runtime/Uclibc/2008-03-04-libc-atexit-uses-dso-handle.c +++ b/test/Runtime/Uclibc/2008-03-04-libc-atexit-uses-dso-handle.c @@ -3,6 +3,7 @@ // RUN: %klee --output-dir=%t.klee-out --exit-on-error --libc=uclibc %t1.bc // just make sure atexit works ok +#include void boo() { } diff --git a/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_nonnull_pointer.c b/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_nonnull_pointer.c index ce1a8fea36..6109fcd72d 100644 --- a/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_nonnull_pointer.c +++ b/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_nonnull_pointer.c @@ -1,5 +1,3 @@ -// REQUIRES: lt-llvm-10.0 - // RUN: %clang %s -fsanitize=pointer-overflow -emit-llvm -g %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --emit-all-errors --ubsan-runtime %t.bc 2>&1 | FileCheck %s @@ -18,7 +16,7 @@ int main() { char *ptr = (char *)address; - // CHECK: KLEE: ERROR: {{.*}}runtime/Sanitizer/ubsan/ubsan_handlers.cpp:{{[0-9]+}}: pointer-overflow + // CHECK: KLEE: ERROR: {{.*}}runtime/Sanitizer/ubsan/ubsan_handlers.cpp:{{[0-9]+}}: nullptr-after-nonzero-offset result = ptr + 1; return 0; } diff --git a/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_null_pointer.c b/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_null_pointer.c index 9f6f6a5548..864f75c2b7 100644 --- a/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_null_pointer.c +++ b/test/UBSan/ubsan_pointer_overflow-applying_nonzero_offset_to_null_pointer.c @@ -1,5 +1,3 @@ -// REQUIRES: geq-llvm-10.0 - // RUN: %clang %s -fsanitize=pointer-overflow -emit-llvm -g %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --emit-all-errors --ubsan-runtime --use-lazy-initialization=none %t.bc 2>&1 | FileCheck %s diff --git a/test/UBSan/ubsan_pointer_overflow-applying_zero_offset_to_null_pointer.c b/test/UBSan/ubsan_pointer_overflow-applying_zero_offset_to_null_pointer.c index c65954e336..627dc80141 100644 --- a/test/UBSan/ubsan_pointer_overflow-applying_zero_offset_to_null_pointer.c +++ b/test/UBSan/ubsan_pointer_overflow-applying_zero_offset_to_null_pointer.c @@ -1,5 +1,3 @@ -// REQUIRES: geq-llvm-10.0 - // RUN: %clang %s -fsanitize=pointer-overflow -emit-llvm -g %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --emit-all-errors --ubsan-runtime %t.bc 2>&1 | FileCheck %s diff --git a/test/VarArgs/VarArgByVal.c b/test/VarArgs/VarArgByVal.c index 533c12cca4..699d531ee6 100644 --- a/test/VarArgs/VarArgByVal.c +++ b/test/VarArgs/VarArgByVal.c @@ -1,6 +1,6 @@ // Variadic functions are not currently supported on Apple Silicon // REQUIRES: not-darwin - +// REQUIRES: geq-llvm-15.0 /* This test checks that KLEE correctly handles variadic arguments with the byval attribute */ @@ -13,6 +13,8 @@ // CHECK: @test1({{.*}}, i32 {{(noundef )?}}-1, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval // CHECK: @test2({{.*}}, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval +// CHECK: call void (ptr, i32, ...) @test1(ptr sret(%struct.foo) align 8 {{.*}}, i32 noundef -1, ptr noundef byval(%struct.foo) align 8 {{.*}}, ptr noundef byval(%struct.bar) align 8 {{.*}}) +// CHECK: call void (ptr, i32, i64, ...) @test2(ptr sret(%struct.foo) align 8 {{.*}}, i32 noundef {{.*}}, i64 noundef {{.*}}, i32 noundef {{.*}}, ptr noundef byval(%struct.foo) align 8 {{.*}}, i64 noundef {{.*}}, ptr noundef byval(%struct.bar) align 8 {{.*}}, ptr noundef byval(%struct.foo) align 8 {{.*}}, ptr noundef byval(%struct.bar) align 8 {{.*}}) #include #include #include diff --git a/test/VectorInstructions/insert_element.c b/test/VectorInstructions/insert_element.c index 5f28254948..d885f0d46d 100644 --- a/test/VectorInstructions/insert_element.c +++ b/test/VectorInstructions/insert_element.c @@ -5,6 +5,7 @@ // RUN: %klee --output-dir=%t.klee-out --optimize=false %t1.bc > %t.stdout.log 2> %t.stderr.log // RUN: FileCheck -check-prefix=CHECK-STDOUT -input-file=%t.stdout.log %s // RUN: FileCheck -check-prefix=CHECK-STDERR -input-file=%t.stderr.log %s +#include "klee/klee.h" #include #include #include diff --git a/test/VectorInstructions/oob-read-llvm-geq11.c b/test/VectorInstructions/oob-read.c similarity index 96% rename from test/VectorInstructions/oob-read-llvm-geq11.c rename to test/VectorInstructions/oob-read.c index 309e05b1f1..2584b3a03b 100644 --- a/test/VectorInstructions/oob-read-llvm-geq11.c +++ b/test/VectorInstructions/oob-read.c @@ -1,5 +1,4 @@ -// REQUIRES: geq-llvm-11.0 -// XFAIL: geq-llvm-11.0 +// XFAIL: * /* The scalarizer pass in LLVM 11 was changed to generate, for a read f[k], with k symbolic and f a 4-element vector: diff --git a/test/VectorInstructions/oob-write-llvm-geq11.c b/test/VectorInstructions/oob-write.c similarity index 97% rename from test/VectorInstructions/oob-write-llvm-geq11.c rename to test/VectorInstructions/oob-write.c index 13c996aa73..b7d6eef6ec 100644 --- a/test/VectorInstructions/oob-write-llvm-geq11.c +++ b/test/VectorInstructions/oob-write.c @@ -1,5 +1,3 @@ -// REQUIRES: geq-llvm-11.0 - /* The scalarizer pass in LLVM 11 was changed to generate, for a write of the form f[k] = v, with f a 4-element vector: if k == 0 => f[0] = v diff --git a/test/regression/2007-07-25-invalid-stp-array-binding-to-objectstate.c b/test/regression/2007-07-25-invalid-stp-array-binding-to-objectstate.c index 1897266a59..ac32063cbc 100644 --- a/test/regression/2007-07-25-invalid-stp-array-binding-to-objectstate.c +++ b/test/regression/2007-07-25-invalid-stp-array-binding-to-objectstate.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc +#include "klee/klee.h" #include int main(void) { diff --git a/test/regression/2007-07-30-unflushed-byte.c b/test/regression/2007-07-30-unflushed-byte.c index e0235c1c8e..dcada5a70c 100644 --- a/test/regression/2007-07-30-unflushed-byte.c +++ b/test/regression/2007-07-30-unflushed-byte.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc - +#include "klee/klee.h" #include int main() { diff --git a/test/regression/2007-08-01-cache-unclear-on-overwrite-flushed.c b/test/regression/2007-08-01-cache-unclear-on-overwrite-flushed.c index ed1947b456..5a6d6e10dc 100644 --- a/test/regression/2007-08-01-cache-unclear-on-overwrite-flushed.c +++ b/test/regression/2007-08-01-cache-unclear-on-overwrite-flushed.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc +#include "klee/klee.h" #include #include diff --git a/test/regression/2007-08-06-64bit-shift.c b/test/regression/2007-08-06-64bit-shift.c index 2edac4f486..3af09dab25 100644 --- a/test/regression/2007-08-06-64bit-shift.c +++ b/test/regression/2007-08-06-64bit-shift.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc +#include "klee/klee.h" #include int main() { diff --git a/test/regression/2007-08-06-access-after-free.c b/test/regression/2007-08-06-access-after-free.c index 970e7b9c96..9ec7c13607 100644 --- a/test/regression/2007-08-06-access-after-free.c +++ b/test/regression/2007-08-06-access-after-free.c @@ -2,7 +2,9 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc +#include "klee/klee.h" #include +#include int main() { int a; diff --git a/test/regression/2007-08-16-invalid-constant-value.c b/test/regression/2007-08-16-invalid-constant-value.c index c49357f8c7..f5474f7a4e 100644 --- a/test/regression/2007-08-16-invalid-constant-value.c +++ b/test/regression/2007-08-16-invalid-constant-value.c @@ -1,5 +1,5 @@ // RUN: rm -f %t4.out %t4.err %t4.log -// RUN: %clang %s -emit-llvm -O2 -c -o %t1.bc +// RUN: %clang %s -std=c89 -emit-llvm -O2 -c -o %t1.bc // RUN: %llvmas -f %p/../Feature/_utils._ll -o %t2.bc // RUN: %llvmlink %t1.bc %t2.bc -o %t3.bc // RUN: rm -rf %t.klee-out @@ -7,8 +7,6 @@ #include -#include "../Feature/utils.h" - int main() { unsigned char a; diff --git a/test/regression/2007-08-16-valid-write-to-freed-object.c b/test/regression/2007-08-16-valid-write-to-freed-object.c index 7e5eb847e2..6cf972e77b 100644 --- a/test/regression/2007-08-16-valid-write-to-freed-object.c +++ b/test/regression/2007-08-16-valid-write-to-freed-object.c @@ -2,6 +2,8 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc +#include "klee/klee.h" +#include unsigned sym() { unsigned x; klee_make_symbolic(&x, sizeof x, "x"); diff --git a/test/regression/2007-10-11-free-of-alloca.c b/test/regression/2007-10-11-free-of-alloca.c index 6aa6cdb30c..cecdeef2b2 100644 --- a/test/regression/2007-10-11-free-of-alloca.c +++ b/test/regression/2007-10-11-free-of-alloca.c @@ -2,7 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc 2>&1 | FileCheck %s // RUN: test -f %t.klee-out/test000001.free.err - +#include int main() { int buf[4]; // CHECK: 2007-10-11-free-of-alloca.c:9: free of alloca 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 4647aae68f..868152ff59 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 @@ -3,8 +3,8 @@ // RUN: %klee --output-dir=%t.klee-out --optimize %t1.bc 2>&1 | FileCheck %s // RUN: test -f %t.klee-out/test000001.ptr.err -#include -#include +#include "klee/klee.h" + #include int main(int argc, char **argv) { @@ -15,7 +15,7 @@ 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:19: memory error: out of bound pointer + // CHECK: 2007-10-11-illegal-access-after-free-and-branch.c:[[@LINE+1]]: memory error: use after free return buf[2]; } klee_silent_exit(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 e3febfd02f..d8546f1e65 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 @@ -2,7 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc // RUN: test -f %t.klee-out/test000001.ktest - +#include "klee/klee.h" 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 995e7173b1..fb4a2df806 100644 --- a/test/regression/2008-03-04-free-of-global.c +++ b/test/regression/2008-03-04-free-of-global.c @@ -3,10 +3,11 @@ // RUN: %klee --output-dir=%t.klee-out %t1.bc 2>&1 | FileCheck %s // RUN: test -f %t.klee-out/test000001.free.err +#include int buf[4]; int main() { - // CHECK: 2008-03-04-free-of-global.c:10: free of global + // CHECK: 2008-03-04-free-of-global.c:[[@LINE+1]]: free of global free(buf); // this should give runtime error, not crash return 0; } diff --git a/test/regression/2008-03-11-free-of-malloc-zero.c b/test/regression/2008-03-11-free-of-malloc-zero.c index 8e0ce568b7..5813cedcfb 100644 --- a/test/regression/2008-03-11-free-of-malloc-zero.c +++ b/test/regression/2008-03-11-free-of-malloc-zero.c @@ -1,7 +1,7 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error %t1.bc - +#include "klee/klee.h" #include int main() { diff --git a/test/regression/2008-04-10-bad-alloca-free.c b/test/regression/2008-04-10-bad-alloca-free.c index 5049f47ce8..d20d07d215 100644 --- a/test/regression/2008-04-10-bad-alloca-free.c +++ b/test/regression/2008-04-10-bad-alloca-free.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --exit-on-error %t1.bc +#include "klee/klee.h" void f(int *addr) { klee_make_symbolic(addr, sizeof *addr, "moo"); } diff --git a/test/regression/2014-07-04-unflushed-error-report.c b/test/regression/2014-07-04-unflushed-error-report.c index c929328d85..2374d554fa 100644 --- a/test/regression/2014-07-04-unflushed-error-report.c +++ b/test/regression/2014-07-04-unflushed-error-report.c @@ -6,6 +6,8 @@ /* This test checks that the error file isn't empty and contains the * right content. */ +#include "klee/klee.h" + int main() { unsigned int x = 15; unsigned int y; diff --git a/test/regression/2015-08-05-invalid-fork.c b/test/regression/2015-08-05-invalid-fork.c index f9b275652d..a797d2d757 100644 --- a/test/regression/2015-08-05-invalid-fork.c +++ b/test/regression/2015-08-05-invalid-fork.c @@ -3,6 +3,7 @@ is printed a single time. */ #include "klee/klee.h" +#include // RUN: %clang %s -emit-llvm -g %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out diff --git a/test/regression/2015-08-30-empty-constraints.c b/test/regression/2015-08-30-empty-constraints.c index f92b69785b..b01fee5e13 100644 --- a/test/regression/2015-08-30-empty-constraints.c +++ b/test/regression/2015-08-30-empty-constraints.c @@ -10,6 +10,8 @@ * are generated. * Make sure we are able to generate an input. */ +#include "klee/klee.h" + int main() { int d; diff --git a/test/regression/2015-08-30-sdiv-1.c b/test/regression/2015-08-30-sdiv-1.c index 7356e74c2a..5fa407f38d 100644 --- a/test/regression/2015-08-30-sdiv-1.c +++ b/test/regression/2015-08-30-sdiv-1.c @@ -7,7 +7,9 @@ /* Division by constant can be optimized.using mul/shift * For signed division, div by 1 or -1 cannot be optimized like that. */ +#include "klee/klee.h" #include + int main() { int32_t dividend; klee_make_symbolic(÷nd, sizeof dividend, "Dividend"); diff --git a/test/regression/2017-02-21-pathOS-id.c b/test/regression/2017-02-21-pathOS-id.c index 93cbceb507..8f41f1a69f 100644 --- a/test/regression/2017-02-21-pathOS-id.c +++ b/test/regression/2017-02-21-pathOS-id.c @@ -4,6 +4,12 @@ // RUN: %klee --output-dir=%t.klee-out --solver-backend=z3 -write-paths %t.bc 2> %t.log // RUN: cat %t.klee-out/test000001.path | wc -l | grep -q 1 // RUN: cat %t.klee-out/test000002.path | wc -l | grep -q 1 +// RUN: cat %t.klee-out/test000003.path | wc -l | grep -q 1 +// RUN: cat %t.klee-out/test000004.path | wc -l | grep -q 1 + +#include "klee/klee.h" +#include "stdlib.h" + int main() { int a, b; klee_make_symbolic(&a, sizeof(int), "a"); diff --git a/test/regression/2017-11-01-test-with-empty-varname.c b/test/regression/2017-11-01-test-with-empty-varname.c index 854498d7b4..0e3194f880 100644 --- a/test/regression/2017-11-01-test-with-empty-varname.c +++ b/test/regression/2017-11-01-test-with-empty-varname.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out %t1.bc // RUN: FileCheck %s --input-file=%t.klee-out/warnings.txt +#include "klee/klee.h" int main() { unsigned a; diff --git a/test/regression/2018-10-30-llvm-pr39177.ll b/test/regression/2018-10-30-llvm-pr39177.ll index 027d0d3014..b28947ab66 100644 --- a/test/regression/2018-10-30-llvm-pr39177.ll +++ b/test/regression/2018-10-30-llvm-pr39177.ll @@ -1,5 +1,7 @@ +; REQUIRES: lt-llvm-15.0 +; The optimizer is more efficient and uses fwrite directly in newer LLVM versions ; RUN: rm -rf %t.klee-out -; RUN: %llvmas -f %s -o - | %klee -optimize -output-dir=%t.klee-out | FileCheck %s +; RUN: %klee -optimize -output-dir=%t.klee-out %s | FileCheck %s 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-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/regression/2020-04-27-stp-array-names.c b/test/regression/2020-04-27-stp-array-names.c index f06e1b1a09..a256441c1d 100644 --- a/test/regression/2020-04-27-stp-array-names.c +++ b/test/regression/2020-04-27-stp-array-names.c @@ -1,4 +1,4 @@ -// RUN: %clang %s -emit-llvm %O0opt -g -c -o %t.bc +// RUN: %clang -std=c89 %s -emit-llvm %O0opt -g -c -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee -output-dir=%t.klee-out --search=bfs --max-instructions=1000 %t.bc b; diff --git a/test/regression/2023-11-20-solver.c b/test/regression/2023-11-20-solver.c new file mode 100644 index 0000000000..ceef818092 --- /dev/null +++ b/test/regression/2023-11-20-solver.c @@ -0,0 +1,36 @@ +// Test case based on #1668, generates array names as part of the solver builder that collide. +// This depends on the order of expression evaluation. +// +// RUN: %clang %s -g -emit-llvm %O0opt -c -o %t1.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out -silent-klee-assume --use-branch-cache=false --use-cex-cache=false --use-independent-solver=false %t1.bc 2>&1 | FileCheck %s +#include "klee/klee.h" +#include + +int main() { + int p1 = klee_int("val"); + int p2 = klee_int("val"); + int p3 = klee_int("val"); + int p4 = klee_int("val"); + int p5 = klee_int("val"); + int p6 = klee_int("val"); + int p7 = klee_int("val"); + int p8 = klee_int("val"); + int p9 = klee_int("val"); + int p10 = klee_int("val"); + int p11 = klee_int("val"); + int p12 = klee_int("val"); + int p13 = klee_int("val"); + int p14 = klee_int("val"); + int p15 = klee_int("val"); + int cond = klee_int("val"); + klee_assume(p12 > p14); + klee_assume(p6 > p3); + // klee_assume(p2 > 0); + klee_assume(p7 != 0); + klee_assume(p11 < p14 & p15 < p13); + klee_assume(cond > p5); + klee_assume(0 > p4); + // CHECK: [[@LINE+1]]: ASSERTION FAIL + assert(p2 > p11); +} \ No newline at end of file From 8546645c0aaf3d4dbadec045eb8a6f21698426b0 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 11:10:57 +0200 Subject: [PATCH 06/40] wip: --- scripts/build/p-libcxx.inc | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/scripts/build/p-libcxx.inc b/scripts/build/p-libcxx.inc index 641fad613f..006db9ad52 100644 --- a/scripts/build/p-libcxx.inc +++ b/scripts/build/p-libcxx.inc @@ -30,7 +30,6 @@ build_libcxx() { local LLVM_VERSION_MAJOR="${LLVM_VERSION/.*/}" local cmake_flags=( - "-DLLVM_ENABLE_PROJECTS=libcxx;libcxxabi" "-DLLVM_ENABLE_THREADS:BOOL=OFF" "-DLIBCXX_ENABLE_THREADS:BOOL=OFF" "-DLIBCXX_ENABLE_SHARED:BOOL=ON" @@ -39,6 +38,13 @@ build_libcxx() { "-DCMAKE_INSTALL_PREFIX=${LIBCXX_INSTALL}" ) + if [[ "${LLVM_VERSION_SHORT}" -ge "140" ]]; then + cmake_flags+=("-DLLVM_ENABLE_RUNTIMES=libcxx;libcxxabi") + cmake_flags+=("-DLLVM_ENABLE_PROJECTS=") + cmake_flags+=("-DLLVM_ENABLE_PROJECTS_USED:BOOL=ON") + else + cmake_flags+=("-DLLVM_ENABLE_PROJECTS=libcxx;libcxxabi") + fi # Static ABI libraries are not supported under OS X if [[ "${OS}" == "osx" ]]; then cmake_flags+=("-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY:BOOL=OFF") @@ -53,7 +59,11 @@ build_libcxx() { export LLVM_COMPILER_PATH="$(dirname "${BITCODE_CC}")" cmake "${cmake_flags[@]}" "${LIBCXX_SRC}/llvm" - make cxx -j$(nproc) || make cxx + if [[ "${LLVM_VERSION_SHORT}" -ge "140" ]]; then + make runtimes "-j$(nproc)" || make runtimes || return 1 + else + make cxx "-j$(nproc)" || make cxx || return 1 + fi ) } @@ -65,19 +75,24 @@ install_libcxx() { export LLVM_COMPILER=clang export LLVM_COMPILER_PATH="$(dirname "${BITCODE_CC}")" - cd "${LIBCXX_BUILD}/projects" - make install + if [[ "${LLVM_VERSION_SHORT}" -ge "140" ]]; then + cd "${LIBCXX_BUILD}/runtimes" || return 1 + make install || return 1 + else + cd "${LIBCXX_BUILD}/projects" || return 1 + make install || return 1 + fi local libraries if [[ "${OS}" == "osx" ]]; then - libraries=("${LIBCXX_INSTALL}"/lib/lib*.dylib) + libraries=("${LIBCXX_INSTALL}"/lib/*/lib*.dylib) else - libraries=("${LIBCXX_INSTALL}"/lib/lib*.so) + libraries=("${LIBCXX_INSTALL}"/lib/*/lib*.so) fi local LLVM_VERSION_MAJOR="${LLVM_VERSION/.*/}" - libraries+=("${LIBCXX_INSTALL}"/lib/lib*.a) + libraries+=("${LIBCXX_INSTALL}"/lib/*/lib*.a) for p in "${libraries[@]}" ; do @@ -113,4 +128,4 @@ get_build_artifacts_libcxx() { setup_artifact_variables_libcxx() { setup_build_variables_libcxx -} \ No newline at end of file +} From 23c69b5f8a60ade6a3f7d2c9997bfee6d9023c47 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 11:39:01 +0200 Subject: [PATCH 07/40] wip: --- CMakeLists.txt | 65 +++++++++++++---------------- runtime/CMakeLists.txt | 2 +- runtime/klee-eh-cxx/CMakeLists.txt | 9 +++- runtime/klee-eh-cxx/klee_eh_cxx.cpp | 2 +- scripts/build/p-klee.inc | 2 +- scripts/build/p-llvm.inc | 21 ++++++---- test/lit.site.cfg.in | 4 +- tools/kleaver/CMakeLists.txt | 3 +- tools/klee/CMakeLists.txt | 3 +- 9 files changed, 58 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4e4836058..ce26032373 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -558,51 +558,44 @@ option(ENABLE_KLEE_LIBCXX "Enable libc++ for klee" OFF) if (ENABLE_KLEE_LIBCXX) message(STATUS "klee-libc++ support enabled") set(SUPPORT_KLEE_LIBCXX 1) # For config.h - set(KLEE_LIBCXX_DIR "" CACHE PATH "Path to directory containing libc++ shared object (bitcode)") - if (NOT EXISTS "${KLEE_LIBCXX_DIR}") - message(FATAL_ERROR - "KLEE_LIBCXX_DIR (\"${KLEE_LIBCXX_DIR}\") does not exist.\n" - "Try passing -DKLEE_LIBCXX_DIR= to CMake where is the path" - "to the directory containing the libc++ shared object file (as bitcode).") - endif() - set(KLEE_LIBCXX_INCLUDE_DIR "" CACHE PATH "Path to libc++ include directory") - if (NOT EXISTS "${KLEE_LIBCXX_INCLUDE_DIR}") - message(FATAL_ERROR - "KLEE_LIBCXX_INCLUDE_DIR (\"${KLEE_LIBCXX_INCLUDE_DIR}\") does not exist.\n" - "Try passing -DKLEE_LIBCXX_INCLUDE_DIR= to CMake where is the" - "libc++ include directory.") - endif() - message(STATUS "Use libc++ include path: \"${KLEE_LIBCXX_INCLUDE_DIR}\"") - - # Find the library bitcode archive - - # Check for static first - set(KLEE_LIBCXX_BC_NAME "libc++.bca") - set(KLEE_LIBCXX_BC_PATH "${KLEE_LIBCXX_DIR}/lib/${KLEE_LIBCXX_BC_NAME}") - if (NOT EXISTS "${KLEE_LIBCXX_BC_PATH}") - # Check for dynamic so lib - set(KLEE_LIBCXX_BC_NAME "libc++.so.bc") - set(KLEE_LIBCXX_BC_PATH "${KLEE_LIBCXX_DIR}/lib/${KLEE_LIBCXX_BC_NAME}") - if (NOT EXISTS "${KLEE_LIBCXX_BC_PATH}") - set(KLEE_LIBCXX_BC_NAME "libc++.dylib.bc") - set(KLEE_LIBCXX_BC_PATH "${KLEE_LIBCXX_DIR}/lib/${KLEE_LIBCXX_BC_NAME}") - if (NOT EXISTS "${KLEE_LIBCXX_BC_PATH}") - message(FATAL_ERROR - "libc++ library not found at \"${KLEE_LIBCXX_DIR}\"") - endif() - endif() - endif() + find_file(KLEE_LIBCXX_BC_PATH + NAMES libc++.bca libc++.so.bc libc++.dylib.bc + DOC "Path to directory containing libc++ shared object (bitcode)" + PATH_SUFFIXES "lib" "lib/x86_64-unknown-linux-gnu" + HINTS ${KLEE_LIBCXX_DIR} + REQUIRED + ) message(STATUS "Found libc++ library: \"${KLEE_LIBCXX_BC_PATH}\"") + find_path(KLEE_LIBCXX_PLATFORM_INCLUDE_PATH + NAMES __config_site #We are searching for a platform-specific C++ library header called `__config_site` + DOC "Path to platform-specific libc++ include directory" + PATH_SUFFIXES "x86_64-unknown-linux-gnu/c++/v1" "include/x86_64-unknown-linux-gnu/c++/v1" + HINTS ${KLEE_LIBCXX_INCLUDE_DIR} + NO_DEFAULT_PATH # Make sure we don't pick-up the standard library's path + ) + + find_path(KLEE_LIBCXX_INCLUDE_PATH + NAMES cerrno #We are searching for a C++ library header called `cerrno` + DOC "Path to libc++ include directory" + PATH_SUFFIXES "c++/v1" "include/c++/v1" + HINTS ${KLEE_LIBCXX_INCLUDE_DIR} + REQUIRED + NO_DEFAULT_PATH # Make sure we don't pick-up the standard library's path + ) + + message(STATUS "Found libc++ include path: ${KLEE_LIBCXX_INCLUDE_PATH} and ${KLEE_LIBCXX_PLATFORM_INCLUDE_PATH} ") + + # Copy KLEE_LIBCXX_BC_PATH so KLEE can find it where it is expected. file(MAKE_DIRECTORY "${KLEE_RUNTIME_DIRECTORY}") execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${KLEE_LIBCXX_BC_PATH}" - "${KLEE_RUNTIME_DIRECTORY}/${KLEE_LIBCXX_BC_NAME}" + "${KLEE_RUNTIME_DIRECTORY}/${KLEE_LIBCXX_BC_PATH}" ) list(APPEND KLEE_COMPONENT_CXX_DEFINES - -DKLEE_LIBCXX_BC_NAME=\"${KLEE_LIBCXX_BC_NAME}\") + -DKLEE_LIBCXX_BC_NAME=\"${KLEE_LIBCXX_BC_PATH}\") else() message(STATUS "libc++ support disabled") diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index be7074a449..3e7b3bc2e1 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -42,7 +42,7 @@ foreach (bc_architecture ${bc_architectures}) elseif (bc_optimization STREQUAL "Release+Debug+Asserts") list(APPEND local_flags -O2 -g -D_DEBUG) elseif (bc_optimization STREQUAL "Debug") - list(APPEND local_flags -g -D_DEBUG -fpermissive) + list(APPEND local_flags -g -D_DEBUG -DNDEBUG) elseif (bc_optimization STREQUAL "Debug+Asserts") list(APPEND local_flags -g -D_DEBUG) else() diff --git a/runtime/klee-eh-cxx/CMakeLists.txt b/runtime/klee-eh-cxx/CMakeLists.txt index e016757b11..b51b854437 100644 --- a/runtime/klee-eh-cxx/CMakeLists.txt +++ b/runtime/klee-eh-cxx/CMakeLists.txt @@ -16,8 +16,15 @@ set(ADDITIONAL_CXX_FLAGS -nostdinc++ -I "${KLEE_LIBCXXABI_SRC_DIR}/src" -I "${KLEE_LIBCXXABI_SRC_DIR}/include" - -I "${KLEE_LIBCXX_INCLUDE_DIR}" + -I "${KLEE_LIBCXX_INCLUDE_PATH}" + -std=c++11 +) + +if (KLEE_LIBCXX_PLATFORM_INCLUDE_PATH) + list(APPEND ADDITIONAL_CXX_FLAGS + -I "${KLEE_LIBCXX_PLATFORM_INCLUDE_PATH}" ) +endif () # Build it include("${CMAKE_SOURCE_DIR}/cmake/compile_bitcode_library.cmake") prefix_with_path("${SRC_FILES}" "${CMAKE_CURRENT_SOURCE_DIR}/" prefixed_files) diff --git a/runtime/klee-eh-cxx/klee_eh_cxx.cpp b/runtime/klee-eh-cxx/klee_eh_cxx.cpp index bc604dd4d2..63e304badf 100644 --- a/runtime/klee-eh-cxx/klee_eh_cxx.cpp +++ b/runtime/klee-eh-cxx/klee_eh_cxx.cpp @@ -85,7 +85,7 @@ void *get_thrown_object_ptr(_Unwind_Exception *unwind_exception) { // Our implementation of a personality function for handling // libcxxabi-exceptions. Follows how libcxxabi's __gxx_personality_v0 handles // exceptions. -[[gnu::used]] extern "C" std::int32_t +extern "C" std::int32_t _klee_eh_cxx_personality(_Unwind_Exception *exceptionPointer, const std::size_t num_bytes, const unsigned char *lp_clauses) { diff --git a/scripts/build/p-klee.inc b/scripts/build/p-klee.inc index df87f94840..89d1b5f0df 100644 --- a/scripts/build/p-klee.inc +++ b/scripts/build/p-klee.inc @@ -52,7 +52,7 @@ if [ "${USE_LIBCXX}" -eq 1 ]; then CMAKE_ARGUMENTS+=( "-DENABLE_KLEE_LIBCXX=TRUE" "-DKLEE_LIBCXX_DIR=${LIBCXX_INSTALL}" - "-DKLEE_LIBCXX_INCLUDE_DIR=${LIBCXX_INSTALL}/include/c++/v1" + "-DKLEE_LIBCXX_INCLUDE_DIR=${LIBCXX_INSTALL}/include/" "-DENABLE_KLEE_EH_CXX=TRUE" "-DKLEE_LIBCXXABI_SRC_DIR=${LIBCXX_SRC}/libcxxabi" ) diff --git a/scripts/build/p-llvm.inc b/scripts/build/p-llvm.inc index abf895aee0..107878da36 100644 --- a/scripts/build/p-llvm.inc +++ b/scripts/build/p-llvm.inc @@ -174,16 +174,21 @@ configure_llvm() { ) if [[ "${SANITIZER_BUILD:-}" == "memory" ]]; then - # We have to build without libunwind if RTTI is disables + # We have to build without libunwind if RTTI is disabled CONFIG+=("-DLLVM_ENABLE_PROJECTS=${ENABLED_LLVM_PROJECTS}") else - CONFIG+=( - "-DLLVM_BUILD_LLVM_DYLIB:BOOL=ON" - "-DLLVM_LINK_LLVM_DYLIB:BOOL=ON" - "-DLLVM_BUILD_STATIC:BOOL=OFF" - "-DLIBCLANG_BUILD_STATIC:BOOL=OFF" - ) - CONFIG+=("-DLLVM_ENABLE_PROJECTS=${ENABLED_LLVM_PROJECTS};libcxx;libcxxabi;libunwind") + CONFIG+=( + "-DLLVM_BUILD_LLVM_DYLIB:BOOL=ON" + "-DLLVM_LINK_LLVM_DYLIB:BOOL=ON" + "-DLLVM_BUILD_STATIC:BOOL=OFF" + "-DLIBCLANG_BUILD_STATIC:BOOL=OFF" + ) + if [[ "${LLVM_VERSION_SHORT}" -ge "140" ]]; then + CONFIG+=("-DLLVM_ENABLE_PROJECTS=${ENABLED_LLVM_PROJECTS}") + CONFIG+=("-DLLVM_ENABLE_RUNTIMES=libcxx;libcxxabi") + else + CONFIG+=("-DLLVM_ENABLE_PROJECTS=${ENABLED_LLVM_PROJECTS};libcxx;libcxxabi") + fi fi if [[ -n ${SANITIZER_BUILD} ]]; then diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index bb3ac9cbcb..48081af6d7 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -9,7 +9,9 @@ config.klee_obj_root = "@KLEE_BINARY_DIR@" config.klee_tools_dir = "@KLEE_TOOLS_DIR@" config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.libcxx_include_dirs = ["@KLEE_LIBCXX_INCLUDE_DIR@"] +config.libcxx_include_dirs = ["@KLEE_LIBCXX_INCLUDE_PATH@"] +if len("@KLEE_LIBCXX_PLATFORM_INCLUDE_PATH@") > 0: + config.libcxx_include_dirs.append("@KLEE_LIBCXX_PLATFORM_INCLUDE_PATH@") # Needed to check if a hack needs to be applied config.llvm_version_major = "@LLVM_VERSION_MAJOR@" diff --git a/tools/kleaver/CMakeLists.txt b/tools/kleaver/CMakeLists.txt index b3e21e2613..c2960a7e88 100644 --- a/tools/kleaver/CMakeLists.txt +++ b/tools/kleaver/CMakeLists.txt @@ -13,8 +13,7 @@ add_executable(kleaver llvm_config(kleaver "${USE_LLVM_SHARED}" core support) target_link_libraries(kleaver PRIVATE kleaverSolver) -target_include_directories(kleaver SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) -target_include_directories(kleaver PRIVATE ${KLEE_INCLUDE_DIRS}) +target_include_directories(kleaver PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) target_compile_options(kleaver PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(kleaver PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) diff --git a/tools/klee/CMakeLists.txt b/tools/klee/CMakeLists.txt index d6664882bc..5d63f93901 100644 --- a/tools/klee/CMakeLists.txt +++ b/tools/klee/CMakeLists.txt @@ -15,8 +15,7 @@ set(KLEE_LIBS ) target_link_libraries(klee ${KLEE_LIBS}) -target_include_directories(klee SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) -target_include_directories(klee PRIVATE ${KLEE_INCLUDE_DIRS}) +target_include_directories(klee PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) target_compile_options(klee PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(klee PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) From 2f4ce12d579f928a0e09bdd4b6f0101becd1478a Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 12:08:13 +0200 Subject: [PATCH 08/40] fix: --- runtime/klee-eh-cxx/klee_eh_cxx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/klee-eh-cxx/klee_eh_cxx.cpp b/runtime/klee-eh-cxx/klee_eh_cxx.cpp index 63e304badf..bf45a114d5 100644 --- a/runtime/klee-eh-cxx/klee_eh_cxx.cpp +++ b/runtime/klee-eh-cxx/klee_eh_cxx.cpp @@ -85,7 +85,7 @@ void *get_thrown_object_ptr(_Unwind_Exception *unwind_exception) { // Our implementation of a personality function for handling // libcxxabi-exceptions. Follows how libcxxabi's __gxx_personality_v0 handles // exceptions. -extern "C" std::int32_t +__attribute__((used)) extern "C" std::int32_t _klee_eh_cxx_personality(_Unwind_Exception *exceptionPointer, const std::size_t num_bytes, const unsigned char *lp_clauses) { From f7ea216e860a73859f375ad2b628cb41284e37f8 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 16:06:20 +0200 Subject: [PATCH 09/40] fix: --- test/Expr/ReadExprConsistency.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Expr/ReadExprConsistency.c b/test/Expr/ReadExprConsistency.c index 661c64e2c2..4b7ee908ef 100644 --- a/test/Expr/ReadExprConsistency.c +++ b/test/Expr/ReadExprConsistency.c @@ -24,12 +24,12 @@ int main() { klee_make_symbolic(arr, sizeof(arr), "arr"); char a = arr[2]; // (ReadExpr 2 arr) - // CHECK: arr[2]:(Read w8 2 (array (w64 3) (makeSymbolic arr 0))) + // CHECK: arr[2]:(SExt w32 (Read w8 2 (array (w64 3) (makeSymbolic arr 0)))) klee_print_expr("arr[2]", arr[2]); arr[1] = 0; char b = arr[symbolic]; // (ReadExpr symbolic [1=0]@arr) - // CHECK: arr[2]:(Read w8 2 (array (w64 3) (makeSymbolic arr 0))) - // CHECK-NOT: arr[2]:(Read w8 2 [1=0]@ (array (w64 3) (makeSymbolic arr 0))) + // CHECK: arr[2]:(SExt w32 (Read w8 2 (array (w64 3) (makeSymbolic arr 0)))) + // CHECK-NOT: arr[2]:(SExt w32 (Read w8 2 [1=0]@ (array (w64 3) (makeSymbolic arr 0)))) klee_print_expr("arr[2]", arr[2]); if (a == b) From a8d5677340835073cdd3fa5385c03dd41ce67f88 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 23:58:59 +0200 Subject: [PATCH 10/40] wip: --- lib/Core/Executor.cpp | 8 +- test/Feature/DoubleFree.c | 2 +- test/Feature/ExtCall.c | 2 +- test/Feature/MultipleFreeResolution.c | 6 +- test/Feature/OneFreeError.c | 2 +- test/Feature/SeedConcretizeExtendFP.c | 37 --------- test/Feature/SeedConcretizeExternalCall.c | 28 ------- test/Feature/SeedConcretizeFP.c | 31 -------- test/Feature/SeedConcretizeMalloc.c | 36 --------- test/Feature/SeedExtension.c | 39 ---------- test/Feature/SilentKleeAssume.c | 2 +- test/Feature/SingleObjectResolution.c | 66 ---------------- test/Feature/WriteExecutionTree.c | 78 ------------------- test/Runtime/POSIX/FilePerm.c | 10 +-- ...-11-illegal-access-after-free-and-branch.c | 2 +- 15 files changed, 16 insertions(+), 333 deletions(-) delete mode 100644 test/Feature/SeedConcretizeExtendFP.c delete mode 100644 test/Feature/SeedConcretizeExternalCall.c delete mode 100644 test/Feature/SeedConcretizeFP.c delete mode 100644 test/Feature/SeedConcretizeMalloc.c delete mode 100644 test/Feature/SeedExtension.c delete mode 100644 test/Feature/SingleObjectResolution.c delete mode 100644 test/Feature/WriteExecutionTree.c diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 81db1fcd7d..63f3bf1a56 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -5330,8 +5330,8 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, for (std::vector>::iterator ai = arguments.begin(), ae = arguments.end(); ai != ae; ++ai) { - if (ExternalCalls == - ExternalCallPolicy::All) { // don't bother checking uniqueness + if (ExternalCalls == ExternalCallPolicy::All || + ExternalCalls == ExternalCallPolicy::OverApprox) { // don't bother checking uniqueness ref arg = *ai; if (auto pointer = dyn_cast(arg)) { arg = pointer->getValue(); @@ -5339,7 +5339,9 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, arg = optimizer.optimizeExpr(arg, true); ref ce = evaluator.visit(arg); ce->toMemory(&args[wordIndex]); - addConstraint(state, EqExpr::create(ce, arg)); + if (ExternalCalls == ExternalCallPolicy::All) { + addConstraint(state, EqExpr::create(ce, arg)); + } wordIndex += (ce->getWidth() + 63) / 64; } else { ref arg = toUnique(state, *ai); diff --git a/test/Feature/DoubleFree.c b/test/Feature/DoubleFree.c index 8c4a373500..47baca6b6e 100644 --- a/test/Feature/DoubleFree.c +++ b/test/Feature/DoubleFree.c @@ -8,7 +8,7 @@ int main() { int *x = malloc(sizeof(*x)); free(x); - // CHECK: memory error: double free + // CHECK: memory error: invalid pointer: free free(x); return 0; } diff --git a/test/Feature/ExtCall.c b/test/Feature/ExtCall.c index e38f92d948..5b9ffe0dca 100644 --- a/test/Feature/ExtCall.c +++ b/test/Feature/ExtCall.c @@ -17,7 +17,7 @@ int main() { int y = abs(x); printf("y = %d\n", y); - // CHECK: calling external: abs((ReadLSB w32 0 x)) + // CHECK: calling external: abs((ReadLSB w32 0 (array (w64 4) (makeSymbolic x 0)))) assert(x == y); } diff --git a/test/Feature/MultipleFreeResolution.c b/test/Feature/MultipleFreeResolution.c index be094e477e..c00d7481fd 100644 --- a/test/Feature/MultipleFreeResolution.c +++ b/test/Feature/MultipleFreeResolution.c @@ -36,9 +36,9 @@ int main() { free(buf[s]); for (i = 0; i < 3; i++) { - // CHECK: MultipleFreeResolution.c:[[@LINE+3]]: memory error: use after free - // CHECK: MultipleFreeResolution.c:[[@LINE+2]]: memory error: use after free - // CHECK: MultipleFreeResolution.c:[[@LINE+1]]: memory error: use after free + // CHECK: MultipleFreeResolution.c:[[@LINE+3]]: memory error: out of bound pointer + // CHECK: MultipleFreeResolution.c:[[@LINE+2]]: memory error: out of bound pointer + // CHECK: MultipleFreeResolution.c:[[@LINE+1]]: memory error: out of bound pointer printf("*buf[%d] = %d\n", i, *buf[i]); } diff --git a/test/Feature/OneFreeError.c b/test/Feature/OneFreeError.c index c8c44c168e..89746bda97 100644 --- a/test/Feature/OneFreeError.c +++ b/test/Feature/OneFreeError.c @@ -8,7 +8,7 @@ int main() { int *x = malloc(sizeof(*x)); free(x); - // CHECK: OneFreeError.c:[[@LINE+1]]: memory error: use after free + // CHECK: OneFreeError.c:[[@LINE+1]]: memory error: out of bound pointer x[0] = 1; return 0; } diff --git a/test/Feature/SeedConcretizeExtendFP.c b/test/Feature/SeedConcretizeExtendFP.c deleted file mode 100644 index 4a281912da..0000000000 --- a/test/Feature/SeedConcretizeExtendFP.c +++ /dev/null @@ -1,37 +0,0 @@ -/* This test checks the case where the seed needs to be patched on re-run */ - -// RUN: %clang -emit-llvm -c %O0opt -g %s -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc -// RUN: test -f %t.klee-out/test000001.ktest -// RUN: not test -f %t.klee-out/test000002.ktest - -// RUN: rm -rf %t.klee-out-2 -// RUN: %klee --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest --allow-seed-extension %t.bc 2>&1 | FileCheck %s -// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s - -#include "klee/klee.h" - -#include -#include -#include - -void TestGen() { - uint16_t x; - klee_make_symbolic(&x, sizeof(x), "x"); - klee_assume(x == 1234); -} - -int main() { - uint32_t i; - klee_make_symbolic(&i, sizeof(i), "i"); - - if (i < 5000) { - double d = i; - // CHECK: concretizing (reason: floating point) - assert((unsigned)d < 5001); - } - - // CHECK-STATS: 3 - // These is similar to SeedConcretizeFP.c (1 query) plus the extra queries due to an incomplete seed -} diff --git a/test/Feature/SeedConcretizeExternalCall.c b/test/Feature/SeedConcretizeExternalCall.c deleted file mode 100644 index 1898417075..0000000000 --- a/test/Feature/SeedConcretizeExternalCall.c +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clang -emit-llvm -c -g %s -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc -// RUN: test -f %t.klee-out/test000001.ktest -// RUN: not test -f %t.klee-out/test000002.ktest - -// RUN: rm -rf %t.klee-out-2 -// RUN: %klee --external-calls=all --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest %t.bc -// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s - -#include "klee/klee.h" - -#include -#include - -void TestGen() { - int x; - klee_make_symbolic(&x, sizeof(x), "x"); - klee_assume(x == 12345678); -} - -int main() { - int x; - klee_make_symbolic(&x, sizeof(x), "x"); - assert(abs(x) == 12345678); - - // CHECK-STATS: 1 -} diff --git a/test/Feature/SeedConcretizeFP.c b/test/Feature/SeedConcretizeFP.c deleted file mode 100644 index 3d55cd53ae..0000000000 --- a/test/Feature/SeedConcretizeFP.c +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clang -emit-llvm -c -g %s -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc -// RUN: test -f %t.klee-out/test000001.ktest -// RUN: not test -f %t.klee-out/test000002.ktest - -// RUN: rm -rf %t.klee-out-2 -// RUN: %klee --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest %t.bc 2>&1 | FileCheck %s -// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s - -#include "klee/klee.h" - -#include -#include - -void TestGen() { - unsigned x; - klee_make_symbolic(&x, sizeof(x), "x"); - klee_assume(x == 12345678); -} - -int main() { - unsigned i; - klee_make_symbolic(&i, sizeof(i), "i"); - double d = i; - // CHECK: concretizing (reason: floating point) - assert((unsigned)d == 12345678); - - // CHECK-STATS: 1 - // This one query involves the constraint that i == 12345678 -} diff --git a/test/Feature/SeedConcretizeMalloc.c b/test/Feature/SeedConcretizeMalloc.c deleted file mode 100644 index 3a6598b2e5..0000000000 --- a/test/Feature/SeedConcretizeMalloc.c +++ /dev/null @@ -1,36 +0,0 @@ -// RUN: %clang -emit-llvm -c -g %s -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --entry-point=SeedGen %t.bc -// RUN: test -f %t.klee-out/test000001.ktest -// RUN: not test -f %t.klee-out/test000002.ktest - -// RUN: rm -rf %t.klee-out-2 -// RUN: %klee --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest %t.bc | FileCheck --allow-empty %s -// RUN: %klee-stats --print-columns 'SolverQueries' --table-format=csv %t.klee-out-2 | FileCheck --check-prefix=CHECK-STATS %s - -#include "klee/klee.h" - -#include -#include -#include - -void SeedGen() { - size_t x; - klee_make_symbolic(&x, sizeof(x), "x"); - klee_assume(x == 100); -} - -int main(int argc, char **argv) { - size_t s; - klee_make_symbolic(&s, sizeof(s), "size"); - char *p = (char *)malloc(s); - if (!p) - return 0; - - if (s != 100) - printf("Error\n"); - // CHECK-NOT: Error - - // CHECK-STATS: 4 - // These queries are due to the explicit constraint asserting that s is 100 and the implicit one checking if we have a huge malloc -} diff --git a/test/Feature/SeedExtension.c b/test/Feature/SeedExtension.c deleted file mode 100644 index 04f6d7a6cc..0000000000 --- a/test/Feature/SeedExtension.c +++ /dev/null @@ -1,39 +0,0 @@ -/* This test checks the case where the seed needs to be patched on re-run */ - -// RUN: %clang -emit-llvm -c %O0opt -g %s -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --entry-point=TestGen %t.bc -// RUN: test -f %t.klee-out/test000001.ktest -// RUN: not test -f %t.klee-out/test000002.ktest - -// RUN: rm -rf %t.klee-out-2 -// RUN: %klee --exit-on-error --output-dir=%t.klee-out-2 --seed-file %t.klee-out/test000001.ktest --allow-seed-extension %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" - -#include -#include -#include - -void TestGen() { - int x; - klee_make_symbolic(&x, sizeof(x), "x"); - klee_assume(x == 12345678); -} - -int main() { - int i; - klee_make_symbolic(&i, sizeof(i), "i"); - double d = i; - // CHECK: concretizing (reason: floating point) - assert((unsigned)d == 12345678); - - int j; - klee_make_symbolic(&j, sizeof(j), "j"); - if (j) - printf("Yes\n"); - // CHECK-DAG: Yes - else - printf("No\n"); - // CHECK-DAG: No -} diff --git a/test/Feature/SilentKleeAssume.c b/test/Feature/SilentKleeAssume.c index 38d6bae623..35b6a16094 100644 --- a/test/Feature/SilentKleeAssume.c +++ b/test/Feature/SilentKleeAssume.c @@ -15,7 +15,7 @@ int main() { int y = klee_int("y"); klee_assume(x > 10); if (y < 42) { - // CHECK-DEFAULT-KLEE-ASSUME: KLEE: ERROR: {{.*SilentKleeAssume.c:18}}: invalid klee_assume call (provably false) + // CHECK-DEFAULT-KLEE-ASSUME: KLEE: ERROR: {{.*SilentKleeAssume.c:}}[[@LINE+1]]: invalid klee_assume call (provably false) klee_assume(x < 10); // CHECK-DEFAULT-KLEE-ASSUME: KLEE: NOTE: now ignoring this error at this location // CHECK-DEFAULT-KLEE-ASSUME: EXITING ON ERROR: diff --git a/test/Feature/SingleObjectResolution.c b/test/Feature/SingleObjectResolution.c deleted file mode 100644 index c1de4185ee..0000000000 --- a/test/Feature/SingleObjectResolution.c +++ /dev/null @@ -1,66 +0,0 @@ -// RUN: %clang %s -g -emit-llvm %O0opt -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --search=dfs --output-dir=%t.klee-out --single-object-resolution %t.bc > %t.log 2>&1 -// RUN: FileCheck %s -input-file=%t.log - -#include "klee/klee.h" -#include - -struct A { - long long int y; - long long int y2; - int z; -}; - -struct B { - long long int x; - struct A y[20]; - struct A *y1; - struct A *y2; - int z; -}; - -int bar(int *pointer, int selector) { - int *ptr = 0; - if (selector) - ptr = pointer + 123; - else - ptr = pointer + 124; - // CHECK: SingleObjectResolution.c:[[@LINE+1]]: memory error: out of bound pointer - return *ptr; -} - -int foo() { - size_t x; - int y; - struct B b; - - // create a lot of memory objects - int *ptrs[1024]; - for (int i = 0; i < 1024; i++) { - ptrs[i] = malloc(23); - } - - klee_make_symbolic(&x, sizeof(x), "x"); - klee_make_symbolic(&y, sizeof(y), "y"); - - b.y1 = malloc(20 * sizeof(struct A)); - - // dereference of a pointer within a struct - int *tmp = &b.y1[x].z; - - int z = bar(tmp, y); - // cleanup test for heap - free(b.y1); - - tmp = &b.y[x].z; // this is to test the cleanup for stack vars - z = bar(tmp, y); - return z; -} - -int main(int argc, char *argv[]) { - // CHECK: KLEE: done: completed paths = 2 - // CHECK: KLEE: done: partially completed paths = 2 - // CHECK: KLEE: done: generated tests = 3 - return foo(); -} diff --git a/test/Feature/WriteExecutionTree.c b/test/Feature/WriteExecutionTree.c deleted file mode 100644 index 42f531a5fe..0000000000 --- a/test/Feature/WriteExecutionTree.c +++ /dev/null @@ -1,78 +0,0 @@ -// RUN: %clang %s -emit-llvm %O0opt -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee -write-exec-tree --output-dir=%t.klee-out %t.bc -// RUN: %klee-exec-tree branches %t.klee-out/exec_tree.db | FileCheck --check-prefix=CHECK-BRANCH %s -// RUN: %klee-exec-tree depths %t.klee-out | FileCheck --check-prefix=CHECK-DEPTH %s -// RUN: %klee-exec-tree instructions %t.klee-out | FileCheck --check-prefix=CHECK-INSTR %s -// RUN: %klee-exec-tree terminations %t.klee-out | FileCheck --check-prefix=CHECK-TERM %s -// RUN: %klee-exec-tree tree-dot %t.klee-out | FileCheck --check-prefix=CHECK-DOT %s -// RUN: %klee-exec-tree tree-info %t.klee-out | FileCheck --check-prefix=CHECK-TINFO %s -// RUN: not %klee-exec-tree dot %t.klee-out/exec-tree-doesnotexist.db - -#include "klee/klee.h" - -#include - -int main(void) { - int a = 42; - int c0, c1, c2, c3; - klee_make_symbolic(&c0, sizeof(c0), "c0"); - klee_make_symbolic(&c1, sizeof(c1), "c1"); - klee_make_symbolic(&c2, sizeof(c2), "c2"); - klee_make_symbolic(&c3, sizeof(c3), "c3"); - - if (c0) { - a += 17; - } else { - a -= 4; - } - - if (c1) { - klee_assume(!c1); - } else if (c2) { - char *p = NULL; - p[4711] = '!'; - } else if (c3) { - klee_silent_exit(0); - } else { - return a; - } - - return 0; -} - -// CHECK-BRANCH: branch type,count -// CHECK-BRANCH: Conditional,7 - -// CHECK-DEPTH: depth,count -// CHECK-DEPTH: 3,2 -// CHECK-DEPTH: 4,2 -// CHECK-DEPTH: 5,4 - -// CHECK-INSTR: asm line,branches,terminations,termination types -// CHECK-INSTR-DAG: {{[0-9]+}},0,2,User(2) -// CHECK-INSTR-DAG: {{[0-9]+}},0,2,Ptr(2) -// CHECK-INSTR-DAG: {{[0-9]+}},0,2,SilentExit(2) -// CHECK-INSTR-DAG: {{[0-9]+}},0,2,Exit(2) - -// CHECK-TERM: termination type,count -// CHECK-TERM-DAG: Exit,2 -// CHECK-TERM-DAG: Ptr,2 -// CHECK-TERM-DAG: User,2 -// CHECK-TERM-DAG: SilentExit,2 - -// CHECK-DOT: strict digraph ExecutionTree { -// CHECK-DOT: node[shape=point,width=0.15,color=darkgrey]; -// CHECK-DOT: edge[color=darkgrey]; -// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="Conditional\nnode: {{[0-9]+}}\nstate: 0\nasm: {{[0-9]+}}"]; -// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="Exit\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=green]; -// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="SilentExit\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=orange]; -// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="Ptr\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=red]; -// CHECK-DOT-DAG: N{{[0-9]+}}[tooltip="User\nnode: {{[0-9]+}}\nstate: {{[0-9]+}}\nasm: {{[0-9]+}}",color=blue]; -// CHECK-DOT-DAG: N{{[0-9]+}}->{N{{[0-9]+}} N{{[0-9]+}}}; -// CHECK-DOT-DAG: } - -// CHECK-TINFO: nodes: 15 -// CHECK-TINFO: leaf nodes: 8 -// CHECK-TINFO: max. depth: 5 -// CHECK-TINFO: avg. depth: 4.2 diff --git a/test/Runtime/POSIX/FilePerm.c b/test/Runtime/POSIX/FilePerm.c index b63bf5c384..e19862a72f 100644 --- a/test/Runtime/POSIX/FilePerm.c +++ b/test/Runtime/POSIX/FilePerm.c @@ -3,7 +3,6 @@ // RUN: %clang %s -emit-llvm %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-files 1 10 --sym-stdout 2>%t.log // RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-files 1 10 | FileCheck %s // RUN: test -f %t.klee-out/test000001.ktest // RUN: test -f %t.klee-out/test000002.ktest @@ -15,14 +14,11 @@ #include #include -int main(int argc, char **argv) { + +int main(int argc, char** argv) { int fd = open("A", O_RDWR); if (fd != -1) - fprintf(stderr, "File 'A' opened successfully\n"); - else - fprintf(stderr, "Cannot open file 'A'\n"); - - printf("File 'A' opened successfully\n"); + printf("File 'A' opened successfully\n"); // CHECK-DAG: File 'A' opened successfully else printf("Cannot open file 'A'\n"); // CHECK-DAG: Cannot open file 'A' 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 868152ff59..024384f8cc 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 @@ -15,7 +15,7 @@ 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:[[@LINE+1]]: memory error: use after free + // CHECK: 2007-10-11-illegal-access-after-free-and-branch.c:[[@LINE+1]]: memory error: out of bound pointer return buf[2]; } klee_silent_exit(0); From 292a765eab595ec83591c3820fa5ae2486fa5089 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 13 Aug 2024 23:59:53 +0200 Subject: [PATCH 11/40] style: --- lib/Core/Executor.cpp | 4 +++- lib/Module/InstrumentLegacy.cpp | 8 +++----- lib/Module/KModule.cpp | 6 +++--- lib/Module/ModuleHelper.h | 3 +-- lib/Module/Optimize.cpp | 6 ++---- test/Runtime/POSIX/FilePerm.c | 6 +++--- 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 63f3bf1a56..bf6707bd72 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -5331,7 +5331,9 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, ae = arguments.end(); ai != ae; ++ai) { if (ExternalCalls == ExternalCallPolicy::All || - ExternalCalls == ExternalCallPolicy::OverApprox) { // don't bother checking uniqueness + ExternalCalls == + ExternalCallPolicy::OverApprox) { // don't bother checking + // uniqueness ref arg = *ai; if (auto pointer = dyn_cast(arg)) { arg = pointer->getValue(); diff --git a/lib/Module/InstrumentLegacy.cpp b/lib/Module/InstrumentLegacy.cpp index efb84cbdc2..9d7db4771a 100644 --- a/lib/Module/InstrumentLegacy.cpp +++ b/lib/Module/InstrumentLegacy.cpp @@ -90,9 +90,8 @@ void klee::checkModule(bool DontVerify, llvm::Module *module) { } void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, - bool Simplify, - bool WithFPRuntime, SwitchImplType SwitchType, - std::string EntryPoint, + bool Simplify, bool WithFPRuntime, + SwitchImplType SwitchType, std::string EntryPoint, llvm::ArrayRef preservedFunctions, llvm::Module *module) { // Preserve all functions containing klee-related function calls from being @@ -107,8 +106,7 @@ void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, if (WithFPRuntime) { if (UseKleeFloatInternals) { for (const auto &p : klee::floatReplacements) { - replaceOrRenameFunction(module, p.first.c_str(), - p.second.c_str()); + replaceOrRenameFunction(module, p.first.c_str(), p.second.c_str()); } } } diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index 617f25f040..76f2e3bc70 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -228,9 +228,9 @@ void KModule::optimiseAndPrepare( if (opts.CheckOvershift) addInternalFunction("klee_overshift_check"); - klee::optimiseAndPrepare(OptimiseKLEECall, opts.Optimize, opts.Simplify, opts.WithFPRuntime, - SwitchType, opts.EntryPoint, preservedFunctions, - module.get()); + klee::optimiseAndPrepare(OptimiseKLEECall, opts.Optimize, opts.Simplify, + opts.WithFPRuntime, SwitchType, opts.EntryPoint, + preservedFunctions, module.get()); } class InstructionToLineAnnotator : public llvm::AssemblyAnnotationWriter { diff --git a/lib/Module/ModuleHelper.h b/lib/Module/ModuleHelper.h index 1eff55ee64..89398adadf 100644 --- a/lib/Module/ModuleHelper.h +++ b/lib/Module/ModuleHelper.h @@ -20,8 +20,7 @@ enum class SwitchImplType { eSwitchTypeInternal }; -void optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, - bool Simplify, +void optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, bool Simplify, bool WithFPRuntime, SwitchImplType SwitchType, std::string EntryPoint, llvm::ArrayRef preservedFunctions, diff --git a/lib/Module/Optimize.cpp b/lib/Module/Optimize.cpp index 64d3b4694a..b0e35e1cf1 100644 --- a/lib/Module/Optimize.cpp +++ b/lib/Module/Optimize.cpp @@ -31,13 +31,11 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Utils.h" -#include "llvm/IR/Module.h" using namespace klee; void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, - bool Simplify, - bool WithFPRuntime, SwitchImplType SwitchType, - std::string EntryPoint, + bool Simplify, bool WithFPRuntime, + SwitchImplType SwitchType, std::string EntryPoint, llvm::ArrayRef preservedFunctions, llvm::Module *module) { assert(0); diff --git a/test/Runtime/POSIX/FilePerm.c b/test/Runtime/POSIX/FilePerm.c index e19862a72f..f60447a0cf 100644 --- a/test/Runtime/POSIX/FilePerm.c +++ b/test/Runtime/POSIX/FilePerm.c @@ -14,13 +14,13 @@ #include #include - -int main(int argc, char** argv) { +int main(int argc, char **argv) { int fd = open("A", O_RDWR); if (fd != -1) printf("File 'A' opened successfully\n"); // CHECK-DAG: File 'A' opened successfully - else printf("Cannot open file 'A'\n"); + else + printf("Cannot open file 'A'\n"); // CHECK-DAG: Cannot open file 'A' if (fd != -1) close(fd); From f837b53500103303c9fb48345be35af5d461ffea Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 14 Aug 2024 22:17:23 +0200 Subject: [PATCH 12/40] chore: Add DEBT --- DEBT | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 DEBT diff --git a/DEBT b/DEBT new file mode 100644 index 0000000000..26456addab --- /dev/null +++ b/DEBT @@ -0,0 +1,13 @@ +KLEE 3.1, 29 February 2024 +========================== + +- New execution tree implementation and klee-exec-tree tool (@251) +- KDAlloc is now the default allocator in KLEE (KDAlloc was introduced in KLEE 3.0) +- Resolve memory reads/writes to single objects in more cases (@tkuchta) +- Concretize values based on seeds when available (@ccadar) + + +KLEE 3.0, 7 June 2023 +===================== + +- Added support for the KDAlloc memory allocator, which enables KLEE to more robustly detect use-after-free errors, improves the detection of buffer overflows, and provides deterministic memory allocation (@danielschemmel, based on https://srg.doc.ic.ac.uk/publications/22-kdalloc-ecoop.html) \ No newline at end of file From 67bcb30de4894ab22a6bdf3f2054b3b8988cca39 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 14 Aug 2024 22:28:40 +0200 Subject: [PATCH 13/40] fix: --- lib/Core/Executor.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index bf6707bd72..2c9f3ad292 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -1968,10 +1968,14 @@ MemoryObject *Executor::serializeLandingpad(ExecutionState &state, std::uint64_t ti_addr = 0; - llvm::BitCastOperator *clause_bitcast = - dyn_cast(current_clause); - if (clause_bitcast) { - llvm::GlobalValue *clause_type = + llvm::Constant *catchClause = lpi.getClause(current_clause_id); + llvm::Constant *typeInfo = catchClause->stripPointerCasts(); + if (auto *gv = dyn_cast(typeInfo)) { + ti_addr = + cast(globalAddresses[gv]->getValue())->getZExtValue(); + } else if (auto *clause_bitcast = + dyn_cast(catchClause)) { + auto *clause_type = dyn_cast(clause_bitcast->getOperand(0)); // Since global variable may have symbolic address, @@ -1995,7 +1999,9 @@ MemoryObject *Executor::serializeLandingpad(ExecutionState &state, pointerMask[old_size + i] = ti_addr; } } else if (lpi.isFilter(current_clause_id)) { - if (current_clause->isNullValue()) { + llvm::Constant *filter_clause = lpi.getClause(current_clause_id); + + if (filter_clause->isNullValue()) { // special handling for a catch-all filter clause, i.e., "[0 x i8*]" // for this case we serialize 1 element.. serialized.push_back(1); @@ -2004,8 +2010,7 @@ MemoryObject *Executor::serializeLandingpad(ExecutionState &state, serialized.resize(serialized.size() + 8, 0); pointerMask.resize(pointerMask.size() + 8, 0); } else { - llvm::ConstantArray const *ca = - cast(current_clause); + const auto *ca = cast(filter_clause); // serialize `num_elements+1` as unsigned char unsigned const num_elements = ca->getNumOperands(); @@ -2025,18 +2030,16 @@ MemoryObject *Executor::serializeLandingpad(ExecutionState &state, // serialize the exception-types occurring in this filter-clause for (llvm::Value const *v : ca->operands()) { - llvm::BitCastOperator const *bitcast = - dyn_cast(v); - if (!bitcast) { - terminateStateOnExecError(state, - "Internal: expected value inside a " - "filter-clause to be a bitcast"); - stateTerminated = true; - return nullptr; + llvm::GlobalValue const *clause_value = nullptr; + + if (auto const *bitcast = dyn_cast(v)) { + clause_value = dyn_cast(bitcast->getOperand(0)); + } + + if (auto const *gv = dyn_cast(v)) { + clause_value = gv; } - llvm::GlobalValue const *clause_value = - dyn_cast(bitcast->getOperand(0)); if (!clause_value) { terminateStateOnExecError( state, "Internal: expected value inside a " From 9081bb9ff264118bca6ef873288f8eb9f7f264cb Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 14 Aug 2024 22:28:52 +0200 Subject: [PATCH 14/40] chore: Update `build.sh` --- build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index e4ef6de75f..e716cd7b63 100755 --- a/build.sh +++ b/build.sh @@ -26,7 +26,7 @@ USE_LIBCXX=1 SQLITE_VERSION="3400100" ## LLVM Required options -LLVM_VERSION=14 +LLVM_VERSION=16 ENABLE_OPTIMIZED=1 ENABLE_DEBUG=0 DISABLE_ASSERTIONS=1 @@ -72,4 +72,4 @@ else fi done -BASE="$BASE" BUILD_SUFFIX="$BUILD_SUFFIX" KLEE_RUNTIME_BUILD=$KLEE_RUNTIME_BUILD COVERAGE=$COVERAGE ENABLE_DOXYGEN=$ENABLE_DOXYGEN USE_TCMALLOC=$USE_TCMALLOC USE_LIBCXX=$USE_LIBCXX LLVM_VERSION=$LLVM_VERSION ENABLE_OPTIMIZED=$ENABLE_OPTIMIZED ENABLE_DEBUG=$ENABLE_DEBUG DISABLE_ASSERTIONS=$DISABLE_ASSERTIONS REQUIRES_RTTI=$REQUIRES_RTTI SOLVERS=$SOLVERS GTEST_VERSION=$GTEST_VERSION UCLIBC_VERSION=$UCLIBC_VERSION STP_VERSION=$STP_VERSION MINISAT_VERSION=$MINISAT_VERSION Z3_VERSION=$Z3_VERSION BITWUZLA_VERSION=$BITWUZLA_VERSION SQLITE_VERSION=$SQLITE_VERSION JSON_VERSION=$JSON_VERSION IMMER_VERSION=$IMMER_VERSION SANITIZER_BUILD=$SANITIZER_BUILD SANITIZER_LLVM_VERSION=$SANITIZER_LLVM_VERSION ENABLE_WARNINGS_AS_ERRORS=$ENABLE_WARNINGS_AS_ERRORS ./scripts/build/build.sh klee --install-system-deps +BASE="$BASE" BUILD_SUFFIX="$BUILD_SUFFIX" KLEE_RUNTIME_BUILD=$KLEE_RUNTIME_BUILD COVERAGE=$COVERAGE ENABLE_DOXYGEN=$ENABLE_DOXYGEN USE_TCMALLOC=$USE_TCMALLOC TCMALLOC_VERSION=$TCMALLOC_VERSION USE_LIBCXX=$USE_LIBCXX LLVM_VERSION=$LLVM_VERSION ENABLE_OPTIMIZED=$ENABLE_OPTIMIZED ENABLE_DEBUG=$ENABLE_DEBUG DISABLE_ASSERTIONS=$DISABLE_ASSERTIONS REQUIRES_RTTI=$REQUIRES_RTTI SOLVERS=$SOLVERS GTEST_VERSION=$GTEST_VERSION UCLIBC_VERSION=$UCLIBC_VERSION STP_VERSION=$STP_VERSION MINISAT_VERSION=$MINISAT_VERSION Z3_VERSION=$Z3_VERSION BITWUZLA_VERSION=$BITWUZLA_VERSION SQLITE_VERSION=$SQLITE_VERSION JSON_VERSION=$JSON_VERSION IMMER_VERSION=$IMMER_VERSION SANITIZER_BUILD=$SANITIZER_BUILD SANITIZER_LLVM_VERSION=$SANITIZER_LLVM_VERSION ENABLE_WARNINGS_AS_ERRORS=$ENABLE_WARNINGS_AS_ERRORS ./scripts/build/build.sh klee --install-system-deps From c7a4f90bcfcf30f180de50e4759ee140f5de5d71 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 15 Aug 2024 13:47:55 +0200 Subject: [PATCH 15/40] fix: --- test/Feature/CoverageCheck.c | 1 + test/Feature/LazyInitialization/DerefSymbolicPointer.c | 1 + test/Feature/LazyInitialization/LazyInitialization.c | 2 ++ test/Feature/LazyInitialization/LinkedList.c | 1 + test/Feature/MemoryBackends.c | 5 +++-- test/Feature/RecursionPruning/sum.c | 1 + test/Floats/internal_fabs_double.c | 3 +-- test/Floats/internal_fabs_float.c | 3 +-- test/Floats/internal_fabs_long_double.c | 2 -- test/VarArgs/VarArgByVal.c | 3 --- test/regression/2022-06-15-concretization-effects.c | 1 + test/regression/2023-08-28-invalid-pointer-dereference.c | 1 + 12 files changed, 13 insertions(+), 11 deletions(-) diff --git a/test/Feature/CoverageCheck.c b/test/Feature/CoverageCheck.c index a9c9eb2b63..342bd332e8 100644 --- a/test/Feature/CoverageCheck.c +++ b/test/Feature/CoverageCheck.c @@ -2,6 +2,7 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --use-guided-search=none --use-cov-check=instruction-based --output-dir=%t.klee-out %t.bc > %t.log #include "klee/klee.h" +#include #define a (2) int main() { diff --git a/test/Feature/LazyInitialization/DerefSymbolicPointer.c b/test/Feature/LazyInitialization/DerefSymbolicPointer.c index b0919d56a3..610365980c 100644 --- a/test/Feature/LazyInitialization/DerefSymbolicPointer.c +++ b/test/Feature/LazyInitialization/DerefSymbolicPointer.c @@ -3,6 +3,7 @@ // RUN: %klee --write-kqueries --output-dir=%t.klee-out --skip-not-symbolic-objects %t.bc > %t.log // RUN: FileCheck %s -input-file=%t.log #include "klee/klee.h" +#include int main() { int *a; diff --git a/test/Feature/LazyInitialization/LazyInitialization.c b/test/Feature/LazyInitialization/LazyInitialization.c index ca055d7d32..ba960bf300 100644 --- a/test/Feature/LazyInitialization/LazyInitialization.c +++ b/test/Feature/LazyInitialization/LazyInitialization.c @@ -2,6 +2,8 @@ // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --skip-not-symbolic-objects --use-timestamps=false --use-guided-search=none %t.bc > %t.log // RUN: FileCheck %s -input-file=%t.log +#include "klee/klee.h" +#include struct Node { int x; diff --git a/test/Feature/LazyInitialization/LinkedList.c b/test/Feature/LazyInitialization/LinkedList.c index 191ce3103b..42af81a362 100644 --- a/test/Feature/LazyInitialization/LinkedList.c +++ b/test/Feature/LazyInitialization/LinkedList.c @@ -3,6 +3,7 @@ // RUN: %klee --write-kqueries --output-dir=%t.klee-out --skip-not-symbolic-objects %t.bc > %t.log // RUN: FileCheck %s -input-file=%t.log #include "klee/klee.h" +#include struct Node { int x; diff --git a/test/Feature/MemoryBackends.c b/test/Feature/MemoryBackends.c index c686ca8d57..7ce117f1c5 100644 --- a/test/Feature/MemoryBackends.c +++ b/test/Feature/MemoryBackends.c @@ -14,6 +14,7 @@ correctness check (aside from testing that the various combinations don't crash) */ +#include "klee/klee.h" #include int validate(char *buf, int N) { @@ -34,7 +35,7 @@ int validate(char *buf, int N) { #endif int main(int argc, char **argv) { int N = SYMBOLIC_SIZE; - unsigned char *buf = malloc(N); + char *buf = malloc(N); int i; klee_make_symbolic(buf, N, "buf"); @@ -45,7 +46,7 @@ int main(int argc, char **argv) { int other_main(int argc, char **argv) { int N = SYMBOLIC_SIZE; - unsigned char *buf = malloc(N); + char *buf = malloc(N); int i; klee_make_symbolic(buf, N, "buf"); diff --git a/test/Feature/RecursionPruning/sum.c b/test/Feature/RecursionPruning/sum.c index bc74f0e85f..08e36cc2db 100644 --- a/test/Feature/RecursionPruning/sum.c +++ b/test/Feature/RecursionPruning/sum.c @@ -4,6 +4,7 @@ // RUN: %klee-stats --print-columns 'ICov(%),BCov(%)' --table-format=csv %t.klee-out > %t.stats // RUN: FileCheck -check-prefix=CHECK-STATS -input-file=%t.stats %s #include "klee/klee.h" +#include #define a (2) int main() { diff --git a/test/Floats/internal_fabs_double.c b/test/Floats/internal_fabs_double.c index 011c9314f2..5557d3b445 100644 --- a/test/Floats/internal_fabs_double.c +++ b/test/Floats/internal_fabs_double.c @@ -5,10 +5,9 @@ // REQUIRES: fp-runtime #include "klee/klee.h" #include -#include #include #include -#include +#include int main() { // -ve diff --git a/test/Floats/internal_fabs_float.c b/test/Floats/internal_fabs_float.c index 4e3dcab6e0..2e952c3707 100644 --- a/test/Floats/internal_fabs_float.c +++ b/test/Floats/internal_fabs_float.c @@ -5,10 +5,9 @@ // REQUIRES: fp-runtime #include "klee/klee.h" #include -#include #include #include -#include +#include int main() { // -ve diff --git a/test/Floats/internal_fabs_long_double.c b/test/Floats/internal_fabs_long_double.c index acd9dad71a..6c98b53653 100644 --- a/test/Floats/internal_fabs_long_double.c +++ b/test/Floats/internal_fabs_long_double.c @@ -6,10 +6,8 @@ // REQUIRES: fp-runtime #include "klee/klee.h" #include -#include #include #include -#include #include long double make_long_double(uint16_t highBits, uint64_t lowBits) { diff --git a/test/VarArgs/VarArgByVal.c b/test/VarArgs/VarArgByVal.c index 699d531ee6..05a245f02b 100644 --- a/test/VarArgs/VarArgByVal.c +++ b/test/VarArgs/VarArgByVal.c @@ -10,9 +10,6 @@ // RUN: FileCheck %s --input-file=%t.klee-out/assembly.ll // // TODO: Make noundef unconditional when LLVM 14 is the oldest supported version. -// CHECK: @test1({{.*}}, i32 {{(noundef )?}}-1, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval -// CHECK: @test2({{.*}}, %struct.foo* {{(noundef )?}}byval{{.*}} %struct.bar* {{(noundef )?}}byval - // CHECK: call void (ptr, i32, ...) @test1(ptr sret(%struct.foo) align 8 {{.*}}, i32 noundef -1, ptr noundef byval(%struct.foo) align 8 {{.*}}, ptr noundef byval(%struct.bar) align 8 {{.*}}) // CHECK: call void (ptr, i32, i64, ...) @test2(ptr sret(%struct.foo) align 8 {{.*}}, i32 noundef {{.*}}, i64 noundef {{.*}}, i32 noundef {{.*}}, ptr noundef byval(%struct.foo) align 8 {{.*}}, i64 noundef {{.*}}, ptr noundef byval(%struct.bar) align 8 {{.*}}, ptr noundef byval(%struct.foo) align 8 {{.*}}, ptr noundef byval(%struct.bar) align 8 {{.*}}) #include diff --git a/test/regression/2022-06-15-concretization-effects.c b/test/regression/2022-06-15-concretization-effects.c index 54978f59bb..450cc73179 100644 --- a/test/regression/2022-06-15-concretization-effects.c +++ b/test/regression/2022-06-15-concretization-effects.c @@ -1,6 +1,7 @@ // RUN: %clang %s -emit-llvm %O0opt -c -g -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --external-calls=all --exit-on-error --output-dir=%t.klee-out %t.bc > %t.output.log 2>&1 +#include "klee/klee.h" #include #include diff --git a/test/regression/2023-08-28-invalid-pointer-dereference.c b/test/regression/2023-08-28-invalid-pointer-dereference.c index cdd8388e71..7449a73372 100644 --- a/test/regression/2023-08-28-invalid-pointer-dereference.c +++ b/test/regression/2023-08-28-invalid-pointer-dereference.c @@ -1,6 +1,7 @@ // RUN: %clang %s -g -emit-llvm %O0opt -c -o %t.bc // RUN: rm -rf %t.klee-out // RUN: %klee --use-sym-size-alloc --output-dir=%t.klee-out %t.bc 2>&1 | FileCheck %s +#include "klee/klee.h" #pragma clang attribute push(__attribute__((optnone)), apply_to = function) From 585efec61dfd7e60712f4b3368088a5b3e2e23f1 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 15 Aug 2024 14:26:59 +0200 Subject: [PATCH 16/40] chore: Delete KType and TypeManager --- include/klee/Module/KType.h | 116 ------- lib/Core/AddressSpace.cpp | 34 +- lib/Core/AddressSpace.h | 14 +- lib/Core/CMakeLists.txt | 2 - lib/Core/CXXTypeSystem/CXXTypeManager.h | 263 -------------- lib/Core/ExecutionState.cpp | 5 +- lib/Core/ExecutionState.h | 11 +- lib/Core/Executor.cpp | 326 ++++++------------ lib/Core/Executor.h | 39 +-- lib/Core/Memory.cpp | 20 +- lib/Core/Memory.h | 21 +- lib/Core/MemoryManager.cpp | 12 +- lib/Core/MemoryManager.h | 5 +- lib/Core/SpecialFunctionHandler.cpp | 89 ++--- lib/Core/TypeManager.h | 66 ---- lib/Module/CMakeLists.txt | 1 - lib/Module/KType.cpp | 45 --- test/Feature/types/ArrayAccess.c | 39 --- test/Feature/types/InnerStructAccess.c | 40 --- test/Feature/types/StructDereference.c | 31 -- .../types/SymbolicPointerMultipleResolve.c | 66 ---- .../types/SymbolicPointerSimpleResolve.c | 26 -- test/Feature/types/UnionAccess.c | 29 -- .../effective-type/EffectiveTypeFirstRead.c | 30 -- .../effective-type/EffectiveTypeMalloc.c | 41 --- .../effective-type/EffectiveTypeMemset.c | 41 --- .../effective-type/EffectiveTypeRealloc.c | 50 --- .../types/effective-type/OperatorNew.cpp | 50 --- .../ArrayPointerAlignment.c | 23 -- .../DefaultPointerAlignment.c | 24 -- .../EffectiveTypePointerAlignment.c | 26 -- .../StructurePointerAlignment.c | 31 -- .../StructurePointerWithOffsetAlignment.c | 35 -- 33 files changed, 184 insertions(+), 1467 deletions(-) delete mode 100644 include/klee/Module/KType.h delete mode 100644 lib/Core/CXXTypeSystem/CXXTypeManager.h delete mode 100644 lib/Core/TypeManager.h delete mode 100644 lib/Module/KType.cpp delete mode 100644 test/Feature/types/ArrayAccess.c delete mode 100644 test/Feature/types/InnerStructAccess.c delete mode 100644 test/Feature/types/StructDereference.c delete mode 100644 test/Feature/types/SymbolicPointerMultipleResolve.c delete mode 100644 test/Feature/types/SymbolicPointerSimpleResolve.c delete mode 100644 test/Feature/types/UnionAccess.c delete mode 100644 test/Feature/types/effective-type/EffectiveTypeFirstRead.c delete mode 100644 test/Feature/types/effective-type/EffectiveTypeMalloc.c delete mode 100644 test/Feature/types/effective-type/EffectiveTypeMemset.c delete mode 100644 test/Feature/types/effective-type/EffectiveTypeRealloc.c delete mode 100644 test/Feature/types/effective-type/OperatorNew.cpp delete mode 100644 test/Feature/types/pointers-alignment/ArrayPointerAlignment.c delete mode 100644 test/Feature/types/pointers-alignment/DefaultPointerAlignment.c delete mode 100644 test/Feature/types/pointers-alignment/EffectiveTypePointerAlignment.c delete mode 100644 test/Feature/types/pointers-alignment/StructurePointerAlignment.c delete mode 100644 test/Feature/types/pointers-alignment/StructurePointerWithOffsetAlignment.c diff --git a/include/klee/Module/KType.h b/include/klee/Module/KType.h deleted file mode 100644 index 1b45b63215..0000000000 --- a/include/klee/Module/KType.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef KLEE_KTYPE_H -#define KLEE_KTYPE_H - -#include -#include -#include -#include - -namespace llvm { -class Type; -class raw_ostream; -} // namespace llvm - -namespace klee { -class Expr; -class TypeManager; - -template class ref; - -enum class TypeSystemKind { Default, Advanced }; -class KType { - friend TypeManager; - -protected: - /** - * Represents type of used TypeManager. Required - * for llvm RTTI. - */ - TypeSystemKind typeSystemKind; - - /** - * Wrapped type. - */ - llvm::Type *type; - - /** - * Owning type manager system. Note, that only it can - * create instances of KTypes. - */ - TypeManager *parent; - - /** - * Alignment in bytes for this type. - */ - size_t alignment = 1; - - /** - * Size of type. - */ - size_t typeStoreSize = 0; - - /** - * Innner types. Maps type to their offsets in current - * type. Should contain type itself and - * all types, that can be found in that object. - * For example, if object of type A contains object - * of type B, then all types in B can be accessed via A. - */ - std::unordered_map> innerTypes; - - KType(llvm::Type *, TypeManager *); - - /** - * Object cannot been created within class, defferent - * from TypeManager, as it is important to have only - * one instance for every llvm::Type. - */ - KType(const KType &) = delete; - KType &operator=(const KType &) = delete; - KType(KType &&) = delete; - KType &operator=(KType &&) = delete; - -public: - /** - * Method to check if 2 types are compatible. - */ - virtual bool isAccessableFrom(KType *accessingType) const; - - /** - * Handler for possible memory access. By default does nothing. - */ - virtual void handleMemoryAccess(KType *, ref, ref, bool isWrite); - - /** - * Returns the stored raw llvm type. - */ - llvm::Type *getRawType() const; - - /** - * Getter for the size. - */ - size_t getSize() const; - - /** - * Getter for the alignment. - */ - size_t getAlignment() const; - - /** - * Return alignment requirements for that object and - * it subobjects. If no such restrictions can be applied - * returns ref to null expression. - */ - virtual ref getContentRestrictions(ref) const; - - const std::unordered_map> &getInnerTypes() const; - - TypeSystemKind getTypeSystemKind() const; - - virtual void print(llvm::raw_ostream &) const; - - virtual ~KType() = default; -}; -} // namespace klee - -#endif diff --git a/lib/Core/AddressSpace.cpp b/lib/Core/AddressSpace.cpp index 85f7940834..8563721b96 100644 --- a/lib/Core/AddressSpace.cpp +++ b/lib/Core/AddressSpace.cpp @@ -15,7 +15,6 @@ #include "klee/Expr/ArrayExprVisitor.h" #include "klee/Expr/Expr.h" -#include "klee/Module/KType.h" #include "klee/Statistics/TimerStatIncrementer.h" #include "CoreStats.h" @@ -82,7 +81,7 @@ ObjectPair AddressSpace::findObject(const MemoryObject *mo) const { } RefObjectPair AddressSpace::lazyInitializeObject(const MemoryObject *mo) const { - return RefObjectPair(mo, new ObjectState(mo, mo->content, mo->type)); + return RefObjectPair(mo, new ObjectState(mo, mo->content)); } RefObjectPair @@ -112,7 +111,7 @@ ObjectState *AddressSpace::getWriteable(const MemoryObject *mo, /// -bool AddressSpace::resolveOne(ref address, KType *, +bool AddressSpace::resolveOne(ref address, ObjectPair &result) const { uint64_t baseConst = address->getConstantBase()->getZExtValue(); uint64_t addressConst = address->getConstantValue()->getZExtValue(); @@ -143,7 +142,7 @@ bool AddressSpace::resolveOne(ref address, KType *, bool AddressSpace::resolveOneIfUnique(ExecutionState &state, TimingSolver *solver, - ref address, KType *, + ref address, ObjectPair &result, bool &success) const { ref base = address->getBase(); ref uniqueAddress = base; @@ -181,17 +180,16 @@ class ResolvePredicate { bool skipGlobal; unsigned timestamp; ExecutionState *state; - KType *objectType; bool complete; public: explicit ResolvePredicate(ExecutionState &state, ref address, - KType *objectType, bool complete) + bool complete) : useTimestamps(UseTimestamps), skipNotSymbolicObjects(SkipNotSymbolicObjects), skipNotLazyInitialized(SkipNotLazyInitialized), skipLocal(SkipLocal), skipGlobal(SkipGlobal), timestamp(UINT_MAX), state(&state), - objectType(objectType), complete(complete) { + complete(complete) { ref base = address->getBase(); if (!isa(base)) { std::pair, ref> moBasePair; @@ -225,20 +223,19 @@ class ResolvePredicate { result = result && (!skipNotLazyInitialized || mo->isLazyInitialized); result = result && (!skipLocal || !mo->isLocal); result = result && (!skipGlobal || !mo->isGlobal); - result = result && os->isAccessableFrom(objectType); result = result && (!complete || os->wasWritten); return result; } }; bool AddressSpace::resolveOne(ExecutionState &state, TimingSolver *solver, - ref address, KType *objectType, - ObjectPair &result, bool &success, + ref address, ObjectPair &result, + bool &success, const std::atomic_bool &haltExecution) const { - ResolvePredicate predicate(state, address, objectType, complete); + ResolvePredicate predicate(state, address, complete); ref addressExpr = address->getValue(); if (ref CP = dyn_cast(address)) { - if (resolveOne(CP, objectType, result)) { + if (resolveOne(CP, result)) { success = true; return true; } @@ -253,7 +250,7 @@ bool AddressSpace::resolveOne(ExecutionState &state, TimingSolver *solver, state.queryMetaData)) return false; - if (resolveOne(addressCex, objectType, result)) { + if (resolveOne(addressCex, result)) { success = true; return true; } @@ -323,13 +320,12 @@ int AddressSpace::checkPointerInObject(ExecutionState &state, } bool AddressSpace::resolve(ExecutionState &state, TimingSolver *solver, - ref p, KType *objectType, - ResolutionList &rl, unsigned maxResolutions, - time::Span timeout) const { - ResolvePredicate predicate(state, p, objectType, complete); + ref p, ResolutionList &rl, + unsigned maxResolutions, time::Span timeout) const { + ResolvePredicate predicate(state, p, complete); if (ref CP = dyn_cast(p)) { ObjectPair res; - if (resolveOne(CP, objectType, res)) { + if (resolveOne(CP, res)) { rl.push_back(res); return false; } @@ -338,7 +334,7 @@ bool AddressSpace::resolve(ExecutionState &state, TimingSolver *solver, ObjectPair fastPathObjectID; bool fastPathSuccess; - if (!resolveOneIfUnique(state, solver, p, objectType, fastPathObjectID, + if (!resolveOneIfUnique(state, solver, p, fastPathObjectID, fastPathSuccess)) { return true; } diff --git a/lib/Core/AddressSpace.h b/lib/Core/AddressSpace.h index 6d92f6594f..520e1bd16d 100644 --- a/lib/Core/AddressSpace.h +++ b/lib/Core/AddressSpace.h @@ -21,7 +21,6 @@ namespace klee { class ExecutionState; class MemoryObject; class ObjectState; -class KType; class TimingSolver; template class ref; @@ -84,8 +83,7 @@ class AddressSpace { /// Resolve address to an ObjectPair in result. /// \return true iff an object was found. - bool resolveOne(ref address, KType *objectType, - ObjectPair &result) const; + bool resolveOne(ref address, ObjectPair &result) const; /// Resolve address to an ObjectPair in result. /// @@ -97,8 +95,7 @@ class AddressSpace { /// (when returning true). /// \return true iff an object was found at \a address. bool resolveOne(ExecutionState &state, TimingSolver *solver, - ref address, KType *objectType, - ObjectPair &result, bool &success, + ref address, ObjectPair &result, bool &success, const std::atomic_bool &haltExecution) const; /// @brief Tries to resolve the pointer in the concrete object @@ -111,8 +108,8 @@ class AddressSpace { /// @param success True iff object was found. /// @return false iff the resolution is incomplete (query timed out). bool resolveOneIfUnique(ExecutionState &state, TimingSolver *solver, - ref address, KType *objectType, - ObjectPair &result, bool &success) const; + ref address, ObjectPair &result, + bool &success) const; /// Resolve pointer `p` to a list of `ObjectPairs` it can point /// to. If `maxResolutions` is non-zero then no more than that many @@ -121,8 +118,7 @@ class AddressSpace { /// \return true iff the resolution is incomplete (`maxResolutions` /// is non-zero and it was reached, or a query timed out). bool resolve(ExecutionState &state, TimingSolver *solver, ref p, - KType *objectType, ResolutionList &rl, - unsigned maxResolutions = 0, + ResolutionList &rl, unsigned maxResolutions = 0, time::Span timeout = time::Span()) const; /***/ diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt index 9f654afc0f..62774aecff 100644 --- a/lib/Core/CMakeLists.txt +++ b/lib/Core/CMakeLists.txt @@ -13,7 +13,6 @@ add_library(kleeCore CodeLocation.cpp Context.cpp CoreStats.cpp - CXXTypeSystem/CXXTypeManager.cpp DistanceCalculator.cpp EventRecorder.cpp ExecutionState.cpp @@ -37,7 +36,6 @@ add_library(kleeCore TargetedExecutionManager.cpp TargetManager.cpp TimingSolver.cpp - TypeManager.cpp UserSearcher.cpp ) diff --git a/lib/Core/CXXTypeSystem/CXXTypeManager.h b/lib/Core/CXXTypeSystem/CXXTypeManager.h deleted file mode 100644 index 66a7625490..0000000000 --- a/lib/Core/CXXTypeSystem/CXXTypeManager.h +++ /dev/null @@ -1,263 +0,0 @@ -#ifndef KLEE_CXXTYPEMANAGER_H -#define KLEE_CXXTYPEMANAGER_H - -#include "../TypeManager.h" - -#include "klee/Module/KType.h" - -#include -#include -#include -#include - -namespace llvm { -class Type; -class Function; -} // namespace llvm - -namespace klee { -class Expr; -class KModule; -template class ref; - -namespace cxxtypes { - -enum CXXTypeKind { - DEFAULT, - COMPOSITE, - STRUCT, - INTEGER, - FP, - ARRAY, - POINTER, - FUNCTION -}; - -class KCXXCompositeType; -class KCXXStructType; -class KCXXIntegerType; -class KCXXFloatingPointType; -class KCXXArrayType; -class KCXXPointerType; -class KCXXType; -class KCXXFunctionType; -} // namespace cxxtypes - -class CXXTypeManager final : public TypeManager { -protected: - virtual void onFinishInitModule() override; - -public: - CXXTypeManager(KModule *); - - virtual KType *getWrappedType(llvm::Type *) override; - virtual KType *handleAlloc(ref) override; - virtual KType *handleRealloc(KType *, ref) override; -}; - -/** - * Classes for cpp type system. Rules described below - * relies on Strict-Aliasing-Rule. See more on this page: - * https://en.cppreference.com/w/cpp/language/reinterpret_cast - */ -namespace cxxtypes { - -class KCXXType : public KType { - friend CXXTypeManager; - friend KCXXStructType; - -private: - static bool isAccessingFromChar(KCXXType *accessingType); - -protected: - /** - * Field for llvm RTTI system. - */ - CXXTypeKind typeKind; - - KCXXType(llvm::Type *, TypeManager *); - -public: - /** - * Checks the first access to this type from specified. - * Using isAccessingFromChar and then cast parameter - * to KCXXType. Method is declared as final because it - * is an 'edge' between LLVM and CXX type systems. - */ - virtual bool isAccessableFrom(KType *) const final override; - virtual bool isAccessableFrom(KCXXType *) const; - - virtual ref getContentRestrictions(ref) const override; - virtual ref getPointersRestrictions(ref) const; - - CXXTypeKind getTypeKind() const; - - static bool classof(const KType *); -}; - -/** - * Composite type represents multuple kinds of types in one memory - * location. E.g., this type can apper if we use placement new - * on array. - */ -class KCXXCompositeType : public KCXXType { - friend CXXTypeManager; - -private: - bool containsSymbolic = false; - std::unordered_map nonTypedMemorySegments; - - std::map> typesLocations; - std::unordered_set insertedTypes; - -protected: - KCXXCompositeType(KType *, TypeManager *, ref); - -public: - virtual ref getPointersRestrictions(ref) const override; - virtual void handleMemoryAccess(KType *, ref, ref size, - bool isWrite) override; - virtual bool isAccessableFrom(KCXXType *) const override; - - static bool classof(const KType *); -}; - -/** - * Struct type can be accessed from all other types, that - * it might contain inside. Holds additional information - * about types inside. - */ -class KCXXStructType : public KCXXType { - friend CXXTypeManager; - -private: - bool isUnion = false; - -protected: - KCXXStructType(llvm::Type *, TypeManager *); - -public: - virtual ref getPointersRestrictions(ref) const override; - virtual bool isAccessableFrom(KCXXType *) const override; - - static bool classof(const KType *); -}; - -/** - * Function type can be accessed obly from another - * function type. - */ -class KCXXFunctionType : public KCXXType { - friend CXXTypeManager; - -private: - KCXXType *returnType; - std::vector arguments; - - bool innerIsAccessableFrom(KCXXType *) const; - bool innerIsAccessableFrom(KCXXFunctionType *) const; - -protected: - KCXXFunctionType(llvm::Type *, TypeManager *); - -public: - virtual bool isAccessableFrom(KCXXType *) const override; - - static bool classof(const KType *); -}; - -/** - * Integer type can be accessed from another integer type - * of the same type. - */ -class KCXXIntegerType : public KCXXType { - friend CXXTypeManager; - -private: - bool innerIsAccessableFrom(KCXXType *) const; - bool innerIsAccessableFrom(KCXXIntegerType *) const; - -protected: - KCXXIntegerType(llvm::Type *, TypeManager *); - -public: - virtual bool isAccessableFrom(KCXXType *) const override; - - static bool classof(const KType *); -}; - -/** - * Floating point type can be access from another floating - * point type of the same type. - */ -class KCXXFloatingPointType : public KCXXType { - friend CXXTypeManager; - -private: - bool innerIsAccessableFrom(KCXXType *) const; - bool innerIsAccessableFrom(KCXXFloatingPointType *) const; - -protected: - KCXXFloatingPointType(llvm::Type *, TypeManager *); - -public: - virtual bool isAccessableFrom(KCXXType *) const override; - - static bool classof(const KType *); -}; - -/** - * Array type can be accessed from another array type of the - * same size or from type of its elements. Types of array elements - * must be the same. - */ -class KCXXArrayType : public KCXXType { - friend CXXTypeManager; - -private: - KCXXType *elementType; - size_t arrayElementsCount; - - bool innerIsAccessableFrom(KCXXType *) const; - bool innerIsAccessableFrom(KCXXArrayType *) const; - -protected: - KCXXArrayType(llvm::Type *, TypeManager *); - -public: - virtual ref getPointersRestrictions(ref) const override; - virtual bool isAccessableFrom(KCXXType *) const override; - - static bool classof(const KType *); -}; - -/** - * Pointer Type can be accessed from another pointer type. - * Pointer elements type must be the same. - */ -class KCXXPointerType : public KCXXType { - friend CXXTypeManager; - -private: - KCXXType *elementType; - bool innerIsAccessableFrom(KCXXType *) const; - bool innerIsAccessableFrom(KCXXPointerType *) const; - -protected: - KCXXPointerType(llvm::Type *, TypeManager *); - -public: - virtual ref getPointersRestrictions(ref) const override; - virtual bool isAccessableFrom(KCXXType *) const override; - - bool isPointerToChar() const; - bool isPointerToFunction() const; - - static bool classof(const KType *); -}; - -} /*namespace cxxtypes*/ - -} /*namespace klee*/ - -#endif /*KLEE_CXXTYPEMANAGER_H*/ diff --git a/lib/Core/ExecutionState.cpp b/lib/Core/ExecutionState.cpp index 2e22f240ff..6c56132a82 100644 --- a/lib/Core/ExecutionState.cpp +++ b/lib/Core/ExecutionState.cpp @@ -247,9 +247,8 @@ void ExecutionState::popFrame() { stack.popFrame(); } -void ExecutionState::addSymbolic(const MemoryObject *mo, const Array *array, - KType *type) { - symbolics.push_back({mo, array, type}); +void ExecutionState::addSymbolic(const MemoryObject *mo, const Array *array) { + symbolics.push_back({mo, array}); } ref diff --git a/lib/Core/ExecutionState.h b/lib/Core/ExecutionState.h index 54728a5e25..dc0e480171 100644 --- a/lib/Core/ExecutionState.h +++ b/lib/Core/ExecutionState.h @@ -248,15 +248,13 @@ struct CleanupPhaseUnwindingInformation : public UnwindingInformation { struct Symbolic { ref memoryObject; const Array *array; - KType *type; - Symbolic(ref mo, const Array *a, KType *t) - : memoryObject(std::move(mo)), array(a), type(t) {} + Symbolic(ref mo, const Array *a) + : memoryObject(std::move(mo)), array(a) {} Symbolic(const Symbolic &other) = default; Symbolic &operator=(const Symbolic &other) = default; friend bool operator==(const Symbolic &lhs, const Symbolic &rhs) { - return lhs.memoryObject == rhs.memoryObject && lhs.array == rhs.array && - lhs.type == rhs.type; + return lhs.memoryObject == rhs.memoryObject && lhs.array == rhs.array; } }; @@ -456,8 +454,7 @@ class ExecutionState { void pushFrame(KInstIterator caller, KFunction *kf); void popFrame(); - void addSymbolic(const MemoryObject *mo, const Array *array, - KType *type = nullptr); + void addSymbolic(const MemoryObject *mo, const Array *array); ref findMemoryObject(const Array *array) const; diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 2c9f3ad292..45008ab6e3 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -10,7 +10,6 @@ #include "Executor.h" #include "AddressSpace.h" -#include "CXXTypeSystem/CXXTypeManager.h" #include "ConstructStorage.h" #include "CoreStats.h" #include "DistanceCalculator.h" @@ -30,7 +29,6 @@ #include "TargetManager.h" #include "TargetedExecutionManager.h" #include "TimingSolver.h" -#include "TypeManager.h" #include "UserSearcher.h" #include "klee/ADT/Bits.h" #include "klee/ADT/SparseStorage.h" @@ -58,7 +56,6 @@ #include "klee/Module/KCallable.h" #include "klee/Module/KInstruction.h" #include "klee/Module/KModule.h" -#include "klee/Module/KType.h" #include "klee/Module/SarifReport.h" #include "klee/Solver/Common.h" #include "klee/Solver/Solver.h" @@ -143,23 +140,11 @@ cl::OptionCategory TestGenCat("Test generation options", cl::OptionCategory LazyInitCat("Lazy initialization option", "These options configure lazy initialization."); -cl::opt UseAdvancedTypeSystem( - "use-advanced-type-system", - cl::desc("Use advanced information about type system from " - "language (default=false)"), - cl::init(false), cl::cat(ExecCat)); - cl::opt MergedPointerDereference( "use-merged-pointer-dereference", cl::init(false), cl::desc("Enable merged pointer dereference (default=false)"), cl::cat(ExecCat)); -cl::opt UseTypeBasedAliasAnalysis( - "use-tbaa", - cl::desc("Turns on restrictions based on types compatibility for " - "symbolic pointers (default=false)"), - cl::init(false), cl::cat(ExecCat)); - cl::opt AlignSymbolicPointers("align-symbolic-pointers", cl::desc("Makes symbolic pointers aligned according" @@ -701,8 +686,6 @@ llvm::Module *Executor::setModule( specialFunctionHandler->bind(); - initializeTypeManager(); - if (StatsTracker::useStatistics() || userSearcherRequiresMD2U()) { statsTracker = new StatsTracker( *this, interpreterHandler->getOutputFilename("assembly.ll"), @@ -722,7 +705,6 @@ void Executor::setFunctionsByModule(FunctionsByModule &&fnsByModule) { } Executor::~Executor() { - delete typeSystemManager; delete externalDispatcher; delete specialFunctionHandler; delete statsTracker; @@ -818,24 +800,22 @@ void Executor::initializeGlobalObject(ExecutionState &state, ObjectState *os, } ObjectPair Executor::addExternalObjectAsNonStatic(ExecutionState &state, - KType *type, unsigned size, + unsigned size, bool isReadOnly) { - auto mo = - allocate(state, Expr::createPointer(size), false, true, nullptr, 8, type); + auto mo = allocate(state, Expr::createPointer(size), false, true, nullptr, 8); mo->isFixed = true; - auto os = bindObjectInState(state, mo, type, false); + auto os = bindObjectInState(state, mo, false); os->setReadOnly(isReadOnly); return ObjectPair{mo, os}; } ObjectPair Executor::addExternalObject(ExecutionState &state, const void *addr, - KType *type, unsigned size, - bool isReadOnly) { + unsigned size, bool isReadOnly) { auto mo = memory->allocateFixed(reinterpret_cast(addr), size, - nullptr, type); - ObjectState *os = bindObjectInState(state, mo, type, false); + nullptr); + ObjectState *os = bindObjectInState(state, mo, false); ref seg = Expr::createPointer(reinterpret_cast(addr)); for (unsigned i = 0; i < size; i++) { @@ -869,28 +849,20 @@ static const std::size_t kCTypeMemOffset = 128; template decltype(auto) Executor::addCTypeFixedObject(ExecutionState &state, - int addressSpaceNum, Module &m, F objectProvider) { using underlying_t = decltype(**objectProvider()); static_assert(std::is_integral_v>, "ctype structure expected to contain integral variables"); - // Obtain types for required object - llvm::Type *type = - llvm::IntegerType::get(m.getContext(), sizeof(underlying_t) * CHAR_BIT); - llvm::Type *pointerType = llvm::PointerType::get(type, addressSpaceNum); - auto ctypeObj = addExternalObject(state, const_cast(reinterpret_cast( *objectProvider() - kCTypeMemOffset)), - typeSystemManager->getWrappedType(type), kCTypeMemSize * sizeof(underlying_t), true); auto ctypePointerObj = addExternalObject( - state, objectProvider(), typeSystemManager->getWrappedType(pointerType), - Context::get().getPointerWidthInBytes(), true); + state, objectProvider(), Context::get().getPointerWidthInBytes(), true); state.addressSpace .getWriteable(ctypePointerObj.first, ctypePointerObj.second) ->write(0, @@ -904,24 +876,17 @@ decltype(auto) Executor::addCTypeFixedObject(ExecutionState &state, template decltype(auto) Executor::addCTypeModelledObject(ExecutionState &state, - int addressSpaceNum, Module &m, F objectProvider) { using underlying_t = decltype(**objectProvider()); static_assert(std::is_integral_v>, "ctype structure expected to contain integral variables"); - // Obtain types for required object - llvm::Type *type = - llvm::IntegerType::get(m.getContext(), sizeof(underlying_t) * CHAR_BIT); - llvm::Type *pointerType = llvm::PointerType::get(type, addressSpaceNum); // Allocate memory auto ctypeObj = addExternalObjectAsNonStatic( - state, typeSystemManager->getWrappedType(type), - kCTypeMemSize * sizeof(underlying_t), true); + state, kCTypeMemSize * sizeof(underlying_t), true); auto ctypePointerObj = addExternalObjectAsNonStatic( - state, typeSystemManager->getWrappedType(pointerType), - Context::get().getPointerWidthInBytes(), true); + state, Context::get().getPointerWidthInBytes(), true); // Write address of memory into pointer state.addressSpace @@ -948,7 +913,6 @@ decltype(auto) Executor::addCTypeModelledObject(ExecutionState &state, void Executor::allocateGlobalObjects(ExecutionState &state) { Module *m = kmodule->module.get(); - unsigned int addressSpaceNum = kmodule->targetData->getAllocaAddrSpace(); if (m->getModuleInlineAsm() != "") klee_warning("executable has module level assembly (ignoring)"); @@ -976,7 +940,7 @@ void Executor::allocateGlobalObjects(ExecutionState &state) { kf, kf->getSourceFilepath(), kf->getLine(), std::nullopt); auto mo = allocate(state, Expr::createPointer(8), false, true, - fCodeLocation, 8, typeSystemManager->getUnknownType()); + fCodeLocation, 8); auto baseExpr = cast(mo->getBaseExpr()); addr = ConstantPointerExpr::create(baseExpr, baseExpr); legalFunctions.emplace(baseExpr->getZExtValue(), &f); @@ -987,24 +951,17 @@ void Executor::allocateGlobalObjects(ExecutionState &state) { #ifndef WINDOWS - llvm::Type *pointerErrnoAddr = llvm::PointerType::get( - llvm::IntegerType::get(m->getContext(), sizeof(*errno_addr) * CHAR_BIT), - addressSpaceNum); const MemoryObject *errnoObj = nullptr; if (Context::get().getPointerWidth() == 32) { - errnoObj = addExternalObjectAsNonStatic( - state, typeSystemManager->getWrappedType(pointerErrnoAddr), - sizeof(*errno_addr), false) - .first; + errnoObj = + addExternalObjectAsNonStatic(state, sizeof(*errno_addr), false).first; errno_addr = reinterpret_cast( cast(errnoObj->getBaseExpr())->getZExtValue()); } else { errno_addr = getErrnoLocation(); errnoObj = - addExternalObject(state, (void *)errno_addr, - typeSystemManager->getWrappedType(pointerErrnoAddr), - sizeof *errno_addr, false) + addExternalObject(state, (void *)errno_addr, sizeof *errno_addr, false) .first; } @@ -1028,19 +985,13 @@ void Executor::allocateGlobalObjects(ExecutionState &state) { // of actual ctype* objects in memory. // Hence, we need to model then in address space. if (Context::get().getPointerWidth() == 32) { - c_type_b_loc_addr = - addCTypeModelledObject(state, addressSpaceNum, *m, __ctype_b_loc); - c_type_tolower_addr = - addCTypeModelledObject(state, addressSpaceNum, *m, __ctype_tolower_loc); - c_type_toupper_addr = - addCTypeModelledObject(state, addressSpaceNum, *m, __ctype_toupper_loc); + c_type_b_loc_addr = addCTypeModelledObject(state, __ctype_b_loc); + c_type_tolower_addr = addCTypeModelledObject(state, __ctype_tolower_loc); + c_type_toupper_addr = addCTypeModelledObject(state, __ctype_toupper_loc); } else { - c_type_b_loc_addr = - addCTypeFixedObject(state, addressSpaceNum, *m, __ctype_b_loc); - c_type_tolower_addr = - addCTypeFixedObject(state, addressSpaceNum, *m, __ctype_tolower_loc); - c_type_toupper_addr = - addCTypeFixedObject(state, addressSpaceNum, *m, __ctype_toupper_loc); + c_type_b_loc_addr = addCTypeFixedObject(state, __ctype_b_loc); + c_type_tolower_addr = addCTypeFixedObject(state, __ctype_tolower_loc); + c_type_toupper_addr = addCTypeFixedObject(state, __ctype_toupper_loc); } #endif #endif @@ -1100,8 +1051,7 @@ void Executor::allocateGlobalObjects(ExecutionState &state) { MemoryObject *mo = allocate(state, size, /*isLocal=*/false, /*isGlobal=*/true, /*allocSite=*/vCodeLocation, - /*alignment=*/globalObjectAlignment, - typeSystemManager->getWrappedType(ty)); + /*alignment=*/globalObjectAlignment); if (!mo) klee_error("out of memory"); @@ -1156,9 +1106,7 @@ void Executor::initializeGlobalObjects(ExecutionState &state) { for (const GlobalVariable &v : m->globals()) { MemoryObject *mo = globalObjects.find(&v)->second; - ObjectState *os = bindObjectInState( - state, mo, typeSystemManager->getWrappedType(v.getType()), false, - nullptr); + ObjectState *os = bindObjectInState(state, mo, false, nullptr); if (v.isDeclaration()) { if (isa(mo->getSizeExpr())) { @@ -1183,8 +1131,7 @@ void Executor::initializeGlobalObjects(ExecutionState &state) { } } else { executeMakeSymbolic( - state, mo, typeSystemManager->getWrappedType(v.getType()), - SourceBuilder::irreproducible("unsizedGlobal"), false); + state, mo, SourceBuilder::irreproducible("unsizedGlobal"), false); } } else if (v.hasInitializer()) { initializeGlobalObject(state, os, v.getInitializer(), 0); @@ -2066,11 +2013,9 @@ MemoryObject *Executor::serializeLandingpad(ExecutionState &state, } } - MemoryObject *mo = - allocate(state, Expr::createPointer(serialized.size()), true, false, - nullptr, 1, typeSystemManager->getUnknownType()); - ObjectState *os = - bindObjectInState(state, mo, typeSystemManager->getUnknownType(), false); + MemoryObject *mo = allocate(state, Expr::createPointer(serialized.size()), + true, false, nullptr, 1); + ObjectState *os = bindObjectInState(state, mo, false); for (unsigned i = 0; i < serialized.size(); i++) { ref sec = ConstantExpr::create(serialized[i], Expr::Int8); if (pointerMask.at(i)) { @@ -2462,8 +2407,7 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, // size. This happens to work for x86-32 and x86-64, however. Expr::Width WordSize = Context::get().getPointerWidth(); if (WordSize == Expr::Int32) { - executeMemoryOperation(state, true, typeSystemManager->getUnknownType(), - makePointer(arguments[0]), + executeMemoryOperation(state, true, makePointer(arguments[0]), PointerExpr::create(sf.varargs->getBaseExpr(), sf.varargs->getBaseExpr()), 0); @@ -2473,21 +2417,20 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, // x86-64 has quite complicated calling convention. However, // instead of implementing it, we can do a simple hack: just // make a function believe that all varargs are on stack. - executeMemoryOperation(state, true, typeSystemManager->getUnknownType(), - makePointer(arguments[0]), + executeMemoryOperation(state, true, makePointer(arguments[0]), ConstantExpr::create(48, 32), 0); // gp_offset - executeMemoryOperation(state, true, typeSystemManager->getUnknownType(), + executeMemoryOperation(state, true, AddExpr::create(makePointer(arguments[0]), ConstantExpr::create(4, 64)), ConstantExpr::create(304, 32), 0); // fp_offset - executeMemoryOperation(state, true, typeSystemManager->getUnknownType(), + executeMemoryOperation(state, true, AddExpr::create(makePointer(arguments[0]), ConstantExpr::create(8, 64)), PointerExpr::create(sf.varargs->getBaseExpr(), sf.varargs->getBaseExpr()), 0); // overflow_arg_area - executeMemoryOperation(state, true, typeSystemManager->getUnknownType(), + executeMemoryOperation(state, true, AddExpr::create(makePointer(arguments[0]), ConstantExpr::create(16, 64)), ConstantExpr::create(0, 64), 0); // reg_save_area @@ -2626,8 +2569,7 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, StackFrame &sf = state.stack.valueStack().back(); MemoryObject *mo = sf.varargs = memory->allocate( Expr::createPointer(size), true, false, false, locationOf(state), - (requires16ByteAlignment ? 16 : 8), - typeSystemManager->getUnknownType()); + (requires16ByteAlignment ? 16 : 8)); if (!mo && size) { terminateStateOnExecError(state, "out of memory (varargs)"); return; @@ -2642,11 +2584,9 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, 0, "While allocating varargs: malloc did not align to 16 bytes."); } - ObjectState *os = bindObjectInState( - state, mo, typeSystemManager->getUnknownType(), true); + ObjectState *os = bindObjectInState(state, mo, true); llvm::Function::arg_iterator ati = std::next(f->arg_begin(), funcArgs); - llvm::Type *argType = (ati == f->arg_end()) ? nullptr : ati->getType(); for (unsigned k = funcArgs; k < callingArgs; k++) { if (!cb.isByValArgument(k)) { @@ -2657,8 +2597,7 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, assert(CP); // byval argument needs to be a concrete pointer ObjectPair idObject; - state.addressSpace.resolveOne( - CP, typeSystemManager->getWrappedType(argType), idObject); + state.addressSpace.resolveOne(CP, idObject); const ObjectState *osarg = idObject.second; assert(osarg); ref sizeExpr = @@ -3562,28 +3501,19 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { count = Expr::createZExtToPointerWidth(count); size = MulExpr::create(size, count); } - executeAlloc(state, size, true, ki, - typeSystemManager->getWrappedType(ai->getType())); + executeAlloc(state, size, true, ki); break; } case Instruction::Load: { ref base = eval(ki, 0, state).value; - executeMemoryOperation( - state, false, - typeSystemManager->getWrappedType( - cast(ki->inst())->getPointerOperandType()), - makePointer(base), 0, ki); + executeMemoryOperation(state, false, makePointer(base), 0, ki); break; } case Instruction::Store: { ref base = eval(ki, 1, state).value; ref value = eval(ki, 0, state).value; - executeMemoryOperation( - state, true, - typeSystemManager->getWrappedType( - cast(ki->inst())->getPointerOperandType()), - makePointer(base), value, ki); + executeMemoryOperation(state, true, makePointer(base), value, ki); break; } @@ -4818,15 +4748,6 @@ void Executor::run(ExecutionState *initialState) { haltExecution = HaltExecution::NotHalt; } -void Executor::initializeTypeManager() { - if (UseAdvancedTypeSystem) { - typeSystemManager = new CXXTypeManager(kmodule.get()); - } else { - typeSystemManager = new TypeManager(kmodule.get()); - } - typeSystemManager->initModule(); -} - static bool shouldWriteTest(const ExecutionState &state, bool isError = false) { state.updateCoveredNew(); bool coveredNew = isError ? state.isCoveredNewError() : state.isCoveredNew(); @@ -5388,15 +5309,10 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, // Update external errno state with local state value ObjectPair result; - llvm::Type *pointerErrnoAddr = llvm::PointerType::get( - llvm::IntegerType::get(kmodule->module->getContext(), - sizeof(*errno_addr) * CHAR_BIT), - kmodule->targetData->getAllocaAddrSpace()); - bool resolved = state.addressSpace.resolveOne( ConstantPointerExpr::create(Expr::createPointer((uint64_t)errno_addr), Expr::createPointer((uint64_t)errno_addr)), - typeSystemManager->getWrappedType(pointerErrnoAddr), result); + result); if (!resolved) klee_error("Could not resolve memory object for errno"); ref errValueExpr = result.second->read(0, sizeof(*errno_addr) * 8); @@ -5529,11 +5445,9 @@ ref Executor::makeMockValue(const std::string &name, Expr::Width width) { } ObjectState *Executor::bindObjectInState(ExecutionState &state, - const MemoryObject *mo, - KType *dynamicType, bool isLocal, + const MemoryObject *mo, bool isLocal, const Array *array) { - ObjectState *os = array ? new ObjectState(mo, array, dynamicType) - : new ObjectState(mo, dynamicType); + ObjectState *os = array ? new ObjectState(mo, array) : new ObjectState(mo); state.addressSpace.bindObject(mo, os); // Its possible that multiple bindings of the same mo in the state @@ -5547,7 +5461,7 @@ ObjectState *Executor::bindObjectInState(ExecutionState &state, } void Executor::executeAlloc(ExecutionState &state, ref size, bool isLocal, - KInstruction *target, KType *type, bool zeroMemory, + KInstruction *target, bool zeroMemory, const ObjectState *reallocFrom, size_t allocationAlignment, bool checkOutOfMemory) { static unsigned allocations = 0; @@ -5556,7 +5470,7 @@ void Executor::executeAlloc(ExecutionState &state, ref size, bool isLocal, } if (!isa(size) && !UseSymbolicSizeAllocation) { - concretizeSize(state, size, isLocal, target, type, zeroMemory, reallocFrom, + concretizeSize(state, size, isLocal, target, zeroMemory, reallocFrom, allocationAlignment, checkOutOfMemory); return; } @@ -5589,7 +5503,7 @@ void Executor::executeAlloc(ExecutionState &state, ref size, bool isLocal, MemoryObject *mo = allocate(state, size, isLocal, /*isGlobal=*/false, locationOf(state), - allocationAlignment, type, conditionExpr); + allocationAlignment, conditionExpr); if (!mo) { bindLocal( target, state, @@ -5603,7 +5517,7 @@ void Executor::executeAlloc(ExecutionState &state, ref size, bool isLocal, source = SourceBuilder::uninitialized(allocations++, target); } auto array = makeArray(size, source); - ObjectState *os = bindObjectInState(state, mo, type, isLocal, array); + ObjectState *os = bindObjectInState(state, mo, isLocal, array); ref address = mo->getBaseExpr(); @@ -5646,8 +5560,7 @@ void Executor::executeFree(ExecutionState &state, ref address, } if (zeroPointer.second) { // address != 0 ExactResolutionList rl; - if (!resolveExact(*zeroPointer.second, address, - typeSystemManager->getUnknownType(), rl, "free") && + if (!resolveExact(*zeroPointer.second, address, rl, "free") && guidanceKind == GuidanceKind::ErrorGuidance) { terminateStateOnTargetError(*zeroPointer.second, ReachWithError::DoubleFree); @@ -5685,7 +5598,7 @@ void Executor::executeFree(ExecutionState &state, ref address, } bool Executor::resolveExact(ExecutionState &estate, ref address, - KType *type, ExactResolutionList &results, + ExactResolutionList &results, const std::string &name) { ref pointer = PointerExpr::create(address->getValue(), address->getValue()); @@ -5734,9 +5647,8 @@ bool Executor::resolveExact(ExecutionState &estate, ref address, /* We do not need this variable here, just a placeholder for resolve */ [[maybe_unused]] bool success = resolveMemoryObjects( - state, pointer, type, state.prevPC, 0, rl, mayBeOutOfBound, - hasLazyInitialized, incomplete, - LazyInitialization == LazyInitializationPolicy::Only); + state, pointer, state.prevPC, 0, rl, mayBeOutOfBound, hasLazyInitialized, + incomplete, LazyInitialization == LazyInitializationPolicy::Only); assert(success); ExecutionState *unbound = &state; @@ -5774,7 +5686,7 @@ bool Executor::resolveExact(ExecutionState &estate, ref address, } void Executor::concretizeSize(ExecutionState &state, ref size, - bool isLocal, KInstruction *target, KType *type, + bool isLocal, KInstruction *target, bool zeroMemory, const ObjectState *reallocFrom, size_t allocationAlignment, bool checkOutOfMemory) { @@ -5829,7 +5741,7 @@ void Executor::concretizeSize(ExecutionState &state, ref size, assert(success && "FIXME: Unhandled solver failure"); (void)success; if (res) { - executeAlloc(*fixedSize.second, tmp, isLocal, target, type, zeroMemory, + executeAlloc(*fixedSize.second, tmp, isLocal, target, zeroMemory, reallocFrom); } else { // See if a *really* big value is possible. If so assume @@ -5862,7 +5774,7 @@ void Executor::concretizeSize(ExecutionState &state, ref size, } if (fixedSize.first) // can be zero when fork fails - executeAlloc(*fixedSize.first, example, isLocal, target, type, zeroMemory, + executeAlloc(*fixedSize.first, example, isLocal, target, zeroMemory, reallocFrom, allocationAlignment, checkOutOfMemory); } @@ -5909,13 +5821,11 @@ bool Executor::computeSizes( return success; } -MemoryObject *Executor::allocate(ExecutionState &state, ref size, - bool isLocal, bool isGlobal, - ref allocSite, - size_t allocationAlignment, KType *type, - ref conditionExpr, - ref lazyInitializationSource, - unsigned timestamp) { +MemoryObject * +Executor::allocate(ExecutionState &state, ref size, bool isLocal, + bool isGlobal, ref allocSite, + size_t allocationAlignment, ref conditionExpr, + ref lazyInitializationSource, unsigned timestamp) { size = ZExtExpr::create(size, Context::get().getPointerWidth()); /* Try to find existing solution. */ @@ -5926,9 +5836,8 @@ MemoryObject *Executor::allocate(ExecutionState &state, ref size, /* Constant solution exists. Just return it. */ if (arrayConstantSize && lazyInitializationSource.isNull()) { - MemoryObject *mo = - memory->allocate(arrayConstantSize, isLocal, isGlobal, false, allocSite, - allocationAlignment, type); + MemoryObject *mo = memory->allocate(arrayConstantSize, isLocal, isGlobal, + false, allocSite, allocationAlignment); if (mo && state.isGEPExpr(mo->getBaseExpr())) { state.gepExprBases.erase(mo->getBaseExpr()); } @@ -6003,8 +5912,7 @@ MemoryObject *Executor::allocate(ExecutionState &state, ref size, /* Allocate corresponding memory object. */ MemoryObject *mo = memory->allocate( size, isLocal, isGlobal, !lazyInitializationSource.isNull(), allocSite, - allocationAlignment, type, conditionExpr, addressExpr, timestamp, - contentArray); + allocationAlignment, conditionExpr, addressExpr, timestamp, contentArray); if (!mo) { return nullptr; @@ -6018,28 +5926,25 @@ MemoryObject *Executor::allocate(ExecutionState &state, ref size, state.constraints.addSymcrete(sizeSymcrete); state.constraints.addSymcrete(addressSymcrete); if (lazyInitializationSource) { - state.addSymbolic(mo, contentArray, type); + state.addSymbolic(mo, contentArray); } return mo; } bool Executor::resolveMemoryObjects( - ExecutionState &state, ref address, KType *targetType, - KInstruction *target, unsigned bytes, - ObjectResolutionList &mayBeResolvedMemoryObjects, bool &mayBeOutOfBound, - bool &mayLazyInitialize, bool &incomplete, bool onlyLazyInitialize) { + ExecutionState &state, ref address, KInstruction *target, + unsigned bytes, ObjectResolutionList &mayBeResolvedMemoryObjects, + bool &mayBeOutOfBound, bool &mayLazyInitialize, bool &incomplete, + bool onlyLazyInitialize) { mayLazyInitialize = false; mayBeOutOfBound = true; incomplete = false; ref base = address->getBase(); unsigned size = bytes; - KType *baseTargetType = targetType; if (state.isGEPExpr(base)) { size = kmodule->targetData->getTypeStoreSize(state.gepExprBases[base]); - baseTargetType = typeSystemManager->getWrappedType(llvm::PointerType::get( - state.gepExprBases[base], kmodule->targetData->getAllocaAddrSpace())); } base = Simplificator::simplifyExpr(state.constraints.cs(), base).simplified; @@ -6093,9 +5998,8 @@ bool Executor::resolveMemoryObjects( ResolutionList rl; solver->setTimeout(coreSolverTimeout); - incomplete = - state.addressSpace.resolve(state, solver.get(), basePointer, - targetType, rl, 0, coreSolverTimeout); + incomplete = state.addressSpace.resolve(state, solver.get(), basePointer, + rl, 0, coreSolverTimeout); solver->setTimeout(time::Span()); for (ResolutionList::iterator i = rl.begin(), ie = rl.end(); i != ie; @@ -6128,8 +6032,8 @@ bool Executor::resolveMemoryObjects( auto sizeExpr = Expr::createTempRead(lazyInstantiationSize, Context::get().getPointerWidth()); ref idLazyInitialization = lazyInitializeObject( - state, basePointer, target, baseTargetType, minObjectSize, sizeExpr, - false, checkOutOfBounds, UseSymbolicSizeLazyInit); + state, basePointer, target, minObjectSize, sizeExpr, false, + checkOutOfBounds, UseSymbolicSizeLazyInit); RefObjectPair op = state.addressSpace.findOrLazyInitializeObject( idLazyInitialization.get()); state.addressSpace.bindObject(op.first, op.second.get()); @@ -6342,8 +6246,8 @@ void Executor::collectReads(ExecutionState &state, ref address, } void Executor::executeMemoryOperation( - ExecutionState &estate, bool isWrite, KType *targetType, - ref address, ref value /* undef if read */, + ExecutionState &estate, bool isWrite, ref address, + ref value /* undef if read */, KInstruction *target /* undef if write */) { KInstruction *ki = estate.prevPC; if (isWrite && isa(ki->inst())) { @@ -6370,13 +6274,6 @@ void Executor::executeMemoryOperation( ref base = address->getBase(); ref basePointer = PointerExpr::create(base, base); ref zeroPointer = PointerExpr::create(Expr::createPointer(0)); - unsigned size = bytes; - KType *baseTargetType = targetType; - - if (estate.isGEPExpr(base)) { - baseTargetType = typeSystemManager->getWrappedType(llvm::PointerType::get( - estate.gepExprBases[base], kmodule->targetData->getAllocaAddrSpace())); - } if (SimplifySymIndices) { if (!isa(base)) { @@ -6415,12 +6312,11 @@ void Executor::executeMemoryOperation( ObjectPair idFastOp; solver->setTimeout(coreSolverTimeout); - if (!state->addressSpace.resolveOne(*state, solver.get(), address, - targetType, idFastOp, success, - haltExecution)) { + if (!state->addressSpace.resolveOne(*state, solver.get(), address, idFastOp, + success, haltExecution)) { address = toConstantPointer(*state, address, "resolveOne failure"); success = state->addressSpace.resolveOne( - cast(address), targetType, idFastOp); + cast(address), idFastOp); } solver->setTimeout(time::Span()); @@ -6477,9 +6373,6 @@ void Executor::executeMemoryOperation( ObjectState *wos = state->addressSpace.getWriteable(mo, os); maxNewWriteableOSSize = std::max(maxNewWriteableOSSize, wos->getSparseStorageEntries()); - wos->getDynamicType()->handleMemoryAccess( - targetType, offset, - ConstantExpr::alloc(size, Context::get().getPointerWidth()), true); if (wos->readOnly) { terminateStateOnProgramError( *state, @@ -6514,9 +6407,8 @@ void Executor::executeMemoryOperation( ObjectPair idFastOp; solver->setTimeout(coreSolverTimeout); - state->addressSpace.resolveOne(*state, solver.get(), basePointer, - baseTargetType, idFastOp, success, - haltExecution); + state->addressSpace.resolveOne(*state, solver.get(), basePointer, idFastOp, + success, haltExecution); solver->setTimeout(time::Span()); if (!success) { @@ -6531,9 +6423,9 @@ void Executor::executeMemoryOperation( ObjectResolutionList mayBeResolvedMemoryObjects; if (!resolveMemoryObjects( - *state, address, targetType, target, bytes, - mayBeResolvedMemoryObjects, mayBeOutOfBound, hasLazyInitialized, - incomplete, LazyInitialization == LazyInitializationPolicy::Only)) { + *state, address, target, bytes, mayBeResolvedMemoryObjects, + mayBeOutOfBound, hasLazyInitialized, incomplete, + LazyInitialization == LazyInitializationPolicy::Only)) { terminateStateOnSolverError(*state, "Query timed out (executeMemoryOperation)"); return; @@ -6678,9 +6570,6 @@ void Executor::executeMemoryOperation( ObjectState *wos = bound->addressSpace.getWriteable(mo, os); maxNewWriteableOSSize = std::max(maxNewWriteableOSSize, wos->getSparseStorageEntries()); - wos->getDynamicType()->handleMemoryAccess( - targetType, offset, - ConstantExpr::alloc(size, Context::get().getPointerWidth()), true); if (wos->readOnly) { terminateStateOnProgramError( *bound, @@ -6731,8 +6620,8 @@ void Executor::executeMemoryOperation( } else if (auto constBasePointer = dyn_cast(basePointer)) { ObjectPair contantResult; - uniqueBaseResolved = unbound->addressSpace.resolveOne( - constBasePointer, baseTargetType, contantResult); + uniqueBaseResolved = + unbound->addressSpace.resolveOne(constBasePointer, contantResult); if (uniqueBaseResolved) { idFastResult = contantResult.first; } @@ -6763,7 +6652,7 @@ void Executor::executeMemoryOperation( ref Executor::lazyInitializeObject( ExecutionState &state, ref address, const KInstruction *target, - KType *targetType, uint64_t concreteSize, ref size, bool isLocal, + uint64_t concreteSize, ref size, bool isLocal, ref conditionExpr, bool isSymbolic) { assert(!isa(address)); std::pair, ref> moBasePair; @@ -6805,11 +6694,10 @@ ref Executor::lazyInitializeObject( } ref addressExpr = address->getBase(); - MemoryObject *mo = - allocate(state, sizeExpr, isLocal, - /*isGlobal=*/false, CodeLocation::create(target, "", 0, {}), - /*allocationAlignment=*/8, targetType, conditionExpr, - addressExpr, timestamp); + MemoryObject *mo = allocate( + state, sizeExpr, isLocal, + /*isGlobal=*/false, CodeLocation::create(target, "", 0, {}), + /*allocationAlignment=*/8, conditionExpr, addressExpr, timestamp); return mo; } @@ -6837,9 +6725,9 @@ void Executor::lazyInitializeLocalObject(ExecutionState &state, StackFrame &sf, } ref conditionExpr = Expr::createTrue(); ref pointer = PointerExpr::create(address, address); - ref id = lazyInitializeObject( - state, pointer, target, typeSystemManager->getWrappedType(ai->getType()), - elementSize, size, true, conditionExpr, UseSymbolicSizeLazyInit); + ref id = + lazyInitializeObject(state, pointer, target, elementSize, size, true, + conditionExpr, UseSymbolicSizeLazyInit); state.addPointerResolution(pointer, id.get()); state.addConstraint(EqExpr::create(address, id->getBaseExpr())); state.addConstraint( @@ -6879,23 +6767,18 @@ ref Executor::makePointer(ref expr) const { } void Executor::executeMakeSymbolic(ExecutionState &state, - const MemoryObject *mo, KType *type, + const MemoryObject *mo, const ref source, bool isLocal) { // Create a new object state for the memory object (instead of a copy). if (!replayKTest) { const Array *array = makeArray(mo->getSizeExpr(), source); - ObjectState *os = bindObjectInState(state, mo, type, isLocal, array); + ObjectState *os = bindObjectInState(state, mo, isLocal, array); ref sizeExpr = dyn_cast(os->getObject()->getSizeExpr()); - if (AlignSymbolicPointers && sizeExpr) { - if (ref alignmentRestrictions = type->getContentRestrictions( - os->read(0, sizeExpr->getZExtValue() * CHAR_BIT))) { - addConstraint(state, alignmentRestrictions); - } - } - state.addSymbolic(mo, array, type); + + state.addSymbolic(mo, array); std::map>::iterator it = seedMap->find(&state); @@ -6948,7 +6831,7 @@ void Executor::executeMakeSymbolic(ExecutionState &state, } } } else { - ObjectState *os = bindObjectInState(state, mo, type, false); + ObjectState *os = bindObjectInState(state, mo, false); if (replayPosition >= replayKTest->numObjects) { terminateStateOnUserError(state, "replay count mismatch"); } else { @@ -7005,17 +6888,10 @@ ExecutionState *Executor::formState(Function *f, int argc, char **argv, ref parameterLocation = CodeLocation::create(kf, kf->getSourceFilepath(), kf->getLine(), {}); - llvm::Type *argumentType = llvm::PointerType::get( - llvm::IntegerType::get(kmodule->module->getContext(), 8), - kmodule->targetData->getAllocaAddrSpace()); - - llvm::Type *argvType = llvm::ArrayType::get(argumentType, 1); - argvMO = allocate( *state, Expr::createPointer((argc + 1 + envc + 1 + 1) * NumPtrBytes), /*isLocal=*/false, /*isGlobal=*/true, - /*allocSite=*/parameterLocation, /*alignment=*/8, - typeSystemManager->getWrappedType(argvType)); + /*allocSite=*/parameterLocation, /*alignment=*/8); if (!argvMO) klee_error("Could not allocate memory for function arguments"); @@ -7040,14 +6916,7 @@ ExecutionState *Executor::formState(Function *f, int argc, char **argv, bindArgument(kf, i, *state, arguments[i]); if (argvMO) { - llvm::Type *argumentType = llvm::PointerType::get( - llvm::IntegerType::get(kmodule->module->getContext(), 8), - kmodule->targetData->getAllocaAddrSpace()); - - llvm::Type *argvType = llvm::ArrayType::get(argumentType, 1); - - ObjectState *argvOS = bindObjectInState( - *state, argvMO, typeSystemManager->getWrappedType(argvType), false); + ObjectState *argvOS = bindObjectInState(*state, argvMO, false); for (int i = 0; i < argc + 1 + envc + 1 + 1; i++) { if (i == argc || i >= argc + 1 + envc) { @@ -7065,14 +6934,11 @@ ExecutionState *Executor::formState(Function *f, int argc, char **argv, MemoryObject *arg = allocate(*state, Expr::createPointer(len + 1), /*isLocal=*/false, /*isGlobal=*/true, - /*allocSite=*/parameterLocation, /*alignment=*/8, - typeSystemManager->getWrappedType(argumentType)); + /*allocSite=*/parameterLocation, /*alignment=*/8); if (!arg) klee_error("Could not allocate memory for function arguments"); - ObjectState *os = bindObjectInState( - *state, arg, typeSystemManager->getWrappedType(argumentType), - false); + ObjectState *os = bindObjectInState(*state, arg, false); for (j = 0; j < len + 1; j++) os->write8(j, s[j]); diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index 12a6126853..d0d4adc20b 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -102,7 +102,6 @@ class TargetManager; class StatsTracker; class TimingSolver; class TreeStreamWriter; -class TypeManager; class MergeHandler; class MergingSearcher; template class ref; @@ -152,7 +151,6 @@ class Executor : public Interpreter { ExternalDispatcher *externalDispatcher; std::unique_ptr solver; std::unique_ptr memory; - TypeManager *typeSystemManager; std::unique_ptr objectManager; StatsTracker *statsTracker; @@ -268,23 +266,19 @@ class Executor : public Interpreter { void seed(ExecutionState &initialState); void run(ExecutionState *initialState); - void initializeTypeManager(); - // Given a concrete object in our [klee's] address space, add it to // objects checked code can reference. - ObjectPair addExternalObject(ExecutionState &state, const void *addr, KType *, + ObjectPair addExternalObject(ExecutionState &state, const void *addr, unsigned size, bool isReadOnly); - ObjectPair addExternalObjectAsNonStatic(ExecutionState &state, KType *, - unsigned size, bool isReadOnly); + ObjectPair addExternalObjectAsNonStatic(ExecutionState &state, unsigned size, + bool isReadOnly); #ifdef HAVE_CTYPE_EXTERNALS template - decltype(auto) addCTypeFixedObject(ExecutionState &state, int addressSpaceNum, - llvm::Module &m, F objectProvider); + decltype(auto) addCTypeFixedObject(ExecutionState &state, F objectProvider); template decltype(auto) addCTypeModelledObject(ExecutionState &state, - int addressSpaceNum, llvm::Module &m, F objectProvider); #endif @@ -307,8 +301,7 @@ class Executor : public Interpreter { std::vector> &arguments); ObjectState *bindObjectInState(ExecutionState &state, const MemoryObject *mo, - KType *dynamicType, bool IsAlloca, - const Array *array = nullptr); + bool IsAlloca, const Array *array = nullptr); ObjectState *bindObjectInState(ExecutionState &state, const MemoryObject *mo, const ObjectState *object); @@ -322,11 +315,11 @@ class Executor : public Interpreter { /// beginning of. typedef std::vector> ExactResolutionList; - bool resolveExact(ExecutionState &state, ref p, KType *type, + bool resolveExact(ExecutionState &state, ref p, ExactResolutionList &results, const std::string &name); void concretizeSize(ExecutionState &state, ref size, bool isLocal, - KInstruction *target, KType *type, bool zeroMemory, + KInstruction *target, bool zeroMemory, const ObjectState *reallocFrom, size_t allocationAlignment, bool checkOutOfMemory); @@ -338,7 +331,7 @@ class Executor : public Interpreter { MemoryObject *allocate(ExecutionState &state, ref size, bool isLocal, bool isGlobal, ref allocSite, - size_t allocationAlignment, KType *type, + size_t allocationAlignment, ref conditionExpr = Expr::createTrue(), ref lazyInitializationSource = ref(), unsigned timestamp = 0); @@ -363,7 +356,7 @@ class Executor : public Interpreter { /// used. Otherwise, the alignment is deduced via /// Executor::getAllocationAlignment void executeAlloc(ExecutionState &state, ref size, bool isLocal, - KInstruction *target, KType *type, bool zeroMemory = false, + KInstruction *target, bool zeroMemory = false, const ObjectState *reallocFrom = 0, size_t allocationAlignment = 0, bool checkOutOfMemory = false); @@ -392,8 +385,7 @@ class Executor : public Interpreter { typedef std::vector> ObjectResolutionList; bool resolveMemoryObjects(ExecutionState &state, ref address, - KType *targetType, KInstruction *target, - unsigned bytes, + KInstruction *target, unsigned bytes, ObjectResolutionList &mayBeResolvedMemoryObjects, bool &mayBeOutOfBound, bool &mayLazyInitialize, bool &incomplete, bool onlyLazyInitialize = false); @@ -418,15 +410,15 @@ class Executor : public Interpreter { // do address resolution / object binding / out of bounds checking // and perform the operation void executeMemoryOperation(ExecutionState &state, bool isWrite, - KType *targetType, ref address, + ref address, ref value /* undef if read */, KInstruction *target /* undef if write */); ref lazyInitializeObject(ExecutionState &state, ref address, - const KInstruction *target, KType *targetType, - uint64_t concreteSize, ref size, bool isLocal, - ref conditionExpr, bool isConstant = true); + const KInstruction *target, uint64_t concreteSize, + ref size, bool isLocal, ref conditionExpr, + bool isConstant = true); void lazyInitializeLocalObject(ExecutionState &state, StackFrame &sf, ref address, const KInstruction *target); @@ -435,8 +427,7 @@ class Executor : public Interpreter { const KInstruction *target); void executeMakeSymbolic(ExecutionState &state, const MemoryObject *mo, - KType *type, const ref source, - bool isLocal); + const ref source, bool isLocal); /// Assume that `current` state stepped to `block`. /// Can we reach at least one target of `current` from there? diff --git a/lib/Core/Memory.cpp b/lib/Core/Memory.cpp index acf8228e89..a13fb97fee 100644 --- a/lib/Core/Memory.cpp +++ b/lib/Core/Memory.cpp @@ -21,7 +21,6 @@ #include "CodeLocation.h" #include "klee/Expr/Assignment.h" #include "klee/Expr/Expr.h" -#include "klee/Module/KType.h" #include "klee/Solver/Solver.h" #include "klee/Support/ErrorHandling.h" @@ -99,29 +98,27 @@ std::string MemoryObject::getAllocInfo() const { /***/ -ObjectState::ObjectState(const MemoryObject *mo, const Array *array, KType *dt) +ObjectState::ObjectState(const MemoryObject *mo, const Array *array) : copyOnWriteOwner(0), object(mo), valueOS(ObjectStage(array, nullptr)), baseOS(ObjectStage(array->size, Expr::createPointer(0), false, Context::get().getPointerWidth())), - lastUpdate(nullptr), size(array->size), dynamicType(dt), readOnly(false) { + lastUpdate(nullptr), size(array->size), readOnly(false) { baseOS.initializeToZero(); } -ObjectState::ObjectState(const MemoryObject *mo, KType *dt) +ObjectState::ObjectState(const MemoryObject *mo) : copyOnWriteOwner(0), object(mo), valueOS(ObjectStage(mo->getSizeExpr(), nullptr)), baseOS(ObjectStage(mo->getSizeExpr(), Expr::createPointer(0), false, Context::get().getPointerWidth())), - lastUpdate(nullptr), size(mo->getSizeExpr()), dynamicType(dt), - readOnly(false) { + lastUpdate(nullptr), size(mo->getSizeExpr()), readOnly(false) { baseOS.initializeToZero(); } ObjectState::ObjectState(const ObjectState &os) : copyOnWriteOwner(0), object(os.object), valueOS(os.valueOS), baseOS(os.baseOS), lastUpdate(os.lastUpdate), size(os.size), - dynamicType(os.dynamicType), readOnly(os.readOnly), - wasWritten(os.wasWritten) {} + readOnly(os.readOnly), wasWritten(os.wasWritten) {} /***/ @@ -511,13 +508,6 @@ void ObjectState::print() const { baseOS.print(); } -KType *ObjectState::getDynamicType() const { return dynamicType; } - -bool ObjectState::isAccessableFrom(KType *accessingType) const { - return !UseTypeBasedAliasAnalysis || - dynamicType->isAccessableFrom(accessingType); -} - /***/ ObjectStage::ObjectStage(const Array *array, ref defaultValue, bool safe, diff --git a/lib/Core/Memory.h b/lib/Core/Memory.h index 71c3172981..830e92d3ab 100644 --- a/lib/Core/Memory.h +++ b/lib/Core/Memory.h @@ -33,14 +33,12 @@ namespace klee { class BitArray; class ExecutionState; -class KType; class Executor; class MemoryManager; class Solver; typedef uint64_t IDType; -extern llvm::cl::opt UseTypeBasedAliasAnalysis; extern llvm::cl::opt MaxFixedSizeStructureSize; class MemoryObject { @@ -83,7 +81,6 @@ class MemoryObject { bool isUserSpecified; MemoryManager *parent; - KType *type; const Array *content; /// "Location" for which this memory object was allocated. This @@ -101,13 +98,13 @@ class MemoryObject { : id(0), timestamp(0), addressExpr(Expr::createPointer(_address)), address(_address), sizeExpr(Expr::createPointer(0)), conditionExpr(Expr::createTrue()), alignment(0), isFixed(true), - isLazyInitialized(false), parent(nullptr), type(nullptr), - content(nullptr), allocSite(nullptr) {} + isLazyInitialized(false), parent(nullptr), content(nullptr), + allocSite(nullptr) {} MemoryObject( ref _address, ref _size, uint64_t alignment, bool _isLocal, bool _isGlobal, bool _isFixed, bool _isLazyInitialized, - ref _allocSite, MemoryManager *_parent, KType *_type, + ref _allocSite, MemoryManager *_parent, ref _condition = Expr::createTrue(), unsigned _timestamp = 0 /* unused if _isLazyInitialized is false*/, const Array *_content = @@ -116,7 +113,7 @@ class MemoryObject { sizeExpr(_size), conditionExpr(_condition), alignment(alignment), name("unnamed"), isLocal(_isLocal), isGlobal(_isGlobal), isFixed(_isFixed), isLazyInitialized(_isLazyInitialized), - isUserSpecified(false), parent(_parent), type(_type), content(_content), + isUserSpecified(false), parent(_parent), content(_content), allocSite(_allocSite) { if (isLazyInitialized) { timestamp = _timestamp; @@ -288,16 +285,14 @@ class ObjectState { ref size; - KType *dynamicType; - public: bool readOnly; bool wasWritten = false; /// Create a new object state for the given memory // For objects in memory - ObjectState(const MemoryObject *mo, const Array *array, KType *dt); - ObjectState(const MemoryObject *mo, KType *dt); + ObjectState(const MemoryObject *mo, const Array *array); + ObjectState(const MemoryObject *mo); // For symbolic objects not in memory (hack) @@ -335,10 +330,6 @@ class ObjectState { void write64(unsigned offset, uint64_t value); void print() const; - bool isAccessableFrom(KType *) const; - - KType *getDynamicType() const; - private: ref read8(ref offset) const; ref readValue8(ref offset) const; diff --git a/lib/Core/MemoryManager.cpp b/lib/Core/MemoryManager.cpp index 5e856e5b0d..f81f311cb6 100644 --- a/lib/Core/MemoryManager.cpp +++ b/lib/Core/MemoryManager.cpp @@ -126,8 +126,7 @@ MemoryManager::~MemoryManager() { MemoryObject *MemoryManager::allocate(ref size, bool isLocal, bool isGlobal, bool isLazyInitialized, ref allocSite, - size_t alignment, KType *type, - ref conditionExpr, + size_t alignment, ref conditionExpr, ref addressExpr, unsigned timestamp, const Array *content) { if (ref sizeExpr = dyn_cast(size)) { @@ -193,16 +192,15 @@ MemoryObject *MemoryManager::allocate(ref size, bool isLocal, ++stats::allocations; res = new MemoryObject(addressExpr, size, alignment, isLocal, isGlobal, false, - isLazyInitialized, allocSite, this, type, - conditionExpr, timestamp, content); + isLazyInitialized, allocSite, this, conditionExpr, + timestamp, content); objects.insert(res); return res; } MemoryObject *MemoryManager::allocateFixed(uint64_t address, uint64_t size, - ref allocSite, - KType *type) { + ref allocSite) { #ifndef NDEBUG for (objects_ty::iterator it = objects.begin(), ie = objects.end(); it != ie; ++it) { @@ -224,7 +222,7 @@ MemoryObject *MemoryManager::allocateFixed(uint64_t address, uint64_t size, ref addressExpr = Expr::createPointer(address); MemoryObject *res = new MemoryObject(addressExpr, Expr::createPointer(size), 8, false, true, - true, false, allocSite, this, type); + true, false, allocSite, this); objects.insert(res); return res; } diff --git a/lib/Core/MemoryManager.h b/lib/Core/MemoryManager.h index f714c7f186..a10cf688a9 100644 --- a/lib/Core/MemoryManager.h +++ b/lib/Core/MemoryManager.h @@ -21,7 +21,6 @@ class Value; } namespace klee { -class KType; class MemoryObject; struct CodeLocation; @@ -46,13 +45,13 @@ class MemoryManager { */ MemoryObject *allocate(ref size, bool isLocal, bool isGlobal, bool isLazyInitialiazed, ref allocSite, - size_t alignment, KType *type, + size_t alignment, ref conditionExpr = Expr::createTrue(), ref addressExpr = ref(), unsigned timestamp = 0, const Array *content = nullptr); MemoryObject *allocateFixed(uint64_t address, uint64_t size, - ref allocSite, KType *type); + ref allocSite); void markFreed(MemoryObject *mo); /* * Returns the size used by deterministic allocation in bytes diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp index 8031d7320e..62557719a2 100644 --- a/lib/Core/SpecialFunctionHandler.cpp +++ b/lib/Core/SpecialFunctionHandler.cpp @@ -17,7 +17,6 @@ #include "Searcher.h" #include "StatsTracker.h" #include "TimingSolver.h" -#include "TypeManager.h" #include "klee/Config/config.h" #include "klee/Core/Context.h" @@ -276,9 +275,7 @@ SpecialFunctionHandler::readStringAtAddress(ExecutionState &state, } ref pointerConst = cast(uniquePointer); - if (!state.addressSpace.resolveOne( - pointerConst, executor.typeSystemManager->getUnknownType(), - idStringAddress)) { + if (!state.addressSpace.resolveOne(pointerConst, idStringAddress)) { executor.terminateStateOnUserError( state, "Invalid string pointer passed to one of the klee_ functions"); return ""; @@ -385,9 +382,8 @@ void SpecialFunctionHandler::handleNew(ExecutionState &state, std::vector> &arguments) { // XXX should type check args assert(arguments.size() == 1 && "invalid number of arguments to new"); - executor.executeAlloc(state, arguments[0], false, target, - executor.typeSystemManager->handleAlloc(arguments[0]), - false, nullptr, 0, CheckOutOfMemory); + executor.executeAlloc(state, arguments[0], false, target, false, nullptr, 0, + CheckOutOfMemory); } void SpecialFunctionHandler::handleDelete(ExecutionState &state, KInstruction *, @@ -405,9 +401,8 @@ void SpecialFunctionHandler::handleNewArray(ExecutionState &state, std::vector> &arguments) { // XXX should type check args assert(arguments.size() == 1 && "invalid number of arguments to new[]"); - executor.executeAlloc(state, arguments[0], false, target, - executor.typeSystemManager->handleAlloc(arguments[0]), - false, nullptr, 0, CheckOutOfMemory); + executor.executeAlloc(state, arguments[0], false, target, false, nullptr, 0, + CheckOutOfMemory); } void SpecialFunctionHandler::handleNewNothrowArray( @@ -417,9 +412,8 @@ void SpecialFunctionHandler::handleNewNothrowArray( assert(arguments.size() == 2 && "invalid number of arguments to new[](unsigned long, std::nothrow_t " "const&)"); - executor.executeAlloc(state, arguments[0], false, target, - executor.typeSystemManager->handleAlloc(arguments[0]), - false, nullptr, 0, CheckOutOfMemory); + executor.executeAlloc(state, arguments[0], false, target, false, nullptr, 0, + CheckOutOfMemory); } void SpecialFunctionHandler::handleDeleteArray( @@ -434,9 +428,8 @@ void SpecialFunctionHandler::handleMalloc(ExecutionState &state, std::vector> &arguments) { // XXX should type check args assert(arguments.size() == 1 && "invalid number of arguments to malloc"); - executor.executeAlloc(state, arguments[0], false, target, - executor.typeSystemManager->handleAlloc(arguments[0]), - false, nullptr, 0, CheckOutOfMemory); + executor.executeAlloc(state, arguments[0], false, target, false, nullptr, 0, + CheckOutOfMemory); } void SpecialFunctionHandler::handleMemalign(ExecutionState &state, @@ -469,9 +462,8 @@ void SpecialFunctionHandler::handleMemalign(ExecutionState &state, 0, "Symbolic alignment for memalign. Choosing smallest alignment"); } - executor.executeAlloc(state, arguments[1], false, target, - executor.typeSystemManager->handleAlloc(arguments[1]), - false, 0, alignment); + executor.executeAlloc(state, arguments[1], false, target, false, 0, + alignment); } #ifdef SUPPORT_KLEE_EH_CXX @@ -672,9 +664,7 @@ void SpecialFunctionHandler::handleGetObjSize( assert(arguments.size() == 1 && "invalid number of arguments to klee_get_obj_size"); Executor::ExactResolutionList rl; - executor.resolveExact(state, arguments[0], - executor.typeSystemManager->getUnknownType(), rl, - "klee_get_obj_size"); + executor.resolveExact(state, arguments[0], rl, "klee_get_obj_size"); for (Executor::ExactResolutionList::iterator it = rl.begin(), ie = rl.end(); it != ie; ++it) { const MemoryObject *mo = it->first; @@ -696,15 +686,10 @@ void SpecialFunctionHandler::handleGetErrno( // Retrieve the memory object of the errno variable ObjectPair idErrnoObject; - llvm::Type *pointerErrnoAddr = llvm::PointerType::get( - llvm::IntegerType::get(executor.kmodule->module->getContext(), - sizeof(*errno_addr) * CHAR_BIT), - executor.kmodule->targetData->getAllocaAddrSpace()); bool resolved = state.addressSpace.resolveOne( ConstantPointerExpr::create(Expr::createPointer((uint64_t)errno_addr), Expr::createPointer((uint64_t)errno_addr)), - executor.typeSystemManager->getWrappedType(pointerErrnoAddr), idErrnoObject); if (!resolved) executor.terminateStateOnUserError(state, @@ -740,9 +725,8 @@ void SpecialFunctionHandler::handleCalloc(ExecutionState &state, assert(arguments.size() == 2 && "invalid number of arguments to calloc"); ref size = MulExpr::create(arguments[0], arguments[1]); - executor.executeAlloc(state, size, false, target, - executor.typeSystemManager->handleAlloc(size), true, - nullptr, 0, CheckOutOfMemory); + executor.executeAlloc(state, size, false, target, true, nullptr, 0, + CheckOutOfMemory); } void SpecialFunctionHandler::handleRealloc(ExecutionState &state, @@ -769,15 +753,12 @@ void SpecialFunctionHandler::handleRealloc(ExecutionState &state, BranchType::Realloc); if (zeroPointer.first) { // address == 0 - executor.executeAlloc(*zeroPointer.first, size, false, target, - executor.typeSystemManager->handleAlloc(size), - false, nullptr, 0, CheckOutOfMemory); + executor.executeAlloc(*zeroPointer.first, size, false, target, false, + nullptr, 0, CheckOutOfMemory); } if (zeroPointer.second) { // address != 0 Executor::ExactResolutionList rl; - executor.resolveExact(*zeroPointer.second, address, - executor.typeSystemManager->getUnknownType(), rl, - "realloc"); + executor.resolveExact(*zeroPointer.second, address, rl, "realloc"); for (Executor::ExactResolutionList::iterator it = rl.begin(), ie = rl.end(); @@ -785,10 +766,8 @@ void SpecialFunctionHandler::handleRealloc(ExecutionState &state, ref os = it->second->addressSpace.findOrLazyInitializeObject(it->first) .second; - executor.executeAlloc(*it->second, size, false, target, - executor.typeSystemManager->handleRealloc( - os->getDynamicType(), size), - false, os.get(), 0, CheckOutOfMemory); + executor.executeAlloc(*it->second, size, false, target, false, os.get(), + 0, CheckOutOfMemory); } } } @@ -815,9 +794,8 @@ void SpecialFunctionHandler::handleCheckMemoryAccess( } else { ObjectPair idObject; - if (!state.addressSpace.resolveOne( - cast(uniquePointer), - executor.typeSystemManager->getUnknownType(), idObject)) { + if (!state.addressSpace.resolveOne(cast(uniquePointer), + idObject)) { executor.terminateStateOnProgramError( state, new ErrorEvent(executor.locationOf(state), StateTerminationType::Ptr, @@ -865,11 +843,9 @@ void SpecialFunctionHandler::handleDefineFixedObject( ->getConstantValue() ->getZExtValue(); uint64_t size = cast(arguments[1])->getZExtValue(); - MemoryObject *mo = executor.memory->allocateFixed( - address, size, executor.locationOf(state), - executor.typeSystemManager->getUnknownType()); - executor.bindObjectInState( - state, mo, executor.typeSystemManager->getUnknownType(), false); + MemoryObject *mo = + executor.memory->allocateFixed(address, size, executor.locationOf(state)); + executor.bindObjectInState(state, mo, false); mo->isUserSpecified = true; // XXX hack; executor.bindLocal(target, state, @@ -898,9 +874,7 @@ void SpecialFunctionHandler::handleMakeSymbolic( } Executor::ExactResolutionList rl; - executor.resolveExact(state, arguments[0], - executor.typeSystemManager->getUnknownType(), rl, - "make_symbolic"); + executor.resolveExact(state, arguments[0], rl, "make_symbolic"); for (Executor::ExactResolutionList::iterator it = rl.begin(), ie = rl.end(); it != ie; ++it) { @@ -931,7 +905,7 @@ void SpecialFunctionHandler::handleMakeSymbolic( if (res) { executor.executeMakeSymbolic( - *s, mo, old->getDynamicType(), + *s, mo, SourceBuilder::makeSymbolic(name, executor.updateNameVersion(*s, name)), false); @@ -967,9 +941,7 @@ void SpecialFunctionHandler::handleMakeMock(ExecutionState &state, KFunction *kf = target->parent->parent; Executor::ExactResolutionList rl; - executor.resolveExact(state, arguments[0], - executor.typeSystemManager->getUnknownType(), rl, - "make_symbolic"); + executor.resolveExact(state, arguments[0], rl, "make_symbolic"); for (auto &it : rl) { ObjectPair op = it.second->addressSpace.findObject(it.first); @@ -1012,8 +984,7 @@ void SpecialFunctionHandler::handleMakeMock(ExecutionState &state, *kf->function(), args); break; } - executor.executeMakeSymbolic(state, mo, old->getDynamicType(), source, - false); + executor.executeMakeSymbolic(state, mo, source, false); } else { executor.terminateStateOnUserError(*s, "Wrong size given to klee_make_mock"); @@ -1027,9 +998,7 @@ void SpecialFunctionHandler::handleMarkGlobal( "invalid number of arguments to klee_mark_global"); Executor::ExactResolutionList rl; - executor.resolveExact(state, arguments[0], - executor.typeSystemManager->getUnknownType(), rl, - "mark_global"); + executor.resolveExact(state, arguments[0], rl, "mark_global"); for (Executor::ExactResolutionList::iterator it = rl.begin(), ie = rl.end(); it != ie; ++it) { diff --git a/lib/Core/TypeManager.h b/lib/Core/TypeManager.h deleted file mode 100644 index 515f50aafb..0000000000 --- a/lib/Core/TypeManager.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef KLEE_TYPEMANAGER_H -#define KLEE_TYPEMANAGER_H - -#include -#include -#include - -namespace llvm { -class Type; -class Function; -} // namespace llvm - -namespace klee { - -class Expr; -class KType; -class KModule; -struct KInstruction; - -template class ref; -template class ExprHashMap; - -/** - * Default class for managing type system. - * Works with *raw* llvm types. By extending this - * class you can add more rules to type system. - */ -class TypeManager { -private: - void initTypesFromGlobals(); - void initTypesFromStructs(); - void initTypesFromInstructions(); - void initTypeInfo(); - -protected: - KModule *parent; - std::vector> types; - std::unordered_map typesMap; - - /** - * Make specified post initialization in initModule(). Note, that - * it is intentionally separated from initModule, as initModule - * order of function calls in it important. By default do nothing. - */ - virtual void onFinishInitModule(); - -public: - TypeManager(KModule *); - - /** - * Initializes type system for current module. - */ - void initModule(); - - virtual KType *getWrappedType(llvm::Type *); - KType *getUnknownType(); - - virtual KType *handleAlloc(ref size); - virtual KType *handleRealloc(KType *, ref); - - virtual ~TypeManager() = default; -}; - -} /*namespace klee*/ - -#endif /* KLEE_TYPEMANAGER_H */ diff --git a/lib/Module/CMakeLists.txt b/lib/Module/CMakeLists.txt index 21840ecbe3..21ee671b02 100644 --- a/lib/Module/CMakeLists.txt +++ b/lib/Module/CMakeLists.txt @@ -18,7 +18,6 @@ set(KLEE_MODULE_COMPONENT_SRCS IntrinsicCleaner.cpp KInstruction.cpp KModule.cpp - KType.cpp KValue.cpp LocalVarDeclarationFinderPass.cpp LowerSwitch.cpp diff --git a/lib/Module/KType.cpp b/lib/Module/KType.cpp deleted file mode 100644 index 8642ae3248..0000000000 --- a/lib/Module/KType.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "klee/Module/KType.h" - -#include "klee/ADT/Ref.h" -#include "klee/Expr/Expr.h" -#include "klee/Module/KModule.h" - -#include "llvm/IR/Type.h" -#include "llvm/Support/raw_ostream.h" - -using namespace klee; -using namespace llvm; - -KType::KType(llvm::Type *type, TypeManager *parent) - : type(type), parent(parent) { - typeSystemKind = TypeSystemKind::Default; - /* Type itself can be reached at offset 0 */ - innerTypes[this].insert(0); -} - -bool KType::isAccessableFrom(KType *) const { return true; } - -llvm::Type *KType::getRawType() const { return type; } - -TypeSystemKind KType::getTypeSystemKind() const { return typeSystemKind; } - -void KType::handleMemoryAccess(KType *, ref, ref, bool) {} - -size_t KType::getSize() const { return typeStoreSize; } - -size_t KType::getAlignment() const { return alignment; } - -ref KType::getContentRestrictions(ref) const { return nullptr; } - -const std::unordered_map> & -KType::getInnerTypes() const { - return innerTypes; -} - -void KType::print(llvm::raw_ostream &os) const { - if (type == nullptr) { - os << "nullptr"; - } else { - type->print(os); - } -} diff --git a/test/Feature/types/ArrayAccess.c b/test/Feature/types/ArrayAccess.c deleted file mode 100644 index 3fa710303c..0000000000 --- a/test/Feature/types/ArrayAccess.c +++ /dev/null @@ -1,39 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include - -int main() { - int array_int[10] = {1, 2, 3, 4, 5}; - float array_float[2] = {1.0, 2.0}; - - int *ptr; - klee_make_symbolic(&ptr, sizeof(ptr), "ptr"); - *ptr = 10; - - // CHECK-NOT: ASSERTION FAIL - assert((void *)ptr != (void *)array_float); - - // CHECK-DAG: x - if ((void *)ptr == (void *)array_int) { - printf("x\n"); - return 0; - } - - float(*ptr_array_float)[2]; - klee_make_symbolic(&ptr_array_float, sizeof(ptr_array_float), "ptr_array_float"); - (*ptr_array_float)[1] = 111.1; - - // CHECK-NOT: ASSERTION FAIL - assert((void *)ptr_array_float != (void *)&array_int); - - // CHECK-DAG: y - if (ptr_array_float == &array_float) { - printf("y\n"); - return 2; - } - return 1; -} diff --git a/test/Feature/types/InnerStructAccess.c b/test/Feature/types/InnerStructAccess.c deleted file mode 100644 index 6062430983..0000000000 --- a/test/Feature/types/InnerStructAccess.c +++ /dev/null @@ -1,40 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include -#include - -typedef struct A { - int32_t x; -} A; - -typedef struct B { - A a; - float y; -} B; - -int main() { - B b; - - int32_t *ptr; - klee_make_symbolic(&ptr, sizeof(ptr), "ptr"); - *ptr = 10; - - // CHECK: x - if ((void *)ptr == (void *)&b) { - printf("x\n"); - return 0; - } - - int16_t *short_ptr; - klee_make_symbolic(&short_ptr, sizeof(short_ptr), "short_ptr"); - *short_ptr = 12; - - // CHECK-NOT: ASSERTION FAIL - assert((void *)short_ptr < (void *)&b || (void *)short_ptr >= (void *)(&b + 1)); - - return 1; -} diff --git a/test/Feature/types/StructDereference.c b/test/Feature/types/StructDereference.c deleted file mode 100644 index a42bcb37ec..0000000000 --- a/test/Feature/types/StructDereference.c +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include - -typedef struct Node { - int x; - struct Node *next; -} Node; - -int main() { - Node node; - - int *pointer; - klee_make_symbolic(&pointer, sizeof(pointer), "pointer"); - *pointer = 100; - - // CHECK-NOT: ASSERTION FAIL - assert((void *)pointer != (void *)&pointer); - - // CHECK: x - if ((void *)pointer == (void *)&node.x) { - // CHECK-NOT: ASSERTION-FAIL - assert(node.x == 100); - printf("x\n"); - return 0; - } -} diff --git a/test/Feature/types/SymbolicPointerMultipleResolve.c b/test/Feature/types/SymbolicPointerMultipleResolve.c deleted file mode 100644 index bf8e73217f..0000000000 --- a/test/Feature/types/SymbolicPointerMultipleResolve.c +++ /dev/null @@ -1,66 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include - -typedef struct Node { - struct Node *next; -} Node; - -int main() { - int a = 100; - float b = 2.0; - long long c = 120; - double d = 11; - Node node; - Node *node_ptr; - - int *pointer; - klee_make_symbolic(&pointer, sizeof(pointer), "pointer"); - *pointer = 1; - - // CHECK-NOT: ASSERTION FAIL - assert((void *)pointer != (void *)&pointer); - - // CHECK-NOT: ASSERTION FAIL - assert((void *)pointer != (void *)&b); - - // CHECK-NOT: ASSERTION FAIL - assert((void *)pointer != (void *)&c); - - // CHECK-NOT: ASSERTION FAIL - assert((void *)pointer != (void *)&d); - - // CHECK-NOT: ASSERTION FAIL - assert((void *)pointer != (void *)&node); - - if ((void *)pointer == (void *)&a) { - // CHECK-NOT: ASSERTION FAIL - assert(a == 1); - } - - char *anyPointer; - klee_make_symbolic(&anyPointer, sizeof(anyPointer), "anyPointer"); - *anyPointer = '0'; - // CHECK-DAG: a - // CHECK-DAG: b - // CHECK-DAG: c - // CHECK-DAG: d - if ((void *)anyPointer == (void *)&a) { - printf("a\n"); - return 0; - } else if ((void *)anyPointer == (void *)&b) { - printf("b\n"); - return 1; - } else if ((void *)anyPointer == (void *)&c) { - printf("c\n"); - return 2; - } else if ((void *)anyPointer == (void *)&d) { - printf("d\n"); - return 3; - } - return 4; -} diff --git a/test/Feature/types/SymbolicPointerSimpleResolve.c b/test/Feature/types/SymbolicPointerSimpleResolve.c deleted file mode 100644 index 957ba1c2d1..0000000000 --- a/test/Feature/types/SymbolicPointerSimpleResolve.c +++ /dev/null @@ -1,26 +0,0 @@ -// RUN: echo "x" > %t.res -// RUN: echo "x" >> %t.res -// RUN: echo "x" >> %t.res -// RUN: echo "x" >> %t.res -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --skip-local=false --use-gep-opt %t.bc >%t.log -// RUN: diff %t.res %t.log - -#include "klee/klee.h" -#include - -int main() { - int a = 100; - int b = 200; - int c = 300; - unsigned int d = 400; - - int *pointer; - klee_make_symbolic(&pointer, sizeof(pointer), "pointer"); - *pointer += 11; - - if (pointer == &a || pointer == &b || pointer == &c || pointer == &d) { - printf("x\n"); - } -} diff --git a/test/Feature/types/UnionAccess.c b/test/Feature/types/UnionAccess.c deleted file mode 100644 index 013a0bfb29..0000000000 --- a/test/Feature/types/UnionAccess.c +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include - -typedef union U { - int x; - float y; - double z; -} U; - -int main() { - U u; - u.x = 0; - int *pointer; - klee_make_symbolic(&pointer, sizeof(pointer), "pointer"); - *pointer = 100; - - // CHECK: x - if (u.x == 100) { - printf("x"); - return 0; - } - - return 1; -} diff --git a/test/Feature/types/effective-type/EffectiveTypeFirstRead.c b/test/Feature/types/effective-type/EffectiveTypeFirstRead.c deleted file mode 100644 index 8b6d359f67..0000000000 --- a/test/Feature/types/effective-type/EffectiveTypeFirstRead.c +++ /dev/null @@ -1,30 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include -#include - -enum { SIZE = 4 }; - -int main() { - char *area = malloc(SIZE); - for (int i = 0; i < SIZE; ++i) { - area[i] = '0'; - } - - int *pointer; - klee_make_symbolic(&pointer, sizeof(pointer), "pointer"); - *pointer = 1; - - // CHECK-DAG: x - if ((void *)pointer == (void *)area) { - printf("x\n"); - // CHECK-NOT: ASSERTION FAIL - assert((area[0] == 1) ^ (area[3] == 1)); - } - - return 0; -} diff --git a/test/Feature/types/effective-type/EffectiveTypeMalloc.c b/test/Feature/types/effective-type/EffectiveTypeMalloc.c deleted file mode 100644 index a5c32d7efc..0000000000 --- a/test/Feature/types/effective-type/EffectiveTypeMalloc.c +++ /dev/null @@ -1,41 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include -#include - -void fillBytes(void *area) { - *((int32_t *)area) = 10; - *((float *)(area + 4)) = 1.0; -} - -enum { AREA_BLOCKS = 8 }; - -int main() { - void *area = malloc(AREA_BLOCKS * (sizeof(int32_t) + sizeof(float))); - for (int i = 0; i < AREA_BLOCKS; ++i) { - fillBytes(area + i * (sizeof(int32_t) + sizeof(float))); - } - - double *doubleArea = malloc(2 * sizeof(double)); - doubleArea[0] = 1.0; - doubleArea[1] = 1.1; - - double *ptr_double; - klee_make_symbolic(&ptr_double, sizeof(ptr_double), "ptr_double"); - *ptr_double = 0.0; - - // CHECK-NOT: ASSERTION FAIL - assert((void *)ptr_double < (void *)area || (void *)ptr_double >= (void *)area + AREA_BLOCKS * (sizeof(int32_t) + sizeof(float))); - - *ptr_double = 1.2; - // CHECK: x - if ((void *)ptr_double >= (void *)doubleArea && (void *)ptr_double < (void *)doubleArea + 2) { - printf("x\n"); - return 0; - } - return 1; -} diff --git a/test/Feature/types/effective-type/EffectiveTypeMemset.c b/test/Feature/types/effective-type/EffectiveTypeMemset.c deleted file mode 100644 index 6301b21e29..0000000000 --- a/test/Feature/types/effective-type/EffectiveTypeMemset.c +++ /dev/null @@ -1,41 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" - -#include -#include -#include - -enum { SIZE = 8 }; - -int main() { - int *area = malloc(SIZE); - memset(area, '1', SIZE); - - float *float_ptr; - klee_make_symbolic(&float_ptr, sizeof(float_ptr), "float_ptr"); - *float_ptr = 10; - - int created = 0; - - // CHECK-DAG: x - if ((void *)float_ptr == (void *)area) { - ++created; - printf("x\n"); - } - - int *int_ptr; - klee_make_symbolic(&int_ptr, sizeof(int_ptr), "int_ptr"); - *int_ptr = 11; - - // CHECK-DAG: y - // CHECK-DAG: z - if ((void *)int_ptr == (void *)area + sizeof(float)) { - ++created; - printf(created == 2 ? "z\n" : "y\n"); - return 1; - } - return 2; -} diff --git a/test/Feature/types/effective-type/EffectiveTypeRealloc.c b/test/Feature/types/effective-type/EffectiveTypeRealloc.c deleted file mode 100644 index cf8501f08b..0000000000 --- a/test/Feature/types/effective-type/EffectiveTypeRealloc.c +++ /dev/null @@ -1,50 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include -#include - -enum { INIT = 4, - NEXT = 8 }; - -void *createArea() { - int32_t *preresult = malloc(INIT); - *preresult = (int32_t)10; - float *result = realloc(preresult, NEXT); - *(result + 1) = (float)1.f; - return result; -} - -int main() { - void *area = createArea(); - - int *ptr_int; - klee_make_symbolic(&ptr_int, sizeof(ptr_int), "ptr_int"); - *ptr_int = 100; - - // CHECK-DAG: x - if ((void *)ptr_int == area) { - printf("x\n"); - return 0; - } - - float *ptr_float; - klee_make_symbolic(&ptr_float, sizeof(ptr_float), "ptr_float"); - *ptr_float = 100.0; - // CHECK-DAG: y - if ((void *)ptr_float >= area + 4) { - printf("y\n"); - return 0; - } - - double *ptr_double; - klee_make_symbolic(&ptr_double, sizeof(ptr_double), "ptr_double"); - *ptr_double = 100.0; - - // CHECK-NOT: ASSERTION FAIL - assert(ptr_double != area); - return 0; -} diff --git a/test/Feature/types/effective-type/OperatorNew.cpp b/test/Feature/types/effective-type/OperatorNew.cpp deleted file mode 100644 index dde3bb0478..0000000000 --- a/test/Feature/types/effective-type/OperatorNew.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include -#include -#include - -struct S { - int a; - float b = 1.0; - double c = 2.0; - int16_t d; - S(int x) : a(x) {} -}; - -bool isSameAddress(void *a, void *b) { - return a == b; -} - -int main() { - S *s = new S(10); - - int *ptr_int; - klee_make_symbolic(&ptr_int, sizeof(ptr_int), "ptr_int"); - *ptr_int = 100; - - // CHECK-DAG: x - if (isSameAddress(ptr_int, s)) { - printf("x\n"); - return 0; - } - - float *ptr_float; - klee_make_symbolic(&ptr_float, sizeof(ptr_float), "ptr_float"); - *ptr_float = 10.f; - - // CHECK-DAG: y - if (isSameAddress(ptr_float, s)) { - printf("y\n"); - return 0; - } - - double *ptr_double; - klee_make_symbolic(&ptr_double, sizeof(ptr_double), "ptr_double"); - *ptr_double = 120; - // CHECK-NOT: ASSERTION-FAIL - assert(!isSameAddress(ptr_double, s)); -} diff --git a/test/Feature/types/pointers-alignment/ArrayPointerAlignment.c b/test/Feature/types/pointers-alignment/ArrayPointerAlignment.c deleted file mode 100644 index 040eaec176..0000000000 --- a/test/Feature/types/pointers-alignment/ArrayPointerAlignment.c +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -fsanitize=alignment,null -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --align-symbolic-pointers=true --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include - -int main() { - int16_t value = 0; - - int16_t *array[2]; - klee_make_symbolic(&array, sizeof(array), "array"); - - // CHECK: x - if (!array[1]) { - printf("x"); - return 0; - } - - // CHECK-NOT: ArrayPointerAlignment.c:[[@LINE+1]]: either misaligned address 0x{{.*}} or invalid usage of address 0x{{.*}} with insufficient space - *(array[1]) = 100; - return 0; -} diff --git a/test/Feature/types/pointers-alignment/DefaultPointerAlignment.c b/test/Feature/types/pointers-alignment/DefaultPointerAlignment.c deleted file mode 100644 index 3a21e7e1ea..0000000000 --- a/test/Feature/types/pointers-alignment/DefaultPointerAlignment.c +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -fsanitize=alignment,null -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --ubsan-runtime --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --align-symbolic-pointers=true --skip-local=false --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include - -int main() { - float value; - - float *ptr; - klee_make_symbolic(&ptr, sizeof(ptr), "ptr"); - - // CHECK: KLEE: ERROR: {{.*}}runtime/Sanitizer/ubsan/ubsan_handlers.cpp:{{[0-9]+}}: null-pointer-use - *ptr = 10; - - int n = klee_range(1, 4, "n"); - ptr = (float *)(((char *)ptr) + n); - - // CHECK: KLEE: ERROR: {{.*}}runtime/Sanitizer/ubsan/ubsan_handlers.cpp:{{[0-9]+}}: misaligned-pointer-use - *ptr = 20; - - return 0; -} diff --git a/test/Feature/types/pointers-alignment/EffectiveTypePointerAlignment.c b/test/Feature/types/pointers-alignment/EffectiveTypePointerAlignment.c deleted file mode 100644 index ba52fd624c..0000000000 --- a/test/Feature/types/pointers-alignment/EffectiveTypePointerAlignment.c +++ /dev/null @@ -1,26 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -fsanitize=alignment,null -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-advanced-type-system --use-tbaa --use-lazy-initialization=none --align-symbolic-pointers=true --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include - -int main() { - int outer_int_value; - double outer_float_value; - - void *area = malloc(sizeof(int *) + sizeof(double *)); - - int **int_place = area; - double **double_place = area + sizeof(int *); - - *int_place = 0; - *double_place = 0; - - klee_make_symbolic(area, sizeof(int *) + sizeof(double *), "area"); - - // CHECK-NOT: EffectiveTypePointerAlignment.c:[[@LINE+1]]: either misaligned address for 0x{{.*}} or invalid usage of address 0x{{.*}} with insufficient space - **int_place = 10; - // CHECK-NOT: EffectiveTypePointerAlignment.c:[[@LINE+1]]: either misaligned address for 0x{{.*}} or invalid usage of address 0x{{.*}} with insufficient space - **double_place = 20; -} diff --git a/test/Feature/types/pointers-alignment/StructurePointerAlignment.c b/test/Feature/types/pointers-alignment/StructurePointerAlignment.c deleted file mode 100644 index 452ffebfdc..0000000000 --- a/test/Feature/types/pointers-alignment/StructurePointerAlignment.c +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -fsanitize=alignment,null -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --ubsan-runtime --use-advanced-type-system --use-tbaa --use-lazy-initialization=all --align-symbolic-pointers=true --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include - -struct Node { - struct Node *next; - int x; -}; - -void foo(struct Node *head) { - if (head->next) { - // CHECK-DAG: x - printf("x\n"); - // CHECK-NOT: StructurePointerAlignment.c:[[@LINE+1]]: either misaligned address for 0x{{.*}} or invalid usage of address 0x{{.*}} with insufficient space - head->next->x = 100; - } else { - // CHECK-DAG: y - printf("y\n"); - } -} - -int main() { - struct Node head; - klee_make_symbolic(&head, sizeof(head), "head"); - klee_prefer_cex(&head, head.x >= -10 & head.x <= 10); - foo(&head); - return 0; -} diff --git a/test/Feature/types/pointers-alignment/StructurePointerWithOffsetAlignment.c b/test/Feature/types/pointers-alignment/StructurePointerWithOffsetAlignment.c deleted file mode 100644 index 9fffde0325..0000000000 --- a/test/Feature/types/pointers-alignment/StructurePointerWithOffsetAlignment.c +++ /dev/null @@ -1,35 +0,0 @@ -// RUN: %clang %s -emit-llvm -g -c -fsanitize=alignment,null -o %t.bc -// RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --ubsan-runtime --use-advanced-type-system --use-tbaa --use-lazy-initialization=all --align-symbolic-pointers=true --use-gep-opt %t.bc 2>&1 | FileCheck %s - -#include "klee/klee.h" -#include - -struct Node { - struct Node *next; - int x; -}; - -void foo(struct Node *head, int n) { - char *pointer = head->next; - pointer += n; - head = (struct Node *)pointer; - - if ((n & (sizeof(int) - 1)) == 0) { - // CHECK-DAG: x - printf("x\n"); - // CHECK-DAG: KLEE: ERROR: {{.*}}runtime/Sanitizer/ubsan/ubsan_handlers.cpp:{{[0-9]+}}: null-pointer-use - head->x = 100; - } else { - // CHECK-DAG: KLEE: ERROR: {{.*}}runtime/Sanitizer/ubsan/ubsan_handlers.cpp:{{[0-9]+}}: misaligned-pointer-use - head->x = 100; - } -} - -int main() { - struct Node head; - klee_make_symbolic(&head, sizeof(head), "head"); - int n = klee_range(0, 4, "n"); - foo(&head, n); - return 0; -} From 40a4dd01cf83a2d86b07f7825bbe365b29d61550 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 14 Aug 2024 20:06:56 +0200 Subject: [PATCH 17/40] fix: --- build.sh | 2 +- include/klee/Core/MockBuilder.h | 8 ++- lib/Core/CXXTypeSystem/CXXTypeManager.cpp | 13 ++++- lib/Core/Executor.cpp | 12 +--- lib/Core/MockBuilder.cpp | 68 ++++++++++++++++++----- lib/Core/TypeManager.cpp | 10 ++++ lib/Expr/Expr.cpp | 1 + lib/Module/CallSplitter.cpp | 6 ++ lib/Module/FunctionAlias.cpp | 1 + lib/Module/ReturnSplitter.cpp | 6 ++ tools/klee/CMakeLists.txt | 2 +- unittests/Ref/RefTest.cpp | 3 - 12 files changed, 99 insertions(+), 33 deletions(-) diff --git a/build.sh b/build.sh index e716cd7b63..5e03c320e0 100755 --- a/build.sh +++ b/build.sh @@ -65,7 +65,7 @@ if [ "$1" = "--debug" ] || [ "$1" = "-g" ]; then ENABLE_OPTIMIZED=0 ENABLE_DEBUG=1 KLEE_RUNTIME_BUILD="Debug+Asserts" - ENABLE_WARNINGS_AS_ERRORS=0 + ENABLE_WARNINGS_AS_ERRORS=1 shift 1 else KEEP_PARSE="false" diff --git a/include/klee/Core/MockBuilder.h b/include/klee/Core/MockBuilder.h index da5d0ea198..34fc81502d 100644 --- a/include/klee/Core/MockBuilder.h +++ b/include/klee/Core/MockBuilder.h @@ -12,8 +12,10 @@ #include "klee/Core/Interpreter.h" #include "klee/Module/Annotation.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" #include #include @@ -58,7 +60,7 @@ class MockBuilder { llvm::Function *func, const std::set &properties); std::map getExternalFunctions(); - std::map getExternalGlobals(); + std::map getExternalGlobals(); std::pair goByOffset(llvm::Value *value, const std::vector &offset); @@ -74,10 +76,10 @@ class MockBuilder { std::set &mainModuleGlobals); std::unique_ptr build(); - void buildAllocSource(llvm::Value *prev, llvm::Type *elemType, + void buildAllocSource(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr); void buildFree(llvm::Value *elem, const Statement::Free *freePtr); - void processingValue(llvm::Value *prev, llvm::Type *elemType, + void processingValue(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr, bool initNullPtr); }; diff --git a/lib/Core/CXXTypeSystem/CXXTypeManager.cpp b/lib/Core/CXXTypeSystem/CXXTypeManager.cpp index af2ad81c4d..b41c89a857 100644 --- a/lib/Core/CXXTypeSystem/CXXTypeManager.cpp +++ b/lib/Core/CXXTypeSystem/CXXTypeManager.cpp @@ -9,6 +9,7 @@ #include "klee/Module/KModule.h" #include "klee/Module/KType.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Metadata.h" @@ -231,9 +232,15 @@ ref cxxtypes::KCXXType::getContentRestrictions(ref object) const { if (type == nullptr) { return nullptr; } +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + llvm::Type *elementType = type->getNonOpaquePointerElementType(); + return llvm::cast(parent->getWrappedType(elementType)) + ->getPointersRestrictions(object); +#else llvm::Type *elementType = type->getPointerElementType(); return llvm::cast(parent->getWrappedType(elementType)) ->getPointersRestrictions(object); +#endif } ref cxxtypes::KCXXType::getPointersRestrictions(ref) const { @@ -641,9 +648,13 @@ cxxtypes::KCXXPointerType::KCXXPointerType(llvm::Type *type, TypeManager *parent) : KCXXType(type, parent) { typeKind = CXXTypeKind::POINTER; - +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + elementType = cast( + parent->getWrappedType(type->getNonOpaquePointerElementType())); +#else elementType = cast(parent->getWrappedType(type->getPointerElementType())); +#endif } bool cxxtypes::KCXXPointerType::isAccessableFrom( diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 45008ab6e3..8d6d5032e2 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -15,7 +15,9 @@ #include "DistanceCalculator.h" #include "ExecutionState.h" #include "ExternalDispatcher.h" +#if LLVM_VERSION_CODE <= LLVM_VERSION(14, 0) #include "GetElementPtrTypeIterator.h" +#endif #include "ImpliedValue.h" #include "Memory.h" #include "MemoryManager.h" @@ -3610,16 +3612,6 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { result = FPToX87FP80Ext(result); } - if (castToType->isPointerTy()) { - castToType = castToType->getPointerElementType(); - if (ref pointer = cast(makePointer(result))) { - ref base = pointer->getBase(); - if (state.isGEPExpr(base)) { - state.gepExprBases[base] = castToType; - } - } - } - bindLocal(ki, state, result); break; } diff --git a/lib/Core/MockBuilder.cpp b/lib/Core/MockBuilder.cpp index 5c82feee13..eb46968036 100644 --- a/lib/Core/MockBuilder.cpp +++ b/lib/Core/MockBuilder.cpp @@ -13,8 +13,11 @@ #include "klee/Support/ErrorHandling.h" #include "klee/Support/ModuleUtil.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" #include @@ -69,12 +72,13 @@ MockBuilder::getExternalFunctions() { return externals; } -std::map MockBuilder::getExternalGlobals() { - std::map externals; +std::map +MockBuilder::getExternalGlobals() { + std::map externals; for (const auto &global : userModule->globals()) { if (global.isDeclaration() && !ignoredExternals.count(global.getName().str())) { - externals.insert(std::make_pair(global.getName(), global.getType())); + externals.insert(std::make_pair(global.getName(), &global)); } } removeAliases(userModule, externals); @@ -202,7 +206,7 @@ void MockBuilder::buildMockMain() { void MockBuilder::buildExternalGlobalsDefinitions() { auto externalGlobals = getExternalGlobals(); for (const auto &[extName, type] : externalGlobals) { - auto elementType = type->getPointerElementType(); + auto elementType = type->getValueType(); klee_message("Mocking external variable %s", extName.c_str()); llvm::GlobalVariable *global = dyn_cast_or_null( mockModule->getOrInsertGlobal(extName, elementType)); @@ -304,8 +308,12 @@ MockBuilder::goByOffset(llvm::Value *value, klee_error("Incorrect annotation offset."); } prev = current; +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + current = builder->CreateLoad(current->getType(), current); +#else current = builder->CreateLoad(current->getType()->getPointerElementType(), current); +#endif } else if (inst == "&") { auto addr = builder->CreateAlloca(current->getType()); prev = current; @@ -329,10 +337,17 @@ inline llvm::Type *getTypeByOffset(llvm::Type *value, llvm::Type *current = value; for (const auto &inst : offset) { if (inst == "*") { +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + if (!current->isPointerTy() || current->isOpaquePointerTy()) { + return nullptr; + } + current = current->getNonOpaquePointerElementType(); +#else if (!current->isPointerTy()) { return nullptr; } current = current->getPointerElementType(); +#endif } else if (inst == "&") { // Not change } else { @@ -460,10 +475,18 @@ void MockBuilder::buildAnnotationForExternalFunctionArgs( builder->CreateCondBr(brValue, derefBB, contBB); builder->SetInsertPoint(derefBB); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + builder->CreateLoad(elem->getType(), elem); +#else builder->CreateLoad(elem->getType()->getPointerElementType(), elem); +#endif builder->CreateBr(contBB); +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + curFunc->insert(curFunc->end(), contBB); +#else curFunc->getBasicBlockList().push_back(contBB); +#endif builder->SetInsertPoint(contBB); break; } @@ -504,12 +527,12 @@ void MockBuilder::buildAnnotationForExternalFunctionArgs( if (freePtr) { buildFree(elem, freePtr); } - processingValue(prev, elem->getType(), allocSourcePtr, initNullPtr); + processingValue(prev, elem, allocSourcePtr, initNullPtr); } } } -void MockBuilder::processingValue(llvm::Value *prev, llvm::Type *elemType, +void MockBuilder::processingValue(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr, bool initNullPtr) { if (initNullPtr) { @@ -529,32 +552,49 @@ void MockBuilder::processingValue(llvm::Value *prev, llvm::Type *elemType, llvm::BasicBlock::Create(ctx, "allocArg", curFunc); builder->CreateCondBr(brValue, allocBB, initNullBB); builder->SetInsertPoint(allocBB); - buildAllocSource(prev, elemType, allocSourcePtr); + buildAllocSource(prev, elem, allocSourcePtr); builder->CreateBr(contBB); } else { builder->CreateCondBr(brValue, initNullBB, contBB); } +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + curFunc->insert(curFunc->end(), initNullBB); +#else curFunc->getBasicBlockList().push_back(initNullBB); +#endif builder->SetInsertPoint(initNullBB); - builder->CreateStore( - llvm::ConstantPointerNull::get(llvm::cast(elemType)), - prev); + builder->CreateStore(llvm::ConstantPointerNull::get( + llvm::cast(elem->getType())), + prev); builder->CreateBr(contBB); +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + curFunc->insert(curFunc->end(), contBB); +#else curFunc->getBasicBlockList().push_back(contBB); +#endif builder->SetInsertPoint(contBB); } else if (allocSourcePtr) { - buildAllocSource(prev, elemType, allocSourcePtr); + buildAllocSource(prev, elem, allocSourcePtr); } } -void MockBuilder::buildAllocSource(llvm::Value *prev, llvm::Type *elemType, +void MockBuilder::buildAllocSource(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr) { if (allocSourcePtr->value != Statement::Alloc::ALLOC) { klee_warning("Annotation: AllocSource \"%d\" not implemented use alloc", allocSourcePtr->value); } - auto valueType = elemType->getPointerElementType(); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + auto valueType = elem->getType(); + if (isa(elem) || isa(elem)) { + valueType = llvm::getLoadStoreType(elem); + } else if (auto func = dyn_cast(elem)) { + valueType = func->getFunctionType(); + } +#else + auto valueType = elem->getType()->getPointerElementType(); +#endif auto sizeValue = llvm::ConstantInt::get( ctx, llvm::APInt(64, mockModule->getDataLayout().getTypeStoreSize(valueType), @@ -627,7 +667,7 @@ void MockBuilder::buildAnnotationForExternalFunctionReturn( llvm::Value *retValuePtr = builder->CreateAlloca(returnType, nullptr); if (returnType->isPointerTy() && (allocSourcePtr || mustInitNull)) { - processingValue(retValuePtr, returnType, allocSourcePtr, + processingValue(retValuePtr, func, allocSourcePtr, mustInitNull || maybeInitNull); } else { buildCallKleeMakeSymbolic("klee_make_mock", retValuePtr, returnType, diff --git a/lib/Core/TypeManager.cpp b/lib/Core/TypeManager.cpp index 490ffc3e32..ae7205d9e8 100644 --- a/lib/Core/TypeManager.cpp +++ b/lib/Core/TypeManager.cpp @@ -32,9 +32,15 @@ KType *TypeManager::getWrappedType(llvm::Type *type) { if (typesMap.count(type) == 0) { types.emplace_back(new KType(type, this)); typesMap.emplace(type, types.back().get()); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + if (type && type->isPointerTy() && !type->isOpaquePointerTy()) { + getWrappedType(type->getNonOpaquePointerElementType()); + } +#else if (type && type->isPointerTy()) { getWrappedType(type->getPointerElementType()); } +#endif if (type && type->isArrayTy()) { getWrappedType(type->getArrayElementType()); } @@ -167,7 +173,11 @@ void TypeManager::initTypeInfo() { for (auto &type : types) { llvm::Type *rawType = type->getRawType(); if (rawType && rawType->isSized()) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) + type->alignment = parent->targetData->getABITypeAlign(rawType).value(); +#else type->alignment = parent->targetData->getABITypeAlignment(rawType); +#endif type->typeStoreSize = parent->targetData->getTypeStoreSize(rawType); } } diff --git a/lib/Expr/Expr.cpp b/lib/Expr/Expr.cpp index e6e4a03ea7..7b0c4d0a4d 100644 --- a/lib/Expr/Expr.cpp +++ b/lib/Expr/Expr.cpp @@ -30,6 +30,7 @@ #include #include +#include #include using namespace klee; diff --git a/lib/Module/CallSplitter.cpp b/lib/Module/CallSplitter.cpp index 0a33411e5d..c1c05ce1fa 100644 --- a/lib/Module/CallSplitter.cpp +++ b/lib/Module/CallSplitter.cpp @@ -9,6 +9,8 @@ #include "Passes.h" +#include "klee/Config/Version.h" + #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -20,7 +22,11 @@ namespace klee { char CallSplitter::ID = 0; bool CallSplitter::runOnFunction(Function &F) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + unsigned n = F.size(); +#else unsigned n = F.getBasicBlockList().size(); +#endif BasicBlock **blocks = new BasicBlock *[n]; unsigned i = 0; for (llvm::Function::iterator bbit = F.begin(), bbie = F.end(); bbit != bbie; diff --git a/lib/Module/FunctionAlias.cpp b/lib/Module/FunctionAlias.cpp index f91fcf3dc0..f8fe004de0 100644 --- a/lib/Module/FunctionAlias.cpp +++ b/lib/Module/FunctionAlias.cpp @@ -14,6 +14,7 @@ #include "klee/Support/ErrorHandling.h" #include "klee/Support/OptionCategories.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Regex.h" diff --git a/lib/Module/ReturnSplitter.cpp b/lib/Module/ReturnSplitter.cpp index 21b89fd566..92484cf398 100644 --- a/lib/Module/ReturnSplitter.cpp +++ b/lib/Module/ReturnSplitter.cpp @@ -10,6 +10,8 @@ #include "Passes.h" +#include "klee/Config/Version.h" + #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -21,7 +23,11 @@ namespace klee { char ReturnSplitter::ID = 0; bool ReturnSplitter::runOnFunction(Function &F) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) + unsigned n = F.size(); +#else unsigned n = F.getBasicBlockList().size(); +#endif BasicBlock **blocks = new BasicBlock *[n]; unsigned i = 0; for (llvm::Function::iterator bbit = F.begin(), bbie = F.end(); bbit != bbie; diff --git a/tools/klee/CMakeLists.txt b/tools/klee/CMakeLists.txt index 5d63f93901..d54ee27372 100644 --- a/tools/klee/CMakeLists.txt +++ b/tools/klee/CMakeLists.txt @@ -15,7 +15,7 @@ set(KLEE_LIBS ) target_link_libraries(klee ${KLEE_LIBS}) -target_include_directories(klee PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) +target_include_directories(klee SYSTEM PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) target_compile_options(klee PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(klee PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) diff --git a/unittests/Ref/RefTest.cpp b/unittests/Ref/RefTest.cpp index 64c3956606..c9ca495f71 100644 --- a/unittests/Ref/RefTest.cpp +++ b/unittests/Ref/RefTest.cpp @@ -94,11 +94,8 @@ TEST(RefTest, SelfMove) { struct Expr *r_e = new Expr(); ref r(r_e); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wself-move" // Check self move r = std::move(r); -#pragma GCC diagnostic pop finished = 1; } EXPECT_EQ(1, finished_counter); From 77b841703aff0b7cc5f90a5ac88433b26829f9bc Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 15 Aug 2024 14:43:41 +0200 Subject: [PATCH 18/40] fix: --- lib/Core/CXXTypeSystem/CXXTypeManager.cpp | 713 ---------------------- lib/Core/TypeManager.cpp | 202 ------ 2 files changed, 915 deletions(-) delete mode 100644 lib/Core/CXXTypeSystem/CXXTypeManager.cpp delete mode 100644 lib/Core/TypeManager.cpp diff --git a/lib/Core/CXXTypeSystem/CXXTypeManager.cpp b/lib/Core/CXXTypeSystem/CXXTypeManager.cpp deleted file mode 100644 index b41c89a857..0000000000 --- a/lib/Core/CXXTypeSystem/CXXTypeManager.cpp +++ /dev/null @@ -1,713 +0,0 @@ -#include "CXXTypeManager.h" -#include "../Memory.h" -#include "../TypeManager.h" - -#include "klee/Expr/Constraints.h" -#include "klee/Expr/Expr.h" - -#include "klee/Core/Context.h" -#include "klee/Module/KModule.h" -#include "klee/Module/KType.h" - -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/IR/DebugInfoMetadata.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Metadata.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/Support/Casting.h" - -#include -#include -#include - -using namespace llvm; -using namespace klee; - -enum { DEMANGLER_BUFFER_SIZE = 4096, METADATA_SIZE = 16 }; - -CXXTypeManager::CXXTypeManager(KModule *parent) : TypeManager(parent) {} - -/** - * Factory method for KTypes. Note, that as there is no vector types in - * C++, we interpret their type as their elements type. - */ -KType *CXXTypeManager::getWrappedType(llvm::Type *type) { - if (typesMap.count(type) == 0) { - cxxtypes::KCXXType *kt = nullptr; - - /* Special case when type is unknown */ - if (type == nullptr) { - kt = new cxxtypes::KCXXType(type, this); - } else { - /* Vector types are considered as their elements type */ - llvm::Type *unwrappedRawType = type; - if (unwrappedRawType->isVectorTy()) { - unwrappedRawType = - llvm::cast(unwrappedRawType)->getElementType(); - } - - switch (unwrappedRawType->getTypeID()) { - case (llvm::Type::StructTyID): - kt = new cxxtypes::KCXXStructType(unwrappedRawType, this); - break; - case (llvm::Type::IntegerTyID): - kt = new cxxtypes::KCXXIntegerType(unwrappedRawType, this); - break; - case (llvm::Type::PPC_FP128TyID): - case (llvm::Type::FP128TyID): - case (llvm::Type::X86_FP80TyID): - case (llvm::Type::DoubleTyID): - case (llvm::Type::FloatTyID): - kt = new cxxtypes::KCXXFloatingPointType(unwrappedRawType, this); - break; - case (llvm::Type::ArrayTyID): - kt = new cxxtypes::KCXXArrayType(unwrappedRawType, this); - break; - case (llvm::Type::FunctionTyID): - kt = new cxxtypes::KCXXFunctionType(unwrappedRawType, this); - break; - case (llvm::Type::PointerTyID): - kt = new cxxtypes::KCXXPointerType(unwrappedRawType, this); - break; - default: - kt = new cxxtypes::KCXXType(unwrappedRawType, this); - } - } - - types.emplace_back(kt); - typesMap.emplace(type, kt); - } - return typesMap[type]; -} - -/** - * We think about allocated memory as a memory without effective type, - * i.e. with llvm::Type == nullptr. - */ -KType *CXXTypeManager::handleAlloc(ref size) { - cxxtypes::KCXXCompositeType *compositeType = - new cxxtypes::KCXXCompositeType(getUnknownType(), this, size); - types.emplace_back(compositeType); - return compositeType; -} - -/** - * Creates a new type from this: copy all types from given - * type, which lie in segment [address, addres + size). - */ -KType *CXXTypeManager::handleRealloc(KType *type, ref size) { - /** - * C standard says that realloc can be called on memory, that were allocated - * using malloc, calloc, memalign, or realloc. Therefore, let's fail execution - * if this did not get appropriate pointer. - */ - cxxtypes::KCXXCompositeType *reallocFromType = - dyn_cast(type); - assert(reallocFromType && "handleRealloc called on non CompositeType"); - - cxxtypes::KCXXCompositeType *resultType = - dyn_cast(handleAlloc(size)); - assert(resultType && "handleAlloc returned non CompositeType"); - - /** - * If we make realloc from simplified composite type or - * allocated object with symbolic size, we will just return previous, - * as we do not care about inner structure of given type anymore. - */ - resultType->containsSymbolic = reallocFromType->containsSymbolic; - ref constantSize = llvm::dyn_cast(size); - if (reallocFromType->containsSymbolic || !constantSize) { - resultType->insertedTypes = reallocFromType->insertedTypes; - return resultType; - } - - size_t sizeValue = constantSize->getZExtValue(); - for (auto offsetToTypeSizePair = reallocFromType->typesLocations.begin(), - itEnd = reallocFromType->typesLocations.end(); - offsetToTypeSizePair != itEnd; ++offsetToTypeSizePair) { - size_t prevOffset = offsetToTypeSizePair->first; - KType *prevType = offsetToTypeSizePair->second.first; - size_t prevSize = offsetToTypeSizePair->second.second; - - if (prevOffset < sizeValue) { - resultType->handleMemoryAccess( - prevType, - ConstantExpr::alloc(prevOffset, Context::get().getPointerWidth()), - ConstantExpr::alloc(prevSize, Context::get().getPointerWidth()), - false); - } - } - return resultType; -} - -void CXXTypeManager::onFinishInitModule() { - /* Here we try to get additional information from metadata - for unions declared in global scope: we iterate through all - metadata nodes availible for declarations until we meet one - with type information. Then we check it tag. */ - for (auto &global : parent->module->globals()) { - llvm::SmallVector - globalVariableInfo; - global.getDebugInfo(globalVariableInfo); - for (auto metaNode : globalVariableInfo) { - llvm::DIGlobalVariable *variable = metaNode->getVariable(); - if (!variable) { - continue; - } - - llvm::DIType *type = variable->getType(); - - if (!type) { - continue; - } - - if (type->getTag() == dwarf::Tag::DW_TAG_union_type) { - KType *kt = getWrappedType(global.getValueType()); - llvm::cast(kt)->isUnion = true; - } - - break; - } - } -} - -/** - * Util method to create constraints for pointers - * for complex structures that can have many types located - * by different offsets. - */ -static ref getComplexPointerRestrictions( - ref object, - const std::vector> &offsetsToTypes) { - ConstraintSet restrictions; - ref resultCondition; - for (auto &offsetToTypePair : offsetsToTypes) { - size_t offset = offsetToTypePair.first; - KType *extractedType = offsetToTypePair.second; - - ref extractedOffset = ExtractExpr::create( - object, offset * CHAR_BIT, extractedType->getSize() * CHAR_BIT); - ref innerAlignmentRequirement = - llvm::cast(extractedType) - ->getPointersRestrictions(extractedOffset); - if (innerAlignmentRequirement.isNull()) { - continue; - } - restrictions.addConstraint(innerAlignmentRequirement); - } - - auto simplified = Simplificator::simplify(restrictions.cs()); - if (simplified.wasSimplified) { - restrictions.changeCS(simplified.simplified); - } - for (auto restriction : restrictions.cs()) { - if (resultCondition.isNull()) { - resultCondition = restriction; - } else { - resultCondition = AndExpr::create(resultCondition, restriction); - } - } - return resultCondition; -} - -/* C++ KType base class */ -cxxtypes::KCXXType::KCXXType(llvm::Type *type, TypeManager *parent) - : KType(type, parent) { - typeSystemKind = TypeSystemKind::Advanced; - typeKind = DEFAULT; -} - -bool cxxtypes::KCXXType::isAccessableFrom(KCXXType *) const { return true; } - -bool cxxtypes::KCXXType::isAccessableFrom(KType *accessingType) const { - KCXXType *accessingCXXType = dyn_cast_or_null(accessingType); - assert(accessingCXXType && - "Attempted to compare raw llvm type with C++ type!"); - return isAccessingFromChar(accessingCXXType) || - isAccessableFrom(accessingCXXType); -} - -ref cxxtypes::KCXXType::getContentRestrictions(ref object) const { - if (type == nullptr) { - return nullptr; - } -#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - llvm::Type *elementType = type->getNonOpaquePointerElementType(); - return llvm::cast(parent->getWrappedType(elementType)) - ->getPointersRestrictions(object); -#else - llvm::Type *elementType = type->getPointerElementType(); - return llvm::cast(parent->getWrappedType(elementType)) - ->getPointersRestrictions(object); -#endif -} - -ref cxxtypes::KCXXType::getPointersRestrictions(ref) const { - return nullptr; -} - -bool cxxtypes::KCXXType::isAccessingFromChar(KCXXType *accessingType) { - /* Special case for unknown type */ - if (accessingType->getRawType() == nullptr) { - return true; - } - - assert(llvm::isa(accessingType) && - "Attempt to access to a memory via non-pointer type"); - - return llvm::cast(accessingType)->isPointerToChar(); -} - -cxxtypes::CXXTypeKind cxxtypes::KCXXType::getTypeKind() const { - return typeKind; -} - -bool cxxtypes::KCXXType::classof(const KType *requestedType) { - return requestedType->getTypeSystemKind() == TypeSystemKind::Advanced; -} - -/* Composite type */ -cxxtypes::KCXXCompositeType::KCXXCompositeType(KType *type, TypeManager *parent, - ref objectSize) - : KCXXType(type->getRawType(), parent) { - typeKind = CXXTypeKind::COMPOSITE; - - if (ref CE = llvm::dyn_cast(objectSize)) { - size_t size = CE->getZExtValue(); - if (type->getRawType() == nullptr) { - ++nonTypedMemorySegments[size]; - } - typesLocations[0] = std::make_pair(type, size); - } else { - containsSymbolic = true; - } - insertedTypes.emplace(type); -} - -ref -cxxtypes::KCXXCompositeType::getPointersRestrictions(ref object) const { - if (containsSymbolic) { - return nullptr; - } - std::vector> offsetToTypes; - for (auto &offsetToTypePair : typesLocations) { - offsetToTypes.emplace_back(offsetToTypePair.first, - offsetToTypePair.second.first); - } - return getComplexPointerRestrictions(object, offsetToTypes); -} - -void cxxtypes::KCXXCompositeType::handleMemoryAccess(KType *type, - ref offset, - ref size, - bool isWrite) { - if (cxxtypes::KCXXPointerType *pointerType = - llvm::dyn_cast(type)) { - if (isWrite && pointerType->isPointerToChar()) { - return; - } - } - - /* - * We want to check adjacent types to ensure, that we did not overlapped - * nothing, and if we overlapped, move bounds for types or even remove them. - */ - ref offsetConstant = dyn_cast(offset); - ref sizeConstant = dyn_cast(size); - - if (offsetConstant && sizeConstant && !containsSymbolic) { - size_t offsetValue = offsetConstant->getZExtValue(); - size_t sizeValue = sizeConstant->getZExtValue(); - - /* We support C-style principle of effective type. - This might be not appropriate for C++, as C++ has - "placement new" operator, but in case of C it is OK. - Therefore we assume, that we write in memory with no - effective type, i.e. do not overloap objects placed in this - object before. */ - - auto it = std::prev(typesLocations.upper_bound(offsetValue)); - - /* We do not overwrite types in memory */ - if (it->second.first->getRawType() != nullptr) { - return; - } - if (std::next(it) != typesLocations.end() && - std::next(it)->first < offsetValue + sizeValue) { - return; - } - - size_t tail = 0; - - size_t prevOffsetValue = it->first; - size_t prevSizeValue = it->second.second; - - /* Calculate number of non-typed bytes after object */ - if (prevOffsetValue + prevSizeValue > offsetValue + sizeValue) { - tail = (prevOffsetValue + prevSizeValue) - (offsetValue + sizeValue); - } - - /* We will possibly cut this object belowe. So let's - decrease counter immediately */ - if (--nonTypedMemorySegments[prevSizeValue] == 0) { - nonTypedMemorySegments.erase(prevSizeValue); - } - - /* Calculate space remaining for non-typed memory in the beginning */ - if (offsetValue - prevOffsetValue != 0) { - it->second.second = - std::min(prevSizeValue, offsetValue - prevOffsetValue); - ++nonTypedMemorySegments[prevSizeValue]; - } else { - typesLocations.erase(it); - } - - typesLocations[offsetValue] = std::make_pair(type, sizeValue); - if (typesLocations.count(offsetValue + sizeValue) == 0 && tail != 0) { - ++nonTypedMemorySegments[tail]; - typesLocations[offsetValue + sizeValue] = - std::make_pair(parent->getUnknownType(), tail); - } - - if (nonTypedMemorySegments.empty()) { - insertedTypes.erase(parent->getUnknownType()); - } - } else { - /* - * If we have written object by a symbolic address, we will use - * simplified representation for Composite Type, as it is too - * dificult to determine relative location of objects in memory - * (requires query the solver at least). - */ - containsSymbolic = true; - } - /* We do not want to add nullptr type to composite type */ - if (type->getRawType() != nullptr) { - insertedTypes.emplace(type); - } -} - -bool cxxtypes::KCXXCompositeType::isAccessableFrom( - KCXXType *accessingType) const { - for (auto &it : insertedTypes) { - if (it->isAccessableFrom(accessingType)) { - return true; - } - } - return false; -} - -bool cxxtypes::KCXXCompositeType::classof(const KType *requestedType) { - return llvm::isa(requestedType) && - llvm::cast(requestedType)->getTypeKind() == - cxxtypes::CXXTypeKind::COMPOSITE; -} - -/* Integer type */ -cxxtypes::KCXXIntegerType::KCXXIntegerType(llvm::Type *type, - TypeManager *parent) - : KCXXType(type, parent) { - typeKind = CXXTypeKind::INTEGER; -} - -bool cxxtypes::KCXXIntegerType::isAccessableFrom( - KCXXType *accessingType) const { - if (llvm::isa(accessingType)) { - return innerIsAccessableFrom(cast(accessingType)); - } - return innerIsAccessableFrom(accessingType); -} - -bool cxxtypes::KCXXIntegerType::innerIsAccessableFrom( - KCXXType *accessingType) const { - return accessingType->getRawType() == nullptr; -} - -bool cxxtypes::KCXXIntegerType::innerIsAccessableFrom( - KCXXIntegerType *accessingType) const { - return accessingType->type == type; -} - -bool cxxtypes::KCXXIntegerType::classof(const KType *requestedType) { - return llvm::isa(requestedType) && - llvm::cast(requestedType)->getTypeKind() == - cxxtypes::CXXTypeKind::INTEGER; -} - -/* Floating point type */ -cxxtypes::KCXXFloatingPointType::KCXXFloatingPointType(llvm::Type *type, - TypeManager *parent) - : KCXXType(type, parent) { - typeKind = CXXTypeKind::FP; -} - -bool cxxtypes::KCXXFloatingPointType::isAccessableFrom( - KCXXType *accessingType) const { - if (llvm::isa(accessingType)) { - return innerIsAccessableFrom(cast(accessingType)); - } - return innerIsAccessableFrom(accessingType); -} - -bool cxxtypes::KCXXFloatingPointType::innerIsAccessableFrom( - KCXXType *accessingType) const { - return accessingType->getRawType() == nullptr; -} - -bool cxxtypes::KCXXFloatingPointType::innerIsAccessableFrom( - KCXXFloatingPointType *accessingType) const { - return accessingType->getRawType() == type; -} - -bool cxxtypes::KCXXFloatingPointType::classof(const KType *requestedType) { - return llvm::isa(requestedType) && - llvm::cast(requestedType)->getTypeKind() == - cxxtypes::CXXTypeKind::FP; -} - -/* Struct type */ -cxxtypes::KCXXStructType::KCXXStructType(llvm::Type *type, TypeManager *parent) - : KCXXType(type, parent) { - typeKind = CXXTypeKind::STRUCT; - /* Hard coded union identification, as we can not always - get this info from metadata. */ - llvm::StructType *structType = llvm::cast(type); - if (structType->hasName()) { - isUnion = structType->getStructName().startswith("union."); - } -} - -ref -cxxtypes::KCXXStructType::getPointersRestrictions(ref object) const { - std::vector> offsetsToTypes; - for (auto &innerTypeToOffsets : innerTypes) { - KType *innerType = innerTypeToOffsets.first; - if (!llvm::isa(innerType)) { - continue; - } - for (auto &offset : innerTypeToOffsets.second) { - offsetsToTypes.emplace_back(offset, innerType); - } - } - return getComplexPointerRestrictions(object, offsetsToTypes); -} - -bool cxxtypes::KCXXStructType::isAccessableFrom(KCXXType *accessingType) const { - /* FIXME: this is a temporary hack for vtables in C++. Ideally, we - * should demangle global variables to get additional info, at least - * that global object is "special" (here it is about vtable). - */ - if (llvm::isa(accessingType) && - llvm::cast(accessingType)->isPointerToFunction()) { - return true; - } - - if (isUnion) { - return true; - } - - for (auto &innerTypesToOffsets : innerTypes) { - KCXXType *innerType = cast(innerTypesToOffsets.first); - - /* To prevent infinite recursion */ - if (isa(innerType)) { - if (innerType == accessingType) { - return true; - } - } else if (innerType->isAccessableFrom(accessingType)) { - return true; - } - } - return false; -} - -bool cxxtypes::KCXXStructType::classof(const KType *requestedType) { - return llvm::isa(requestedType) && - llvm::cast(requestedType)->getTypeKind() == - cxxtypes::CXXTypeKind::STRUCT; -} - -/* Array type */ -cxxtypes::KCXXArrayType::KCXXArrayType(llvm::Type *type, TypeManager *parent) - : KCXXType(type, parent) { - typeKind = CXXTypeKind::ARRAY; - - llvm::Type *rawArrayType = llvm::cast(type); - KType *elementKType = - parent->getWrappedType(rawArrayType->getArrayElementType()); - assert(llvm::isa(elementKType) && - "Type manager returned non CXX type for array element"); - elementType = cast(elementKType); - arrayElementsCount = rawArrayType->getArrayNumElements(); -} - -ref -cxxtypes::KCXXArrayType::getPointersRestrictions(ref object) const { - std::vector> offsetsToTypes; - for (unsigned idx = 0; idx < arrayElementsCount; ++idx) { - offsetsToTypes.emplace_back(idx * elementType->getSize(), elementType); - } - return getComplexPointerRestrictions(object, offsetsToTypes); -} - -bool cxxtypes::KCXXArrayType::isAccessableFrom(KCXXType *accessingType) const { - if (llvm::isa(accessingType)) { - return innerIsAccessableFrom(llvm::cast(accessingType)); - } - return innerIsAccessableFrom(accessingType); -} - -bool cxxtypes::KCXXArrayType::innerIsAccessableFrom( - KCXXType *accessingType) const { - return (accessingType->getRawType() == nullptr) || - elementType->isAccessableFrom(accessingType); -} - -bool cxxtypes::KCXXArrayType::innerIsAccessableFrom( - KCXXArrayType *accessingType) const { - /* Arrays of unknown size in llvm has 1 element inside */ - return (arrayElementsCount == accessingType->arrayElementsCount || - arrayElementsCount == 1 || accessingType->arrayElementsCount == 1) && - elementType->isAccessableFrom(accessingType->elementType); -} - -bool cxxtypes::KCXXArrayType::classof(const KType *requestedType) { - return llvm::isa(requestedType) && - llvm::cast(requestedType)->getTypeKind() == - cxxtypes::CXXTypeKind::ARRAY; -} - -/* Function type */ -cxxtypes::KCXXFunctionType::KCXXFunctionType(llvm::Type *type, - TypeManager *parent) - : KCXXType(type, parent) { - typeKind = CXXTypeKind::FUNCTION; - - assert(type->isFunctionTy() && - "Given non-function type to construct KFunctionType!"); - llvm::FunctionType *function = llvm::cast(type); - returnType = llvm::dyn_cast( - parent->getWrappedType(function->getReturnType())); - assert(returnType != nullptr && "Type manager returned non CXXKType"); - - for (auto argType : function->params()) { - KType *argKType = parent->getWrappedType(argType); - assert(llvm::isa(argKType) && - "Type manager return non CXXType for function argument"); - arguments.push_back(cast(argKType)); - } -} - -bool cxxtypes::KCXXFunctionType::isAccessableFrom( - KCXXType *accessingType) const { - if (llvm::isa(accessingType)) { - return innerIsAccessableFrom(llvm::cast(accessingType)); - } - return innerIsAccessableFrom(accessingType); -} - -bool cxxtypes::KCXXFunctionType::innerIsAccessableFrom( - KCXXType *accessingType) const { - return accessingType->getRawType() == nullptr; -} - -bool cxxtypes::KCXXFunctionType::innerIsAccessableFrom( - KCXXFunctionType *accessingType) const { - unsigned currentArgCount = type->getFunctionNumParams(); - unsigned accessingArgCount = accessingType->type->getFunctionNumParams(); - - if (!type->isFunctionVarArg() && currentArgCount != accessingArgCount) { - return false; - } - - for (unsigned idx = 0; idx < std::min(currentArgCount, accessingArgCount); - ++idx) { - if (type->getFunctionParamType(idx) != - accessingType->type->getFunctionParamType(idx)) { - return false; - } - } - - /* - * FIXME: We need to check return value, but it can differ though in llvm IR. - * E.g., first member in structs is i32 (...), that can be accessed later - * by void (...). Need a research how to maintain it properly. - */ - return true; -} - -bool cxxtypes::KCXXFunctionType::classof(const KType *requestedType) { - return llvm::isa(requestedType) && - llvm::cast(requestedType)->getTypeKind() == - cxxtypes::CXXTypeKind::FUNCTION; -} - -/* Pointer type */ -cxxtypes::KCXXPointerType::KCXXPointerType(llvm::Type *type, - TypeManager *parent) - : KCXXType(type, parent) { - typeKind = CXXTypeKind::POINTER; -#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - elementType = cast( - parent->getWrappedType(type->getNonOpaquePointerElementType())); -#else - elementType = - cast(parent->getWrappedType(type->getPointerElementType())); -#endif -} - -bool cxxtypes::KCXXPointerType::isAccessableFrom( - KCXXType *accessingType) const { - if (llvm::isa(accessingType)) { - return innerIsAccessableFrom(llvm::cast(accessingType)); - } - return innerIsAccessableFrom(accessingType); -} - -bool cxxtypes::KCXXPointerType::innerIsAccessableFrom( - KCXXType *accessingType) const { - return accessingType->getRawType() == nullptr; -} - -ref -cxxtypes::KCXXPointerType::getPointersRestrictions(ref object) const { - /** - * We assume that alignment is always a power of 2 and has - * a bit representation as 00...010...00. By subtracting 1 - * we are getting 00...011...1. Then we apply this mask to - * address and require, that bitwise AND should give 0 (i.e. - * non of the last bits is 1). - */ - ref appliedAlignmentMask = AndExpr::create( - Expr::createPointer(elementType->getAlignment() - 1), object); - - ref sizeExpr = Expr::createPointer(elementType->getSize() - 1); - - ref objectUpperBound = AddExpr::create(object, sizeExpr); - - return AndExpr::create(Expr::createIsZero(appliedAlignmentMask), - UgeExpr::create(objectUpperBound, sizeExpr)); -} - -bool cxxtypes::KCXXPointerType::innerIsAccessableFrom( - KCXXPointerType *accessingType) const { - return elementType->isAccessableFrom(accessingType->elementType); -} - -bool cxxtypes::KCXXPointerType::isPointerToChar() const { - if (llvm::isa(elementType)) { - return (elementType->getRawType()->getIntegerBitWidth() == 8); - } - return false; -} - -bool cxxtypes::KCXXPointerType::isPointerToFunction() const { - return llvm::isa(elementType); -} - -bool cxxtypes::KCXXPointerType::classof(const KType *requestedType) { - return llvm::isa(requestedType) && - llvm::cast(requestedType)->getTypeKind() == - cxxtypes::CXXTypeKind::POINTER; -} diff --git a/lib/Core/TypeManager.cpp b/lib/Core/TypeManager.cpp deleted file mode 100644 index ae7205d9e8..0000000000 --- a/lib/Core/TypeManager.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "TypeManager.h" - -#include "klee/ADT/Ref.h" -#include "klee/Expr/Expr.h" -#include "klee/Module/KInstruction.h" -#include "klee/Module/KModule.h" -#include "klee/Module/KType.h" - -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/Support/Casting.h" - -#include -#include -#include - -using namespace klee; - -/** - * Initializes type system with raw llvm types. - */ -TypeManager::TypeManager(KModule *parent) : parent(parent) {} - -/** - * Computes KType for given type, and cache it, if it was not - * inititalized before. So, any two calls with the same argument - * will return same KType's. - */ -KType *TypeManager::getWrappedType(llvm::Type *type) { - if (typesMap.count(type) == 0) { - types.emplace_back(new KType(type, this)); - typesMap.emplace(type, types.back().get()); -#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - if (type && type->isPointerTy() && !type->isOpaquePointerTy()) { - getWrappedType(type->getNonOpaquePointerElementType()); - } -#else - if (type && type->isPointerTy()) { - getWrappedType(type->getPointerElementType()); - } -#endif - if (type && type->isArrayTy()) { - getWrappedType(type->getArrayElementType()); - } - } - return typesMap[type]; -} - -KType *TypeManager::getUnknownType() { return getWrappedType(nullptr); } - -KType *TypeManager::handleAlloc(ref) { return getUnknownType(); } - -KType *TypeManager::handleRealloc(KType *type, ref) { return type; } - -/** - * Performs initialization for struct types, including inner types. - * Note, that initialization for structs differs from initialization - * for other types, as types from structs can create cyclic dependencies, - * and that is why it cannot be done in constructor. - */ -void TypeManager::initTypesFromStructs() { - /* - * To collect information about all inner types - * we will topologically sort dependencies between structures - * (e.g. if struct A contains class B, we will make edge from A to B) - * and pull types to top. - */ - - for (auto &structType : parent->module->getIdentifiedStructTypes()) { - getWrappedType(structType); - } - - std::unordered_set collectedStructTypes; - for (const auto &it : typesMap) { - if (llvm::StructType *itStruct = - llvm::dyn_cast(it.first)) { - collectedStructTypes.insert(itStruct); - } - } - - for (auto &typesToOffsets : typesMap) { - if (llvm::isa(typesToOffsets.first)) { - collectedStructTypes.insert( - llvm::cast(typesToOffsets.first)); - } - } - - std::vector sortedStructTypesGraph; - std::unordered_set visitedStructTypesGraph; - - std::function dfs = [this, &sortedStructTypesGraph, - &visitedStructTypesGraph, - &dfs](llvm::StructType *type) { - visitedStructTypesGraph.insert(type); - - for (auto typeTo : type->elements()) { - getWrappedType(typeTo); - if (visitedStructTypesGraph.count(typeTo) == 0 && typeTo->isStructTy()) { - dfs(llvm::cast(typeTo)); - } - } - - sortedStructTypesGraph.push_back(type); - }; - - for (auto &structType : collectedStructTypes) { - dfs(structType); - } - - for (auto structType : sortedStructTypesGraph) { - if (structType->isOpaque()) { - continue; - } - - /* Here we make initializaion for inner types of given structure type */ - const llvm::StructLayout *structLayout = - parent->targetData->getStructLayout(structType); - for (unsigned idx = 0; idx < structType->getNumElements(); ++idx) { - uint64_t offset = structLayout->getElementOffset(idx); - llvm::Type *rawElementType = structType->getElementType(idx); - typesMap[structType]->innerTypes[typesMap[rawElementType]].insert(offset); - - /* Provide initialization from types in inner class */ - for (auto &innerStructMemberTypesToOffsets : - typesMap[rawElementType]->innerTypes) { - KType *innerStructMemberType = innerStructMemberTypesToOffsets.first; - const std::set &innerTypeOffsets = - innerStructMemberTypesToOffsets.second; - - /* Add offsets from inner class */ - for (uint64_t innerTypeOffset : innerTypeOffsets) { - typesMap[structType]->innerTypes[innerStructMemberType].insert( - offset + innerTypeOffset); - } - } - } - } -} - -/** - * Performs type system initialization for global objects. - */ -void TypeManager::initTypesFromGlobals() { - for (auto &global : parent->module->getGlobalList()) { - getWrappedType(global.getType()); - } -} - -/** - * Performs type system initialization for all instructions in - * this module. Takes into consideration return and argument types. - */ -void TypeManager::initTypesFromInstructions() { - for (auto &function : *(parent->module)) { - for (auto &BasicBlock : function) { - for (auto &inst : BasicBlock) { - /* Register return type */ - getWrappedType(inst.getType()); - - /* Register types for arguments */ - for (auto opb = inst.op_begin(), ope = inst.op_end(); opb != ope; - ++opb) { - getWrappedType((*opb)->getType()); - } - } - } - } -} - -void TypeManager::initTypeInfo() { - for (auto &type : types) { - llvm::Type *rawType = type->getRawType(); - if (rawType && rawType->isSized()) { -#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - type->alignment = parent->targetData->getABITypeAlign(rawType).value(); -#else - type->alignment = parent->targetData->getABITypeAlignment(rawType); -#endif - type->typeStoreSize = parent->targetData->getTypeStoreSize(rawType); - } - } -} - -void TypeManager::onFinishInitModule() {} - -/** - * Method to initialize all types in given module. - * Note, that it cannot be called in costructor - * as implementation of getWrappedType can be different - * for high-level languages. Note, that struct types is - * called last, as it is required to know about all - * structure types in code. - */ -void TypeManager::initModule() { - initTypesFromGlobals(); - initTypesFromInstructions(); - initTypesFromStructs(); - initTypeInfo(); - onFinishInitModule(); -} From 40337ee2b83a3502c042085c15684970d29b7c60 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 15 Aug 2024 14:46:34 +0200 Subject: [PATCH 19/40] fix: --- lib/Core/MockBuilder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Core/MockBuilder.cpp b/lib/Core/MockBuilder.cpp index eb46968036..c417d54dee 100644 --- a/lib/Core/MockBuilder.cpp +++ b/lib/Core/MockBuilder.cpp @@ -206,7 +206,11 @@ void MockBuilder::buildMockMain() { void MockBuilder::buildExternalGlobalsDefinitions() { auto externalGlobals = getExternalGlobals(); for (const auto &[extName, type] : externalGlobals) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) auto elementType = type->getValueType(); +#else + auto elementType = type->getType()->getValueType(); +#endif klee_message("Mocking external variable %s", extName.c_str()); llvm::GlobalVariable *global = dyn_cast_or_null( mockModule->getOrInsertGlobal(extName, elementType)); From 58155c0072036e3192fd15b6fd2fcf90dec93b44 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 15 Aug 2024 14:53:38 +0200 Subject: [PATCH 20/40] fix: --- lib/Core/MockBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Core/MockBuilder.cpp b/lib/Core/MockBuilder.cpp index c417d54dee..536313b4f0 100644 --- a/lib/Core/MockBuilder.cpp +++ b/lib/Core/MockBuilder.cpp @@ -209,7 +209,7 @@ void MockBuilder::buildExternalGlobalsDefinitions() { #if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) auto elementType = type->getValueType(); #else - auto elementType = type->getType()->getValueType(); + auto elementType = type->getType()->getPointerElementType(); #endif klee_message("Mocking external variable %s", extName.c_str()); llvm::GlobalVariable *global = dyn_cast_or_null( From 4b17fe75a5fa15060677eedf20ba8aaf1ba07c54 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 15 Aug 2024 15:14:21 +0200 Subject: [PATCH 21/40] fix: --- include/klee/Core/MockBuilder.h | 11 +++++++++- lib/Core/MockBuilder.cpp | 36 ++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/include/klee/Core/MockBuilder.h b/include/klee/Core/MockBuilder.h index 34fc81502d..35b23b1bc0 100644 --- a/include/klee/Core/MockBuilder.h +++ b/include/klee/Core/MockBuilder.h @@ -9,6 +9,7 @@ #ifndef KLEE_MOCKBUILDER_H #define KLEE_MOCKBUILDER_H +#include "klee/Config/Version.h" #include "klee/Core/Interpreter.h" #include "klee/Module/Annotation.h" @@ -76,12 +77,20 @@ class MockBuilder { std::set &mainModuleGlobals); std::unique_ptr build(); + void buildFree(llvm::Value *elem, const Statement::Free *freePtr); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) void buildAllocSource(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr); - void buildFree(llvm::Value *elem, const Statement::Free *freePtr); void processingValue(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr, bool initNullPtr); +#else + void buildAllocSource(llvm::Value *prev, llvm::Value *elemType, + const Statement::Alloc *allocSourcePtr); + void processingValue(llvm::Value *prev, llvm::Type *elemType, + const Statement::Alloc *allocSourcePtr, + bool initNullPtr); +#endif }; } // namespace klee diff --git a/lib/Core/MockBuilder.cpp b/lib/Core/MockBuilder.cpp index 536313b4f0..756ebeaa84 100644 --- a/lib/Core/MockBuilder.cpp +++ b/lib/Core/MockBuilder.cpp @@ -531,14 +531,24 @@ void MockBuilder::buildAnnotationForExternalFunctionArgs( if (freePtr) { buildFree(elem, freePtr); } +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) processingValue(prev, elem, allocSourcePtr, initNullPtr); +#else + processingValue(prev, elem->getType(), allocSourcePtr, initNullPtr); +#endif } } } +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) void MockBuilder::processingValue(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr, bool initNullPtr) { +#else +void MockBuilder::processingValue(llvm::Value *prev, llvm::Type *elemType, + const Statement::Alloc *allocSourcePtr, + bool initNullPtr) { +#endif if (initNullPtr) { auto intType = llvm::IntegerType::get(ctx, 1); auto *allocCond = builder->CreateAlloca(intType, nullptr); @@ -556,7 +566,11 @@ void MockBuilder::processingValue(llvm::Value *prev, llvm::Value *elem, llvm::BasicBlock::Create(ctx, "allocArg", curFunc); builder->CreateCondBr(brValue, allocBB, initNullBB); builder->SetInsertPoint(allocBB); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) buildAllocSource(prev, elem, allocSourcePtr); +#else + buildAllocSource(prev, elemType, allocSourcePtr); +#endif builder->CreateBr(contBB); } else { builder->CreateCondBr(brValue, initNullBB, contBB); @@ -567,9 +581,15 @@ void MockBuilder::processingValue(llvm::Value *prev, llvm::Value *elem, curFunc->getBasicBlockList().push_back(initNullBB); #endif builder->SetInsertPoint(initNullBB); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) builder->CreateStore(llvm::ConstantPointerNull::get( llvm::cast(elem->getType())), prev); +#else + builder->CreateStore( + llvm::ConstantPointerNull::get(llvm::cast(elemType)), + prev); +#endif builder->CreateBr(contBB); #if LLVM_VERSION_CODE >= LLVM_VERSION(16, 0) @@ -579,12 +599,21 @@ void MockBuilder::processingValue(llvm::Value *prev, llvm::Value *elem, #endif builder->SetInsertPoint(contBB); } else if (allocSourcePtr) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) buildAllocSource(prev, elem, allocSourcePtr); +#else + buildAllocSource(prev, elemType, allocSourcePtr); +#endif } } +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) void MockBuilder::buildAllocSource(llvm::Value *prev, llvm::Value *elem, const Statement::Alloc *allocSourcePtr) { +#else +void MockBuilder::buildAllocSource(llvm::Value *prev, llvm::Type *elemType, + const Statement::Alloc *allocSourcePtr) { +#endif if (allocSourcePtr->value != Statement::Alloc::ALLOC) { klee_warning("Annotation: AllocSource \"%d\" not implemented use alloc", allocSourcePtr->value); @@ -597,7 +626,7 @@ void MockBuilder::buildAllocSource(llvm::Value *prev, llvm::Value *elem, valueType = func->getFunctionType(); } #else - auto valueType = elem->getType()->getPointerElementType(); + auto valueType = elemType->getPointerElementType(); #endif auto sizeValue = llvm::ConstantInt::get( ctx, @@ -671,8 +700,13 @@ void MockBuilder::buildAnnotationForExternalFunctionReturn( llvm::Value *retValuePtr = builder->CreateAlloca(returnType, nullptr); if (returnType->isPointerTy() && (allocSourcePtr || mustInitNull)) { +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) processingValue(retValuePtr, func, allocSourcePtr, mustInitNull || maybeInitNull); +#else + processingValue(retValuePtr, returnType, allocSourcePtr, + mustInitNull || maybeInitNull); +#endif } else { buildCallKleeMakeSymbolic("klee_make_mock", retValuePtr, returnType, func->getName().str()); From 0d61cc382dc44dbaaa3f547369d4ef732d496601 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 15 Aug 2024 15:22:43 +0200 Subject: [PATCH 22/40] fix: --- include/klee/Core/MockBuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/klee/Core/MockBuilder.h b/include/klee/Core/MockBuilder.h index 35b23b1bc0..c5e5525170 100644 --- a/include/klee/Core/MockBuilder.h +++ b/include/klee/Core/MockBuilder.h @@ -85,7 +85,7 @@ class MockBuilder { const Statement::Alloc *allocSourcePtr, bool initNullPtr); #else - void buildAllocSource(llvm::Value *prev, llvm::Value *elemType, + void buildAllocSource(llvm::Value *prev, llvm::Type *elemType, const Statement::Alloc *allocSourcePtr); void processingValue(llvm::Value *prev, llvm::Type *elemType, const Statement::Alloc *allocSourcePtr, From 618d135049233dcbcee27605750e9284c261c483 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Fri, 16 Aug 2024 12:18:29 +0200 Subject: [PATCH 23/40] fix: --- tools/kleaver/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/kleaver/CMakeLists.txt b/tools/kleaver/CMakeLists.txt index c2960a7e88..8ce45d7c83 100644 --- a/tools/kleaver/CMakeLists.txt +++ b/tools/kleaver/CMakeLists.txt @@ -13,7 +13,7 @@ add_executable(kleaver llvm_config(kleaver "${USE_LLVM_SHARED}" core support) target_link_libraries(kleaver PRIVATE kleaverSolver) -target_include_directories(kleaver PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) +target_include_directories(kleaver SYSTEM PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) target_compile_options(kleaver PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(kleaver PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) From ad49f966062ea517ad6d39faad06d2453de613d5 Mon Sep 17 00:00:00 2001 From: Vladislav Kalugin Date: Mon, 19 Aug 2024 20:57:00 +0000 Subject: [PATCH 24/40] Update annotations --- build.sh | 4 +- include/klee/Core/MockBuilder.h | 2 +- lib/Core/MockBuilder.cpp | 79 ++++++++++++++----- lib/Module/Annotation.cpp | 2 + test/Feature/Annotation/Free.c | 1 + test/Feature/Annotation/General.c | 2 +- test/Feature/MockStrategies.c | 1 + .../UseAfterFree/Double_Free_BadCase01.c | 2 +- .../UseAfterFree/Double_Free_BadCase02.c | 2 +- test/Industry/if2.c | 2 +- test/Industry/test.c | 2 +- test/Industry/while_true.c | 2 +- test/Replay/libkleeruntest/replay_mocks.c | 2 + 13 files changed, 74 insertions(+), 29 deletions(-) diff --git a/build.sh b/build.sh index 5e03c320e0..7902b2aaf6 100755 --- a/build.sh +++ b/build.sh @@ -5,7 +5,7 @@ # Base folder where dependencies and KLEE itself are installed BASE=$HOME/klee_build -BUILD_SUFFIX="Release" +BUILD_SUFFIX="Debug" ## KLEE Required options # Build type for KLEE. The options are: @@ -15,7 +15,7 @@ BUILD_SUFFIX="Release" # Release+Debug+Asserts # Debug # Debug+Asserts -KLEE_RUNTIME_BUILD="Release" +KLEE_RUNTIME_BUILD="Debug" COVERAGE=0 ENABLE_DOXYGEN=0 diff --git a/include/klee/Core/MockBuilder.h b/include/klee/Core/MockBuilder.h index c5e5525170..a100958530 100644 --- a/include/klee/Core/MockBuilder.h +++ b/include/klee/Core/MockBuilder.h @@ -64,7 +64,7 @@ class MockBuilder { std::map getExternalGlobals(); std::pair - goByOffset(llvm::Value *value, const std::vector &offset); + goByOffset(llvm::Value *value, const std::vector &offset, bool isPointer); public: MockBuilder(const llvm::Module *initModule, diff --git a/lib/Core/MockBuilder.cpp b/lib/Core/MockBuilder.cpp index 756ebeaa84..a32ddf1663 100644 --- a/lib/Core/MockBuilder.cpp +++ b/lib/Core/MockBuilder.cpp @@ -23,6 +23,9 @@ #include #include +//TODO remove it +// #define LLVM_VERSION_CODE LLVM_VERSION(15, 0) + namespace klee { template @@ -303,26 +306,37 @@ void MockBuilder::buildExternalFunctionsDefinitions() { std::pair MockBuilder::goByOffset(llvm::Value *value, - const std::vector &offset) { + const std::vector &offset, + bool isPointer) { llvm::Value *prev = nullptr; llvm::Value *current = value; - for (const auto &inst : offset) { - if (inst == "*") { + for (auto it = offset.begin(); it != offset.end(); ++it) { + if (*it == "*") { if (!current->getType()->isPointerTy()) { klee_error("Incorrect annotation offset."); } prev = current; #if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - current = builder->CreateLoad(current->getType(), current); + if((it + 1 != offset.end() && *(it + 1) == "*") || isPointer) { + current = builder->CreateLoad(llvm::PointerType::getUnqual(ctx), current); + } else { + current = builder->CreateLoad(llvm::IntegerType::get(ctx, 1), current); + if(it + 1 != offset.end()) { + klee_warning("smth about not full annotation"); + } + } #else current = builder->CreateLoad(current->getType()->getPointerElementType(), current); #endif - } else if (inst == "&") { + } else if (*it == "&") { auto addr = builder->CreateAlloca(current->getType()); prev = current; current = builder->CreateStore(current, addr); - } else { + } + +#if LLVM_VERSION_CODE < LLVM_VERSION(15, 0) + else { const size_t index = std::stol(inst); if (!(current->getType()->isPointerTy() || current->getType()->isArrayTy())) { @@ -332,26 +346,21 @@ MockBuilder::goByOffset(llvm::Value *value, current = builder->CreateConstInBoundsGEP1_64(current->getType(), current, index); } +#endif } return {prev, current}; } +#if LLVM_VERSION_CODE < LLVM_VERSION(15, 0) inline llvm::Type *getTypeByOffset(llvm::Type *value, const std::vector &offset) { llvm::Type *current = value; for (const auto &inst : offset) { if (inst == "*") { -#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - if (!current->isPointerTy() || current->isOpaquePointerTy()) { - return nullptr; - } - current = current->getNonOpaquePointerElementType(); -#else if (!current->isPointerTy()) { return nullptr; } current = current->getPointerElementType(); -#endif } else if (inst == "&") { // Not change } else { @@ -365,7 +374,9 @@ inline llvm::Type *getTypeByOffset(llvm::Type *value, } return current; } +#endif +#if LLVM_VERSION_CODE < LLVM_VERSION(15, 0) inline bool isCorrectStatements(const std::vector &statements, const llvm::Argument *arg) { return std::any_of(statements.begin(), statements.end(), @@ -384,6 +395,7 @@ inline bool isCorrectStatements(const std::vector &statements, } }); } +#endif bool tryAlign(llvm::Function *func, const std::vector> &statements, @@ -395,6 +407,9 @@ bool tryAlign(llvm::Function *func, for (size_t i = 0, j = 0; j < func->arg_size() && i < statements.size();) { while (true) { + +#if LLVM_VERSION_CODE < LLVM_VERSION(15, 0) + #if LLVM_VERSION_CODE >= LLVM_VERSION(10, 0) auto arg = func->getArg(j); #else @@ -403,6 +418,8 @@ bool tryAlign(llvm::Function *func, if (isCorrectStatements(statements[i], arg)) { break; } +#endif + res.emplace_back(); j++; if (j >= func->arg_size()) { @@ -446,7 +463,22 @@ void MockBuilder::buildAnnotationForExternalFunctionArgs( #endif auto statementsMap = unifyByOffset(statements[i]); for (const auto &[offset, statementsOffset] : statementsMap) { - auto [prev, elem] = goByOffset(arg, offset); + bool isPointer = std::any_of(statementsOffset.begin(), statementsOffset.end(), + [](Statement::Ptr statment) { + switch (statment->getKind()) + { + case Statement::Kind::Deref: + case Statement::Kind::InitNull: + case Statement::Kind::MaybeInitNull: + case Statement::Kind::Free: + case Statement::Kind::AllocSource: + return true; + case Statement::Kind::Unknown: + default: + return false; + } + }); + auto [prev, elem] = goByOffset(arg, offset, isPointer); Statement::Alloc *allocSourcePtr = nullptr; Statement::Free *freePtr = nullptr; @@ -480,7 +512,7 @@ void MockBuilder::buildAnnotationForExternalFunctionArgs( builder->SetInsertPoint(derefBB); #if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - builder->CreateLoad(elem->getType(), elem); + builder->CreateLoad(llvm::IntegerType::get(ctx, 1), elem); #else builder->CreateLoad(elem->getType()->getPointerElementType(), elem); #endif @@ -620,11 +652,18 @@ void MockBuilder::buildAllocSource(llvm::Value *prev, llvm::Type *elemType, } #if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) auto valueType = elem->getType(); - if (isa(elem) || isa(elem)) { - valueType = llvm::getLoadStoreType(elem); - } else if (auto func = dyn_cast(elem)) { - valueType = func->getFunctionType(); - } + llvm::errs() << "gbo3: "; + elem->getType()->print(llvm::errs(), true, true); + llvm::errs() << "\n"; + llvm::errs() << "val: "; + elem->print(llvm::errs(), true); + llvm::errs() << "\n"; + // if (isa(elem) || isa(elem)) { + // valueType = llvm::getLoadStoreType(elem); + // } else if (auto func = dyn_cast(elem)) { + // valueType = func->getFunctionType(); + // } + // llvm::errs() << valueType->getTypeID(); #else auto valueType = elemType->getPointerElementType(); #endif diff --git a/lib/Module/Annotation.cpp b/lib/Module/Annotation.cpp index 1e5e6c19f5..96ff3e5c26 100644 --- a/lib/Module/Annotation.cpp +++ b/lib/Module/Annotation.cpp @@ -58,6 +58,7 @@ Unknown::Unknown(const std::string &str) { offset.emplace_back("&"); break; } +#if LLVM_VERSION_CODE < LLVM_VERSION(15, 0) case '[': { size_t posEndExpr = rawOffset.find(']', pos); if (posEndExpr == std::string::npos) { @@ -67,6 +68,7 @@ Unknown::Unknown(const std::string &str) { pos = posEndExpr; break; } +#endif default: { klee_warning("Annotation: Incorrect offset format \"%s\"", str.c_str()); break; diff --git a/test/Feature/Annotation/Free.c b/test/Feature/Annotation/Free.c index 22614bf8f5..76ba591531 100644 --- a/test/Feature/Annotation/Free.c +++ b/test/Feature/Annotation/Free.c @@ -12,6 +12,7 @@ // RUN: %klee --solver-backend=z3 --output-dir=%t3.klee-out-1 --annotations=%S/Free.json --mock-policy=all --mock-modeled-functions --emit-all-errors=true %t3.bc 2>&1 | FileCheck %s -check-prefix=CHECK-FREE3 #include +#include int *maybeAllocSource1(); void maybeFree1(int *a); diff --git a/test/Feature/Annotation/General.c b/test/Feature/Annotation/General.c index a642919f2b..592c0cf5bc 100644 --- a/test/Feature/Annotation/General.c +++ b/test/Feature/Annotation/General.c @@ -24,7 +24,7 @@ void ptrArg(struct ST, int **a); int *ptrRet(); int main() { - int *a = 15; + int *a = (int*) 15; #ifdef PTRARG struct ST st; ptrArg(st, &a); diff --git a/test/Feature/MockStrategies.c b/test/Feature/MockStrategies.c index d8998cfe54..39af53a87b 100644 --- a/test/Feature/MockStrategies.c +++ b/test/Feature/MockStrategies.c @@ -22,6 +22,7 @@ // CHECK-4: KLEE: done: completed paths = 2 // CHECK-4: KLEE: done: generated tests = 2 +#include #include extern int foo(int x, int y); diff --git a/test/Industry/UseAfterFree/Double_Free_BadCase01.c b/test/Industry/UseAfterFree/Double_Free_BadCase01.c index 34420ba6ee..081dc36d4f 100644 --- a/test/Industry/UseAfterFree/Double_Free_BadCase01.c +++ b/test/Industry/UseAfterFree/Double_Free_BadCase01.c @@ -36,7 +36,7 @@ void DoubleFreeBad01() free(p); // CHECK: KLEE: WARNING: 100.00% DoubleFree True Positive at trace 1 } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -o %t1.bc +// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --libc=klee --skip-not-symbolic-objects --skip-not-lazy-initialized --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s diff --git a/test/Industry/UseAfterFree/Double_Free_BadCase02.c b/test/Industry/UseAfterFree/Double_Free_BadCase02.c index f048ea3234..0b6ec7774f 100644 --- a/test/Industry/UseAfterFree/Double_Free_BadCase02.c +++ b/test/Industry/UseAfterFree/Double_Free_BadCase02.c @@ -39,7 +39,7 @@ void DoubleFreeBad02(int flag) } } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -o %t1.bc +// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --libc=klee --skip-not-symbolic-objects --skip-not-lazy-initialized --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s diff --git a/test/Industry/if2.c b/test/Industry/if2.c index b6ef8b0982..2c8035963a 100644 --- a/test/Industry/if2.c +++ b/test/Industry/if2.c @@ -8,7 +8,7 @@ int main(int x) { return *p; } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -o %t1.bc +// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --search=bfs --max-instructions=45 --max-cycles-before-stuck=0 --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s -check-prefix=CHECK-NONE diff --git a/test/Industry/test.c b/test/Industry/test.c index 500ab31738..82cd244eed 100644 --- a/test/Industry/test.c +++ b/test/Industry/test.c @@ -19,7 +19,7 @@ void TestBad8(int len) buf[0] = 'a'; // CHECK-NUM: KLEE: WARNING: 100.00% NullPointerException True Positive at trace 1 } // CHECK-UID: KLEE: WARNING: 100.00% NullPointerException True Positive at trace 8389b1896658d867c9e15267acfe8c32 -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -o %t1.bc +// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --libc=klee --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s -check-prefix=CHECK-NUM diff --git a/test/Industry/while_true.c b/test/Industry/while_true.c index ffbf90e30b..ccbdffacf9 100644 --- a/test/Industry/while_true.c +++ b/test/Industry/while_true.c @@ -8,7 +8,7 @@ int main() { return *p; } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -o %t1.bc +// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc // RUN: rm -rf %t.klee-out-1 // RUN: %klee --output-dir=%t.klee-out-1 --use-guided-search=error --mock-policy=failed --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --max-stepped-instructions=20 --max-cycles-before-stuck=0 --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out-1/warnings.txt %s -check-prefix=CHECK-NONE diff --git a/test/Replay/libkleeruntest/replay_mocks.c b/test/Replay/libkleeruntest/replay_mocks.c index 615bea931b..20317ecab3 100644 --- a/test/Replay/libkleeruntest/replay_mocks.c +++ b/test/Replay/libkleeruntest/replay_mocks.c @@ -15,6 +15,8 @@ // RUN: test -f %t.klee-out/test000001.ktest // RUN: env KTEST_FILE=%t.klee-out/test000001.ktest %t_runner2 +#include + extern int variable; extern int foo(int); From 0253e3460832568157fd2bd7530ba9bc5ab52ba1 Mon Sep 17 00:00:00 2001 From: Vladislav Kalugin Date: Mon, 19 Aug 2024 21:47:03 +0000 Subject: [PATCH 25/40] Update annotations unit tests --- include/klee/Core/MockBuilder.h | 2 +- lib/Core/MockBuilder.cpp | 50 +++-------------------- unittests/Annotations/AnnotationsTest.cpp | 21 ++++++++++ 3 files changed, 28 insertions(+), 45 deletions(-) diff --git a/include/klee/Core/MockBuilder.h b/include/klee/Core/MockBuilder.h index a100958530..c5e5525170 100644 --- a/include/klee/Core/MockBuilder.h +++ b/include/klee/Core/MockBuilder.h @@ -64,7 +64,7 @@ class MockBuilder { std::map getExternalGlobals(); std::pair - goByOffset(llvm::Value *value, const std::vector &offset, bool isPointer); + goByOffset(llvm::Value *value, const std::vector &offset); public: MockBuilder(const llvm::Module *initModule, diff --git a/lib/Core/MockBuilder.cpp b/lib/Core/MockBuilder.cpp index a32ddf1663..ba1dd2a77f 100644 --- a/lib/Core/MockBuilder.cpp +++ b/lib/Core/MockBuilder.cpp @@ -23,9 +23,6 @@ #include #include -//TODO remove it -// #define LLVM_VERSION_CODE LLVM_VERSION(15, 0) - namespace klee { template @@ -306,30 +303,22 @@ void MockBuilder::buildExternalFunctionsDefinitions() { std::pair MockBuilder::goByOffset(llvm::Value *value, - const std::vector &offset, - bool isPointer) { + const std::vector &offset) { llvm::Value *prev = nullptr; llvm::Value *current = value; - for (auto it = offset.begin(); it != offset.end(); ++it) { - if (*it == "*") { + for (const auto &inst : offset) { + if (inst == "*") { if (!current->getType()->isPointerTy()) { klee_error("Incorrect annotation offset."); } prev = current; #if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) - if((it + 1 != offset.end() && *(it + 1) == "*") || isPointer) { - current = builder->CreateLoad(llvm::PointerType::getUnqual(ctx), current); - } else { - current = builder->CreateLoad(llvm::IntegerType::get(ctx, 1), current); - if(it + 1 != offset.end()) { - klee_warning("smth about not full annotation"); - } - } + current = builder->CreateLoad(llvm::PointerType::getUnqual(ctx), current); #else current = builder->CreateLoad(current->getType()->getPointerElementType(), current); #endif - } else if (*it == "&") { + } else if (inst == "&") { auto addr = builder->CreateAlloca(current->getType()); prev = current; current = builder->CreateStore(current, addr); @@ -463,22 +452,7 @@ void MockBuilder::buildAnnotationForExternalFunctionArgs( #endif auto statementsMap = unifyByOffset(statements[i]); for (const auto &[offset, statementsOffset] : statementsMap) { - bool isPointer = std::any_of(statementsOffset.begin(), statementsOffset.end(), - [](Statement::Ptr statment) { - switch (statment->getKind()) - { - case Statement::Kind::Deref: - case Statement::Kind::InitNull: - case Statement::Kind::MaybeInitNull: - case Statement::Kind::Free: - case Statement::Kind::AllocSource: - return true; - case Statement::Kind::Unknown: - default: - return false; - } - }); - auto [prev, elem] = goByOffset(arg, offset, isPointer); + auto [prev, elem] = goByOffset(arg, offset); Statement::Alloc *allocSourcePtr = nullptr; Statement::Free *freePtr = nullptr; @@ -652,18 +626,6 @@ void MockBuilder::buildAllocSource(llvm::Value *prev, llvm::Type *elemType, } #if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) auto valueType = elem->getType(); - llvm::errs() << "gbo3: "; - elem->getType()->print(llvm::errs(), true, true); - llvm::errs() << "\n"; - llvm::errs() << "val: "; - elem->print(llvm::errs(), true); - llvm::errs() << "\n"; - // if (isa(elem) || isa(elem)) { - // valueType = llvm::getLoadStoreType(elem); - // } else if (auto func = dyn_cast(elem)) { - // valueType = func->getFunctionType(); - // } - // llvm::errs() << valueType->getTypeID(); #else auto valueType = elemType->getPointerElementType(); #endif diff --git a/unittests/Annotations/AnnotationsTest.cpp b/unittests/Annotations/AnnotationsTest.cpp index 4899d69837..bc56c9a720 100644 --- a/unittests/Annotations/AnnotationsTest.cpp +++ b/unittests/Annotations/AnnotationsTest.cpp @@ -13,6 +13,8 @@ #include "nlohmann/json.hpp" +#include "klee/Config/Version.h" + #include using json = nlohmann::json; @@ -112,6 +114,24 @@ TEST(AnnotationsTest, KnownAnnotations) { Statement::Kind::InitNull); } +TEST(AnnotationsTest, WithOffsetsSimple) { + const json j = json::parse(R"( +{ + "foo" : { + "annotation" : [["InitNull:**&"]], + "properties" : [] + } +} +)"); + const AnnotationsMap actual = parseAnnotationsJson(j); + ASSERT_EQ(actual.at("foo").returnStatements[0]->getKind(), + Statement::Kind::InitNull); + const std::vector expectedOffset{"*", "*", "&"}; + ASSERT_EQ(actual.at("foo").returnStatements[0]->offset, expectedOffset); +} + + +#if LLVM_VERSION_CODE < LLVM_VERSION(15, 0) TEST(AnnotationsTest, WithOffsets) { const json j = json::parse(R"( { @@ -127,3 +147,4 @@ TEST(AnnotationsTest, WithOffsets) { const std::vector expectedOffset{"*", "10", "*", "&"}; ASSERT_EQ(actual.at("foo").returnStatements[0]->offset, expectedOffset); } +#endif \ No newline at end of file From 476f8211de19c71b377da8df8a7222f10d2f67c3 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 20 Aug 2024 11:18:13 +0200 Subject: [PATCH 26/40] fix: --- ..._lcr.3.ufo.UNBOUNDED.pals+Problem12_label00.c | 3 ++- test/Industry/if2.c | 16 ++++++++-------- test/Industry/if2.c.json | 4 ++-- test/Industry/while_true.c | 4 ++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/test/Industry/CoverageBranches/pals_lcr.3.ufo.UNBOUNDED.pals+Problem12_label00.c b/test/Industry/CoverageBranches/pals_lcr.3.ufo.UNBOUNDED.pals+Problem12_label00.c index 62bab5e5fc..458c9dc80a 100644 --- a/test/Industry/CoverageBranches/pals_lcr.3.ufo.UNBOUNDED.pals+Problem12_label00.c +++ b/test/Industry/CoverageBranches/pals_lcr.3.ufo.UNBOUNDED.pals+Problem12_label00.c @@ -1,6 +1,7 @@ +// REQUIRES: lt-llvm-15.0 // RUN: %clang %s -emit-llvm %O0opt -g -c -o %t1.bc // RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --optimize-aggressive=false --track-coverage=branches --delete-dead-loops=false --emit-all-errors --mock-policy=all --use-forked-solver=false --optimize --skip-not-lazy-initialized --output-source=false --output-stats=false --output-istats=false -istats-write-interval=3s --use-sym-size-alloc=true --cex-cache-validity-cores --symbolic-allocation-threshold=8192 --cover-on-the-fly=false --delay-cover-on-the-fly=400000 --only-output-states-covering-new --dump-states-on-halt=all --search=dfs --search=random-state --use-iterative-deepening-search=max-cycles --max-cycles=4 %t1.bc +// RUN: %klee --output-dir=%t.klee-out --optimize-aggressive=false --track-coverage=branches --delete-dead-loops=false --emit-all-errors --mock-policy=all --use-forked-solver=false --optimize --skip-not-lazy-initialized --output-source=false --output-stats=false --output-istats=false -istats-write-interval=3s --use-sym-size-alloc=true --cex-cache-validity-cores --symbolic-allocation-threshold=8192 --cover-on-the-fly=false --delay-cover-on-the-fly=400000 --only-output-states-covering-new --dump-states-on-halt=all --search=dfs --search=random-state --use-iterative-deepening-search=max-cycles --max-cycles=6 %t1.bc // RUN: rm -f ./%gcov-files-path*.gcda ./%gcov-files-path*.gcno ./%gcov-files-path*.gcov // RUN: %cc -DGCOV %s %libkleeruntest -Wl,-rpath %libkleeruntestdir -o %t_runner %gcov-options diff --git a/test/Industry/if2.c b/test/Industry/if2.c index 2c8035963a..178a061043 100644 --- a/test/Industry/if2.c +++ b/test/Industry/if2.c @@ -1,17 +1,17 @@ int main(int x) { int *p = 0; - if (x) { - p = &x; - } else { - klee_sleep(); + while (!p) { + if (x) { + p = &x; + } else { + p = 0; + } } return *p; } // RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc // RUN: rm -rf %t.klee-out -// RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --search=bfs --max-instructions=45 --max-cycles-before-stuck=0 --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc +// RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --search=bfs --max-cycles=1 --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s -check-prefix=CHECK-NONE -// CHECK-NONE: KLEE: WARNING: 50.00% NullPointerException False Positive at trace 1 -// RUN: FileCheck -input-file=%t.klee-out/messages.txt %s -check-prefix=CHECK-DISTANCE -// CHECK-DISTANCE: KLEE: (0, 1, 0) for Target 1: error in function main (lines 8 to 8) +// CHECK-NONE: KLEE: WARNING: {{[0-9][0-9]\.[0-9][0-9]}}% NullPointerException False Positive at trace 1 diff --git a/test/Industry/if2.c.json b/test/Industry/if2.c.json index f7053713fe..bc0d06d785 100644 --- a/test/Industry/if2.c.json +++ b/test/Industry/if2.c.json @@ -33,7 +33,7 @@ "uri": "if2.c" }, "region": { - "startLine": 8, + "startLine": 10, "startColumn": 10 } } @@ -52,7 +52,7 @@ "uri": "if2.c" }, "region": { - "startLine": 8, + "startLine": 10, "startColumn": 10 } } diff --git a/test/Industry/while_true.c b/test/Industry/while_true.c index ccbdffacf9..70d82b7c8e 100644 --- a/test/Industry/while_true.c +++ b/test/Industry/while_true.c @@ -14,11 +14,11 @@ int main() { // RUN: FileCheck -input-file=%t.klee-out-1/warnings.txt %s -check-prefix=CHECK-NONE // CHECK-NONE: KLEE: WARNING: 0.00% NullPointerException False Positive at trace 1 // RUN: FileCheck -input-file=%t.klee-out-1/messages.txt %s -check-prefix=CHECK-REACH-1 -// CHECK-REACH-1: (0, 1, 4) for Target 1: error in function main (lines 8 to 8) +// CHECK-REACH-1: (0, 1, {{3|4}}) for Target 1: error in function main (lines 8 to 8) // RUN: rm -rf %t.klee-out-2 // RUN: %klee --output-dir=%t.klee-out-2 --use-guided-search=error --mock-policy=failed --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --max-stepped-instructions=4980 --max-cycles-before-stuck=0 --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out-2/warnings.txt %s -check-prefix=CHECK-ALL // CHECK-ALL: KLEE: WARNING: 99.00% NullPointerException False Positive at trace 1 // RUN: FileCheck -input-file=%t.klee-out-2/messages.txt %s -check-prefix=CHECK-REACH-2 -// CHECK-REACH-2: (0, 1, 1) for Target 1: error in function main (lines 8 to 8) +// CHECK-REACH-2: (0, 1, {{1|2}}) for Target 1: error in function main (lines 8 to 8) From 8430a1361e8f6f1abbd11a0565543cbfa362100b Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 20 Aug 2024 11:29:34 +0200 Subject: [PATCH 27/40] fix: --- test/Industry/UseAfterFree/Double_Free_BadCase01.c | 2 +- test/Industry/UseAfterFree/Double_Free_BadCase02.c | 2 +- test/Industry/if2.c | 2 +- test/Industry/test.c | 2 +- test/Industry/while_true.c | 2 +- test/lit.site.cfg.in | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/Industry/UseAfterFree/Double_Free_BadCase01.c b/test/Industry/UseAfterFree/Double_Free_BadCase01.c index 081dc36d4f..35260c2fdd 100644 --- a/test/Industry/UseAfterFree/Double_Free_BadCase01.c +++ b/test/Industry/UseAfterFree/Double_Free_BadCase01.c @@ -36,7 +36,7 @@ void DoubleFreeBad01() free(p); // CHECK: KLEE: WARNING: 100.00% DoubleFree True Positive at trace 1 } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc +// RUN: %clang %s -emit-llvm %O0opt -c -g -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --libc=klee --skip-not-symbolic-objects --skip-not-lazy-initialized --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s diff --git a/test/Industry/UseAfterFree/Double_Free_BadCase02.c b/test/Industry/UseAfterFree/Double_Free_BadCase02.c index 0b6ec7774f..d463b9a616 100644 --- a/test/Industry/UseAfterFree/Double_Free_BadCase02.c +++ b/test/Industry/UseAfterFree/Double_Free_BadCase02.c @@ -39,7 +39,7 @@ void DoubleFreeBad02(int flag) } } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc +// RUN: %clang %s -emit-llvm %O0opt -c -g -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --libc=klee --skip-not-symbolic-objects --skip-not-lazy-initialized --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s diff --git a/test/Industry/if2.c b/test/Industry/if2.c index 178a061043..1856863e13 100644 --- a/test/Industry/if2.c +++ b/test/Industry/if2.c @@ -10,7 +10,7 @@ int main(int x) { return *p; } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc +// RUN: %clang %s -emit-llvm %O0opt -c -g -O0 -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --search=bfs --max-cycles=1 --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s -check-prefix=CHECK-NONE diff --git a/test/Industry/test.c b/test/Industry/test.c index 82cd244eed..e3c89fa82d 100644 --- a/test/Industry/test.c +++ b/test/Industry/test.c @@ -19,7 +19,7 @@ void TestBad8(int len) buf[0] = 'a'; // CHECK-NUM: KLEE: WARNING: 100.00% NullPointerException True Positive at trace 1 } // CHECK-UID: KLEE: WARNING: 100.00% NullPointerException True Positive at trace 8389b1896658d867c9e15267acfe8c32 -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc +// RUN: %clang %s -emit-llvm %O0opt -c -g -o %t1.bc // RUN: rm -rf %t.klee-out // RUN: %klee --output-dir=%t.klee-out --use-guided-search=error --annotations=%annotations --mock-policy=all --libc=klee --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out/warnings.txt %s -check-prefix=CHECK-NUM diff --git a/test/Industry/while_true.c b/test/Industry/while_true.c index 70d82b7c8e..b31484cef4 100644 --- a/test/Industry/while_true.c +++ b/test/Industry/while_true.c @@ -8,7 +8,7 @@ int main() { return *p; } -// RUN: %clang %s -emit-llvm -c -g -O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration -o %t1.bc +// RUN: %clang %s -emit-llvm %O0opt -c -g -O0 -o %t1.bc // RUN: rm -rf %t.klee-out-1 // RUN: %klee --output-dir=%t.klee-out-1 --use-guided-search=error --mock-policy=failed --skip-not-symbolic-objects --skip-not-lazy-initialized --check-out-of-memory --max-stepped-instructions=20 --max-cycles-before-stuck=0 --use-lazy-initialization=only --analysis-reproduce=%s.json %t1.bc // RUN: FileCheck -input-file=%t.klee-out-1/warnings.txt %s -check-prefix=CHECK-NONE diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 48081af6d7..fa226f9e56 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -42,7 +42,7 @@ config.cxx = "@NATIVE_CXX@" # NOTE: any changes to compiler flags also have to be applied to # test/Concrete/CMakeLists.txt -config.O0opt = "-O0 -Xclang -disable-O0-optnone" +config.O0opt = "-O0 -Xclang -disable-O0-optnone -Wno-implicit-function-declaration" config.sqlite3 = "@SQLITE_CLI@" From 6138376a5cab65d1c44796dcc36538eaab1d26de Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 20 Aug 2024 11:30:03 +0200 Subject: [PATCH 28/40] style: --- test/Feature/Annotation/General.c | 2 +- test/Feature/MockStrategies.c | 2 +- unittests/Annotations/AnnotationsTest.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/Feature/Annotation/General.c b/test/Feature/Annotation/General.c index 592c0cf5bc..de23ed41a4 100644 --- a/test/Feature/Annotation/General.c +++ b/test/Feature/Annotation/General.c @@ -24,7 +24,7 @@ void ptrArg(struct ST, int **a); int *ptrRet(); int main() { - int *a = (int*) 15; + int *a = (int *)15; #ifdef PTRARG struct ST st; ptrArg(st, &a); diff --git a/test/Feature/MockStrategies.c b/test/Feature/MockStrategies.c index 39af53a87b..e984f20c04 100644 --- a/test/Feature/MockStrategies.c +++ b/test/Feature/MockStrategies.c @@ -22,8 +22,8 @@ // CHECK-4: KLEE: done: completed paths = 2 // CHECK-4: KLEE: done: generated tests = 2 -#include #include +#include extern int foo(int x, int y); diff --git a/unittests/Annotations/AnnotationsTest.cpp b/unittests/Annotations/AnnotationsTest.cpp index bc56c9a720..95385b9970 100644 --- a/unittests/Annotations/AnnotationsTest.cpp +++ b/unittests/Annotations/AnnotationsTest.cpp @@ -130,7 +130,6 @@ TEST(AnnotationsTest, WithOffsetsSimple) { ASSERT_EQ(actual.at("foo").returnStatements[0]->offset, expectedOffset); } - #if LLVM_VERSION_CODE < LLVM_VERSION(15, 0) TEST(AnnotationsTest, WithOffsets) { const json j = json::parse(R"( From 355ce548388411b24b34badfaa9ceedad264f291 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 20 Aug 2024 11:46:08 +0200 Subject: [PATCH 29/40] fix: --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7aa9493ebf..ca9bd0411e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -5,7 +5,7 @@ on: pull_request: branches: [main, utbot-main] push: - branches: [main, utbot-main, misonijnik/rebase-3.1-inner] + branches: [main, utbot-main] # Defaults for building KLEE env: From b7d36ee5fb17045ab7d07cd192f170957db46c26 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 20 Aug 2024 11:51:46 +0200 Subject: [PATCH 30/40] fix: --- .github/workflows/build.yaml | 1 + DEBT | 2 +- build.sh | 6 +++--- lib/Module/KModule.cpp | 6 ------ 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ca9bd0411e..b5e3869c1e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -57,6 +57,7 @@ jobs: "Latest klee-uclibc", "Asserts disabled", "No TCMalloc, optimised runtime", + "Warnings as errors", ] include: - name: "LLVM 16" diff --git a/DEBT b/DEBT index 26456addab..1504244a1b 100644 --- a/DEBT +++ b/DEBT @@ -10,4 +10,4 @@ KLEE 3.1, 29 February 2024 KLEE 3.0, 7 June 2023 ===================== -- Added support for the KDAlloc memory allocator, which enables KLEE to more robustly detect use-after-free errors, improves the detection of buffer overflows, and provides deterministic memory allocation (@danielschemmel, based on https://srg.doc.ic.ac.uk/publications/22-kdalloc-ecoop.html) \ No newline at end of file +- Added support for the KDAlloc memory allocator, which enables KLEE to more robustly detect use-after-free errors, improves the detection of buffer overflows, and provides deterministic memory allocation (@danielschemmel, based on https://srg.doc.ic.ac.uk/publications/22-kdalloc-ecoop.html) diff --git a/build.sh b/build.sh index 7902b2aaf6..e716cd7b63 100755 --- a/build.sh +++ b/build.sh @@ -5,7 +5,7 @@ # Base folder where dependencies and KLEE itself are installed BASE=$HOME/klee_build -BUILD_SUFFIX="Debug" +BUILD_SUFFIX="Release" ## KLEE Required options # Build type for KLEE. The options are: @@ -15,7 +15,7 @@ BUILD_SUFFIX="Debug" # Release+Debug+Asserts # Debug # Debug+Asserts -KLEE_RUNTIME_BUILD="Debug" +KLEE_RUNTIME_BUILD="Release" COVERAGE=0 ENABLE_DOXYGEN=0 @@ -65,7 +65,7 @@ if [ "$1" = "--debug" ] || [ "$1" = "-g" ]; then ENABLE_OPTIMIZED=0 ENABLE_DEBUG=1 KLEE_RUNTIME_BUILD="Debug+Asserts" - ENABLE_WARNINGS_AS_ERRORS=1 + ENABLE_WARNINGS_AS_ERRORS=0 shift 1 else KEEP_PARSE="false" diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index 76f2e3bc70..d498d1cd65 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -346,12 +346,6 @@ void KModule::manifest(InterpreterHandler *ih, } } - for (auto &Function : functions) { - if (Function->getName() == "_klee_eh_cxx_personality") { - llvm::errs(); - } - } - if (DebugPrintEscapingFunctions && !escapingFunctions.empty()) { llvm::errs() << "KLEE: escaping functions: ["; std::string delimiter = ""; From fa1718909f07ed132cc4ef50ea191146d6cdb846 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 20 Aug 2024 12:48:39 +0200 Subject: [PATCH 31/40] fix: --- lib/Solver/BitwuzlaSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Solver/BitwuzlaSolver.cpp b/lib/Solver/BitwuzlaSolver.cpp index b6fcadd567..fd5f94f990 100644 --- a/lib/Solver/BitwuzlaSolver.cpp +++ b/lib/Solver/BitwuzlaSolver.cpp @@ -385,7 +385,7 @@ std::string BitwuzlaSolverImpl::getConstraintLog(const Query &query) { outputLog << "(check-sat)\n"; // Client is responsible for freeing the returned C-string - return strdup(outputLog.str().c_str()); + return outputLog.str(); } bool BitwuzlaSolverImpl::computeTruth(const ConstraintQuery &query, From 5a3326a1cfdbe4f7324625094959567409bc00b5 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 21 Aug 2024 17:49:33 +0200 Subject: [PATCH 32/40] fix: --- .github/workflows/build.yaml | 13 +++++++------ build.sh | 3 +-- lib/Core/Memory.h | 1 - lib/Core/SeedInfo.cpp | 2 +- test/regression/2023-11-20-solver.c | 2 +- tools/kleaver/CMakeLists.txt | 3 ++- tools/klee/CMakeLists.txt | 3 ++- tools/klee/main.cpp | 1 - 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b5e3869c1e..4cef0bf1d0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -6,6 +6,12 @@ on: branches: [main, utbot-main] push: branches: [main, utbot-main] + workflow_dispatch: + inputs: + logLevel: + description: 'Warnings as errors' + required: true + default: '1' # Defaults for building KLEE env: @@ -17,7 +23,7 @@ env: ENABLE_DOXYGEN: 0 ENABLE_OPTIMIZED: 1 ENABLE_DEBUG: 1 - ENABLE_WARNINGS_AS_ERRORS: 0 + ENABLE_WARNINGS_AS_ERRORS: {{ github.event.inputs.logLevel }} GTEST_VERSION: 1.11.0 KLEE_RUNTIME_BUILD: "Debug+Asserts" LLVM_VERSION: 11 @@ -57,7 +63,6 @@ jobs: "Latest klee-uclibc", "Asserts disabled", "No TCMalloc, optimised runtime", - "Warnings as errors", ] include: - name: "LLVM 16" @@ -134,10 +139,6 @@ jobs: SOLVERS: STP USE_TCMALLOC: 0 KLEE_RUNTIME_BUILD: "Release+Debug+Asserts" - # Check we can build without warnings - - name: "Warnings as errors" - env: - ENABLE_WARNINGS_AS_ERRORS: 1 steps: - name: Checkout KLEE source code uses: actions/checkout@v3 diff --git a/build.sh b/build.sh index e716cd7b63..5270919ebf 100755 --- a/build.sh +++ b/build.sh @@ -31,7 +31,7 @@ ENABLE_OPTIMIZED=1 ENABLE_DEBUG=0 DISABLE_ASSERTIONS=1 REQUIRES_RTTI=1 -ENABLE_WARNINGS_AS_ERRORS=1 +ENABLE_WARNINGS_AS_ERRORS=0 ## Solvers Required options # SOLVERS=STP @@ -65,7 +65,6 @@ if [ "$1" = "--debug" ] || [ "$1" = "-g" ]; then ENABLE_OPTIMIZED=0 ENABLE_DEBUG=1 KLEE_RUNTIME_BUILD="Debug+Asserts" - ENABLE_WARNINGS_AS_ERRORS=0 shift 1 else KEEP_PARSE="false" diff --git a/lib/Core/Memory.h b/lib/Core/Memory.h index 830e92d3ab..2923bd5d53 100644 --- a/lib/Core/Memory.h +++ b/lib/Core/Memory.h @@ -33,7 +33,6 @@ namespace klee { class BitArray; class ExecutionState; -class Executor; class MemoryManager; class Solver; diff --git a/lib/Core/SeedInfo.cpp b/lib/Core/SeedInfo.cpp index cbc1a99b9c..2e0b2e22ae 100644 --- a/lib/Core/SeedInfo.cpp +++ b/lib/Core/SeedInfo.cpp @@ -76,7 +76,7 @@ void SeedInfo::patchSeed(const ExecutionState &state, ref condition, std::set> directReads; std::vector> reads; findReads(condition, false, reads); - for (auto const &re : reads) { + for (const auto &re : reads) { if (ConstantExpr *CE = dyn_cast(re->index)) { directReads.insert( std::make_pair(re->updates.root, (unsigned)CE->getZExtValue(32))); diff --git a/test/regression/2023-11-20-solver.c b/test/regression/2023-11-20-solver.c index ceef818092..aba67c32cd 100644 --- a/test/regression/2023-11-20-solver.c +++ b/test/regression/2023-11-20-solver.c @@ -33,4 +33,4 @@ int main() { klee_assume(0 > p4); // CHECK: [[@LINE+1]]: ASSERTION FAIL assert(p2 > p11); -} \ No newline at end of file +} diff --git a/tools/kleaver/CMakeLists.txt b/tools/kleaver/CMakeLists.txt index 8ce45d7c83..4b4cf8de59 100644 --- a/tools/kleaver/CMakeLists.txt +++ b/tools/kleaver/CMakeLists.txt @@ -13,7 +13,8 @@ add_executable(kleaver llvm_config(kleaver "${USE_LLVM_SHARED}" core support) target_link_libraries(kleaver PRIVATE kleaverSolver) -target_include_directories(kleaver SYSTEM PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) +target_include_directories(klee SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) +target_include_directories(klee PRIVATE ${KLEE_INCLUDE_DIRS}) target_compile_options(kleaver PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(kleaver PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) diff --git a/tools/klee/CMakeLists.txt b/tools/klee/CMakeLists.txt index d54ee27372..d6664882bc 100644 --- a/tools/klee/CMakeLists.txt +++ b/tools/klee/CMakeLists.txt @@ -15,7 +15,8 @@ set(KLEE_LIBS ) target_link_libraries(klee ${KLEE_LIBS}) -target_include_directories(klee SYSTEM PRIVATE ${KLEE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS}) +target_include_directories(klee SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) +target_include_directories(klee PRIVATE ${KLEE_INCLUDE_DIRS}) target_compile_options(klee PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(klee PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp index d020fa9eb2..c3f2101bf4 100644 --- a/tools/klee/main.cpp +++ b/tools/klee/main.cpp @@ -1491,7 +1491,6 @@ static int run_klee_on_function(int pArgc, char **pArgv, char **pEnvp, // Assume with early exit a bug finding mode and otherwise coverage if (UseGuidedSearch == Interpreter::GuidanceKind::ErrorGuidance) *meta_file << "\tCOVER( init(main()), FQL(COVER " - "EDGES(@CALL(__VERIFIER_error))) )\n"; else *meta_file << "\tCOVER( init(main()), FQL(COVER " From 5c370b62ace79a3d77085a822005dca76ec31c21 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 21 Aug 2024 18:01:25 +0200 Subject: [PATCH 33/40] fix: --- .github/workflows/build.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4cef0bf1d0..a719906a53 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -8,10 +8,10 @@ on: branches: [main, utbot-main] workflow_dispatch: inputs: - logLevel: + warnings_as_errors: description: 'Warnings as errors' required: true - default: '1' + default: 1 # Defaults for building KLEE env: @@ -23,7 +23,7 @@ env: ENABLE_DOXYGEN: 0 ENABLE_OPTIMIZED: 1 ENABLE_DEBUG: 1 - ENABLE_WARNINGS_AS_ERRORS: {{ github.event.inputs.logLevel }} + ENABLE_WARNINGS_AS_ERRORS: ${{ github.event_name == 'workflow_dispatch' && inputs.warnings_as_errors || 1}} GTEST_VERSION: 1.11.0 KLEE_RUNTIME_BUILD: "Debug+Asserts" LLVM_VERSION: 11 From 9c2d2359af4e099959061fe80ed9b34652188c41 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 21 Aug 2024 18:03:52 +0200 Subject: [PATCH 34/40] fix: --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 816eeba2cb..f1244a2410 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,7 +10,7 @@ task: build_script: - mkdir build - cd build - - cmake -DLLVM_DIR=/usr/local/llvm13 -DMAKE_BINARY=/usr/local/bin/gmake -DJSON_SRC_DIR=/usr/local -DIMMER_SRC_DIR=/usr/local -DENABLE_TCMALLOC:BOOL=true -DENABLE_POSIX_RUNTIME:BOOL=ON -DENABLE_SOLVER_Z3:BOOL=true -DENABLE_SYSTEM_TESTS:BOOL=ON -DENABLE_WARNINGS_AS_ERRORS=0 .. + - cmake -DLLVM_DIR=/usr/local/llvm13 -DMAKE_BINARY=/usr/local/bin/gmake -DJSON_SRC_DIR=/usr/local -DIMMER_SRC_DIR=/usr/local -DENABLE_TCMALLOC:BOOL=true -DENABLE_POSIX_RUNTIME:BOOL=ON -DENABLE_SOLVER_Z3:BOOL=true -DENABLE_SYSTEM_TESTS:BOOL=ON -DENABLE_WARNINGS_AS_ERRORS=1 .. - gmake test_script: - sed -i.bak -e 's/lit\./lit13\./' test/lit.cfg From c691dbecbcc53ae2e5e180688cbb9ff42215517c Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 21 Aug 2024 19:18:51 +0200 Subject: [PATCH 35/40] fix: --- lib/Core/ExternalDispatcher.cpp | 6 +----- lib/Core/SpecialFunctionHandler.cpp | 4 ++-- lib/Solver/STPSolver.cpp | 2 +- runtime/CMakeLists.txt | 2 +- tools/kleaver/CMakeLists.txt | 6 ++---- unittests/Searcher/CMakeLists.txt | 3 ++- 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/Core/ExternalDispatcher.cpp b/lib/Core/ExternalDispatcher.cpp index 66a4fbbb0e..4f6a291047 100644 --- a/lib/Core/ExternalDispatcher.cpp +++ b/lib/Core/ExternalDispatcher.cpp @@ -306,17 +306,13 @@ Function *ExternalDispatcherImpl::createDispatcher(KCallable *target, llvm::IRBuilder<> Builder(dBB); // Get a Value* for &gTheArgsP, as an i64**. -#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) auto argI64sp = Builder.CreateIntToPtr( ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)&gTheArgsP), PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))), "argsp"); +#if LLVM_VERSION_CODE >= LLVM_VERSION(15, 0) auto argI64s = Builder.CreateLoad(Builder.getPtrTy(), argI64sp, "args"); #else - auto argI64sp = Builder.CreateIntToPtr( - ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)(void *)&gTheArgsP), - PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))), - "argsp"); auto argI64s = Builder.CreateLoad( argI64sp->getType()->getPointerElementType(), argI64sp, "args"); #endif diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp index 62557719a2..bd8fa2c255 100644 --- a/lib/Core/SpecialFunctionHandler.cpp +++ b/lib/Core/SpecialFunctionHandler.cpp @@ -206,7 +206,7 @@ SpecialFunctionHandler::SpecialFunctionHandler(Executor &_executor) void SpecialFunctionHandler::prepare( std::vector &preservedFunctions) { - for (auto &hi : handlerInfo) { + for (const auto &hi : handlerInfo) { Function *f = executor.kmodule->module->getFunction(hi.name); // No need to create if the function doesn't exist, since it cannot @@ -227,7 +227,7 @@ void SpecialFunctionHandler::prepare( } void SpecialFunctionHandler::bind() { - for (auto &hi : handlerInfo) { + for (const auto &hi : handlerInfo) { Function *f = executor.kmodule->module->getFunction(hi.name); if (f && (!hi.doNotOverride || f->isDeclaration())) { diff --git a/lib/Solver/STPSolver.cpp b/lib/Solver/STPSolver.cpp index 053b34824a..98b80ac20d 100644 --- a/lib/Solver/STPSolver.cpp +++ b/lib/Solver/STPSolver.cpp @@ -214,7 +214,7 @@ std::string STPSolverImpl::getConstraintLog(const Query &query) { vc_printQueryStateToBuffer(vc, builder->getFalse(), &buffer, &length, false); vc_pop(vc); - std::string result = buffer; + std::string result(buffer); std::free(buffer); return result; diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 3e7b3bc2e1..42600a57df 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -42,7 +42,7 @@ foreach (bc_architecture ${bc_architectures}) elseif (bc_optimization STREQUAL "Release+Debug+Asserts") list(APPEND local_flags -O2 -g -D_DEBUG) elseif (bc_optimization STREQUAL "Debug") - list(APPEND local_flags -g -D_DEBUG -DNDEBUG) + list(APPEND local_flags -g -D_DEBUG --fpermissive) elseif (bc_optimization STREQUAL "Debug+Asserts") list(APPEND local_flags -g -D_DEBUG) else() diff --git a/tools/kleaver/CMakeLists.txt b/tools/kleaver/CMakeLists.txt index 4b4cf8de59..dda7b1be65 100644 --- a/tools/kleaver/CMakeLists.txt +++ b/tools/kleaver/CMakeLists.txt @@ -13,12 +13,10 @@ add_executable(kleaver llvm_config(kleaver "${USE_LLVM_SHARED}" core support) target_link_libraries(kleaver PRIVATE kleaverSolver) -target_include_directories(klee SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) -target_include_directories(klee PRIVATE ${KLEE_INCLUDE_DIRS}) +target_include_directories(kleaver SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) +target_include_directories(kleaver PRIVATE ${KLEE_INCLUDE_DIRS}) target_compile_options(kleaver PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(kleaver PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) -target_compile_definitions(kleaver PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) - install(TARGETS kleaver RUNTIME DESTINATION bin) diff --git a/unittests/Searcher/CMakeLists.txt b/unittests/Searcher/CMakeLists.txt index 7132f1d617..5f5347cc45 100644 --- a/unittests/Searcher/CMakeLists.txt +++ b/unittests/Searcher/CMakeLists.txt @@ -5,4 +5,5 @@ target_include_directories(SearcherTest BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/lib" target_compile_options(SearcherTest PRIVATE ${KLEE_COMPONENT_CXX_FLAGS}) target_compile_definitions(SearcherTest PRIVATE ${KLEE_COMPONENT_CXX_DEFINES}) -target_include_directories(SearcherTest PRIVATE ${KLEE_INCLUDE_DIRS} ${SQLite3_INCLUDE_DIRS}) +target_include_directories(SearcherTest SYSTEM PRIVATE ${SQLite3_INCLUDE_DIRS}) +target_include_directories(SearcherTest PRIVATE ${KLEE_INCLUDE_DIRS}) From 039fd2e41b9bb316e228f4e9218b6ce640813651 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 21 Aug 2024 20:43:05 +0200 Subject: [PATCH 36/40] fix: --- runtime/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 42600a57df..be7074a449 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -42,7 +42,7 @@ foreach (bc_architecture ${bc_architectures}) elseif (bc_optimization STREQUAL "Release+Debug+Asserts") list(APPEND local_flags -O2 -g -D_DEBUG) elseif (bc_optimization STREQUAL "Debug") - list(APPEND local_flags -g -D_DEBUG --fpermissive) + list(APPEND local_flags -g -D_DEBUG -fpermissive) elseif (bc_optimization STREQUAL "Debug+Asserts") list(APPEND local_flags -g -D_DEBUG) else() From a5bafde2472b911e08dd7c515d9adcd5e807a385 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 22 Aug 2024 12:00:16 +0200 Subject: [PATCH 37/40] fix: --- lib/Module/InstrumentLegacy.cpp | 2 +- lib/Module/ModuleHelper.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Module/InstrumentLegacy.cpp b/lib/Module/InstrumentLegacy.cpp index 9d7db4771a..0a05a40572 100644 --- a/lib/Module/InstrumentLegacy.cpp +++ b/lib/Module/InstrumentLegacy.cpp @@ -91,7 +91,7 @@ void klee::checkModule(bool DontVerify, llvm::Module *module) { void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, bool Simplify, bool WithFPRuntime, - SwitchImplType SwitchType, std::string EntryPoint, + SwitchImplType SwitchType, const std::string &EntryPoint, llvm::ArrayRef preservedFunctions, llvm::Module *module) { // Preserve all functions containing klee-related function calls from being diff --git a/lib/Module/ModuleHelper.h b/lib/Module/ModuleHelper.h index 89398adadf..d31a991347 100644 --- a/lib/Module/ModuleHelper.h +++ b/lib/Module/ModuleHelper.h @@ -22,7 +22,7 @@ enum class SwitchImplType { void optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, bool Simplify, bool WithFPRuntime, SwitchImplType SwitchType, - std::string EntryPoint, + const std::string &EntryPoint, llvm::ArrayRef preservedFunctions, llvm::Module *module); void checkModule(bool DontVerfify, llvm::Module *module); From 57bd8c3c083313b2c8737f5df7b1bbb7a144be27 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Thu, 22 Aug 2024 12:05:12 +0200 Subject: [PATCH 38/40] style: --- lib/Module/InstrumentLegacy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Module/InstrumentLegacy.cpp b/lib/Module/InstrumentLegacy.cpp index 0a05a40572..b7d0ee821d 100644 --- a/lib/Module/InstrumentLegacy.cpp +++ b/lib/Module/InstrumentLegacy.cpp @@ -91,7 +91,8 @@ void klee::checkModule(bool DontVerify, llvm::Module *module) { void klee::optimiseAndPrepare(bool OptimiseKLEECall, bool Optimize, bool Simplify, bool WithFPRuntime, - SwitchImplType SwitchType, const std::string &EntryPoint, + SwitchImplType SwitchType, + const std::string &EntryPoint, llvm::ArrayRef preservedFunctions, llvm::Module *module) { // Preserve all functions containing klee-related function calls from being From a0d346181ed670228a9330845460ab3f4fa89ae9 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 27 Aug 2024 15:21:08 +0200 Subject: [PATCH 39/40] fix: --- lib/Core/SeedInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Core/SeedInfo.cpp b/lib/Core/SeedInfo.cpp index 2e0b2e22ae..727439163d 100644 --- a/lib/Core/SeedInfo.cpp +++ b/lib/Core/SeedInfo.cpp @@ -83,7 +83,7 @@ void SeedInfo::patchSeed(const ExecutionState &state, ref condition, } } - for (auto const &[array, i] : directReads) { + for (const auto &[array, i] : directReads) { ref read = ReadExpr::create(UpdateList(array, 0), ConstantExpr::alloc(i, Expr::Int32)); From 8d0be58d5e46837b9e0c7333ecf006acc702d603 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Tue, 10 Sep 2024 14:01:33 +0200 Subject: [PATCH 40/40] fix: --- unittests/Annotations/AnnotationsTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/Annotations/AnnotationsTest.cpp b/unittests/Annotations/AnnotationsTest.cpp index 95385b9970..3ebe6c9a37 100644 --- a/unittests/Annotations/AnnotationsTest.cpp +++ b/unittests/Annotations/AnnotationsTest.cpp @@ -146,4 +146,4 @@ TEST(AnnotationsTest, WithOffsets) { const std::vector expectedOffset{"*", "10", "*", "&"}; ASSERT_EQ(actual.at("foo").returnStatements[0]->offset, expectedOffset); } -#endif \ No newline at end of file +#endif