From 5ae0e30595238367f340af269287fff582ec9083 Mon Sep 17 00:00:00 2001 From: Sergey Morozov Date: Tue, 12 Dec 2023 15:32:24 +0300 Subject: [PATCH] [feat] Introduces KValue --- base class for all KLEEs wrappers around llvm::* structures (KInstruction, KConstant, etc.) [feat] Model unsized globals as objects of symbolic size. --- include/klee/Core/Context.h | 2 + include/klee/Expr/SourceBuilder.h | 8 +- include/klee/Expr/SymbolicSource.h | 8 +- include/klee/Module/KCallable.h | 44 ++-- include/klee/Module/KInstruction.h | 24 ++- include/klee/Module/KModule.h | 72 +++++-- include/klee/Module/KValue.h | 60 ++++++ include/klee/Module/LocationInfo.h | 2 + lib/Core/DistanceCalculator.cpp | 10 +- lib/Core/ExecutionState.cpp | 17 +- lib/Core/ExecutionState.h | 2 +- lib/Core/Executor.cpp | 203 ++++++++++-------- lib/Core/Executor.h | 14 +- lib/Core/ExecutorUtil.cpp | 158 +++++++------- lib/Core/ExternalDispatcher.cpp | 4 +- lib/Core/SpecialFunctionHandler.cpp | 12 +- lib/Core/StatsTracker.cpp | 8 +- lib/Core/TargetCalculator.cpp | 16 +- lib/Core/TargetManager.cpp | 7 +- lib/Core/TargetedExecutionManager.cpp | 12 +- lib/Expr/ExprPPrinter.cpp | 15 +- lib/Expr/Parser.cpp | 6 +- lib/Expr/Path.cpp | 2 +- lib/Expr/SourceBuilder.cpp | 3 +- lib/Expr/SymbolicSource.cpp | 8 +- lib/Module/CMakeLists.txt | 1 + lib/Module/CodeGraphInfo.cpp | 28 +-- lib/Module/KInstruction.cpp | 19 +- lib/Module/KModule.cpp | 64 +++--- lib/Module/KValue.cpp | 30 +++ lib/Module/LocationInfo.cpp | 23 ++ lib/Module/SarifReport.cpp | 4 +- lib/Solver/BitwuzlaSolver.cpp | 2 +- .../SymbolicSizes/SymbolicSizeUnsizedGlobal.c | 14 ++ 34 files changed, 579 insertions(+), 323 deletions(-) create mode 100644 include/klee/Module/KValue.h create mode 100644 lib/Module/KValue.cpp create mode 100644 test/Feature/SymbolicSizes/SymbolicSizeUnsizedGlobal.c diff --git a/include/klee/Core/Context.h b/include/klee/Core/Context.h index 64f209baaa..34298eb37e 100644 --- a/include/klee/Core/Context.h +++ b/include/klee/Core/Context.h @@ -40,6 +40,8 @@ class Context { /// Returns width of the pointer in bits Expr::Width getPointerWidth() const { return PointerWidth; } + + Expr::Width getPointerWidthInBytes() const { return PointerWidth / CHAR_BIT; } }; } // namespace klee diff --git a/include/klee/Expr/SourceBuilder.h b/include/klee/Expr/SourceBuilder.h index 6869ad0753..9a3e2035ee 100644 --- a/include/klee/Expr/SourceBuilder.h +++ b/include/klee/Expr/SourceBuilder.h @@ -1,13 +1,13 @@ #ifndef KLEE_SOURCEBUILDER_H #define KLEE_SOURCEBUILDER_H -#include "klee/ADT/Ref.h" -#include "klee/ADT/SparseStorage.h" #include "klee/Expr/SymbolicSource.h" -#include "klee/Module/KModule.h" namespace klee { +template class SparseStorage; +template class ref; + class SourceBuilder { public: SourceBuilder() = delete; @@ -18,7 +18,7 @@ class SourceBuilder { static ref uninitialized(unsigned version, const KInstruction *allocSite); static ref - symbolicSizeConstantAddress(unsigned version, const KInstruction *allocSite, + symbolicSizeConstantAddress(unsigned version, const KValue *allocSite, ref size); static ref makeSymbolic(const std::string &name, unsigned version); diff --git a/include/klee/Expr/SymbolicSource.h b/include/klee/Expr/SymbolicSource.h index 5829855543..6853e4715d 100644 --- a/include/klee/Expr/SymbolicSource.h +++ b/include/klee/Expr/SymbolicSource.h @@ -23,7 +23,9 @@ namespace klee { class Array; class Expr; class ConstantExpr; +struct KGlobalVariable; class KModule; +struct KValue; struct KInstruction; class SymbolicSource { @@ -125,10 +127,10 @@ class UninitializedSource : public SymbolicSource { class SymbolicSizeConstantAddressSource : public SymbolicSource { public: const unsigned version; - const KInstruction *allocSite; + const KValue *allocSite; ref size; - SymbolicSizeConstantAddressSource(unsigned _version, - const KInstruction *_allocSite, + + SymbolicSizeConstantAddressSource(unsigned _version, const KValue *_allocSite, ref _size) : version(_version), allocSite(_allocSite), size(_size) {} diff --git a/include/klee/Module/KCallable.h b/include/klee/Module/KCallable.h index ade28cfc82..a54a1c32dc 100644 --- a/include/klee/Module/KCallable.h +++ b/include/klee/Module/KCallable.h @@ -12,6 +12,7 @@ #include +#include "klee/Module/KValue.h" #include "klee/Support/CompilerWarning.h" DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS @@ -19,57 +20,52 @@ DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/IR/Function.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/Support/Casting.h" DISABLE_WARNING_POP namespace klee { /// Wrapper for callable objects passed in callExternalFunction -class KCallable { -public: - enum CallableKind { CK_Function, CK_InlineAsm }; - -private: - const CallableKind Kind; +class KCallable : public KValue { +protected: + KCallable(llvm::Value *value, KValue::Kind kind) : KValue(value, kind) {} public: - KCallable(CallableKind Kind) : Kind(Kind) {} - - CallableKind getKind() const { return Kind; } - - virtual llvm::StringRef getName() const = 0; virtual llvm::FunctionType *getFunctionType() const = 0; - virtual llvm::Value *getValue() = 0; - virtual ~KCallable() = default; + static bool classof(const KValue *rhs) { + return rhs->getKind() == KValue::Kind::FUNCTION || + rhs->getKind() == KValue::Kind::INLINE_ASM; + } }; class KInlineAsm : public KCallable { private: + /* Prepared name of ASM code */ + std::string name; + static unsigned getFreshAsmId() { static unsigned globalId = 0; return globalId++; } - llvm::InlineAsm *value; - std::string name; - public: - KInlineAsm(llvm::InlineAsm *value) - : KCallable(CK_InlineAsm), value(value), + KInlineAsm(llvm::InlineAsm *inlineAsm) + : KCallable(inlineAsm, KValue::Kind::INLINE_ASM), name("__asm__" + llvm::Twine(getFreshAsmId()).str()) {} llvm::StringRef getName() const override { return name; } llvm::FunctionType *getFunctionType() const override { - return value->getFunctionType(); + return inlineAsm()->getFunctionType(); } - llvm::Value *getValue() override { return value; } - - static bool classof(const KCallable *callable) { - return callable->getKind() == CK_InlineAsm; + static bool classof(const KValue *rhs) { + return rhs->getKind() == KValue::Kind::INLINE_ASM; } - llvm::InlineAsm *getInlineAsm() { return value; } + [[nodiscard]] llvm::InlineAsm *inlineAsm() const { + return llvm::dyn_cast(value); + } }; } // namespace klee diff --git a/include/klee/Module/KInstruction.h b/include/klee/Module/KInstruction.h index a4ee2c9c44..872f433d63 100644 --- a/include/klee/Module/KInstruction.h +++ b/include/klee/Module/KInstruction.h @@ -11,6 +11,8 @@ #define KLEE_KINSTRUCTION_H #include "KModule.h" +#include "KValue.h" + #include "klee/Config/Version.h" #include "klee/Support/CompilerWarning.h" #include "llvm/IR/Argument.h" @@ -37,7 +39,7 @@ static const unsigned MAGIC_HASH_CONSTANT = 39; /// KInstruction - Intermediate instruction representation used /// during execution. -struct KInstruction { +struct KInstruction : public KValue { struct Index { unsigned long instID; @@ -66,7 +68,9 @@ struct KInstruction { } }; - llvm::Instruction *inst; + llvm::Instruction *inst() const { + return llvm::dyn_cast_or_null(value); + } /// Value numbers for each operand. -1 is an invalid value, /// otherwise negative numbers are indices (negated and offset by @@ -113,14 +117,24 @@ struct KInstruction { [[nodiscard]] inline KFunction *getKFunction() const { return getKBlock()->parent; } - bool operator<(const KInstruction &other) const { - return getID() < other.getID(); + + [[nodiscard]] bool operator<(const KValue &rhs) const override { + if (getKind() == rhs.getKind()) { + return getID() < cast(rhs).getID(); + } else { + return getKind() < rhs.getKind(); + } } + [[nodiscard]] inline KModule *getKModule() const { return getKFunction()->parent; } - unsigned hash() const { return getID().hash(); } + [[nodiscard]] unsigned hash() const override { return getID().hash(); } + + static bool classof(const KValue *rhs) { + return rhs->getKind() == Kind::INSTRUCTION; + } }; struct KGEPInstruction : KInstruction { diff --git a/include/klee/Module/KModule.h b/include/klee/Module/KModule.h index dfd00c101f..388cd73b14 100644 --- a/include/klee/Module/KModule.h +++ b/include/klee/Module/KModule.h @@ -13,12 +13,14 @@ #include "klee/Config/Version.h" #include "klee/Core/Interpreter.h" #include "klee/Module/KCallable.h" +#include "klee/Module/KValue.h" #include "klee/Support/CompilerWarning.h" DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/ADT/ArrayRef.h" #include "llvm/IR/CFG.h" +#include "llvm/Support/Casting.h" DISABLE_WARNING_POP #include @@ -57,11 +59,14 @@ template class ref; enum KBlockType { Base, Call, Return }; -struct KBlock { +struct KBlock : public KValue { KFunction *parent; - llvm::BasicBlock *basicBlock; KInstruction **instructions; + [[nodiscard]] llvm::BasicBlock *basicBlock() const { + return llvm::dyn_cast_or_null(value); + } + public: KBlock(KFunction *, llvm::BasicBlock *, KModule *, const std::unordered_map &, @@ -74,7 +79,7 @@ struct KBlock { virtual KBlockType getKBlockType() const { return KBlockType::Base; } static bool classof(const KBlock *) { return true; } - unsigned getNumInstructions() const noexcept { return basicBlock->size(); } + unsigned getNumInstructions() const noexcept { return basicBlock()->size(); } KInstruction *getFirstInstruction() const noexcept { return instructions[0]; } KInstruction *getLastInstruction() const noexcept { return instructions[getNumInstructions() - 1]; @@ -84,6 +89,10 @@ struct KBlock { /// Block number in function [[nodiscard]] uintptr_t getId() const; + + static bool classof(const KValue *rhs) { + return rhs->getKind() == Kind::BLOCK ? classof(cast(rhs)) : false; + } }; typedef std::function KBlockPredicate; @@ -107,6 +116,10 @@ struct KCallBlock : KBlock { bool internal() const; bool kleeHandled() const; KFunction *getKFunction() const; + + static bool classof(const KValue *rhs) { + return rhs->getKind() == Kind::BLOCK ? classof(cast(rhs)) : false; + } }; struct KReturnBlock : KBlock { @@ -120,6 +133,10 @@ struct KReturnBlock : KBlock { return E->getKBlockType() == KBlockType::Return; } KBlockType getKBlockType() const override { return KBlockType::Return; }; + + static bool classof(const KValue *rhs) { + return rhs->getKind() == Kind::BLOCK ? classof(cast(rhs)) : false; + } }; struct KFunction : public KCallable { @@ -129,9 +146,12 @@ struct KFunction : public KCallable { public: KModule *parent; - llvm::Function *function; KInstruction **instructions; + [[nodiscard]] llvm::Function *function() const { + return llvm::dyn_cast_or_null(value); + } + [[nodiscard]] KInstruction *getInstructionByRegister(size_t reg) const; std::unordered_map instructionMap; @@ -158,12 +178,8 @@ struct KFunction : public KCallable { unsigned getArgRegister(unsigned index) const { return index; } - llvm::StringRef getName() const override { - return function ? function->getName() : ""; - } - llvm::FunctionType *getFunctionType() const override { - return function->getFunctionType(); + return function()->getFunctionType(); } const std::unordered_map &getLabelMap() { @@ -175,10 +191,8 @@ struct KFunction : public KCallable { return labelMap; } - llvm::Value *getValue() override { return function; } - - static bool classof(const KCallable *callable) { - return callable->getKind() == CK_Function; + static bool classof(const KValue *callable) { + return callable->getKind() == KValue::Kind::FUNCTION; } [[nodiscard]] size_t getLine() const; @@ -203,10 +217,12 @@ struct KFunctionCompare { } }; -class KConstant { +struct KConstant : public KValue { public: /// Actual LLVM constant this represents. - llvm::Constant *ct; + [[nodiscard]] llvm::Constant *ct() const { + return llvm::dyn_cast_or_null(value); + }; /// The constant ID. unsigned id; @@ -216,6 +232,28 @@ class KConstant { KInstruction *ki; KConstant(llvm::Constant *, unsigned, KInstruction *); + + [[nodiscard]] static bool classof(const KValue *rhs) { + return rhs->getKind() == KValue::Kind::CONSTANT; + } +}; + +struct KGlobalVariable : public KValue { +public: + KGlobalVariable(llvm::GlobalVariable *global); + + [[nodiscard]] llvm::GlobalVariable *globalVariable() const { + return llvm::dyn_cast_or_null(value); + } + + [[nodiscard]] static bool classof(const KValue *rhs) { + return rhs->getKind() == KValue::Kind::GLOBAL_VARIABLE; + } + + // Filename where the global variable is defined + [[nodiscard]] std::string getSourceFilepath() const; + // Line number where the global variable is defined + [[nodiscard]] size_t getLine() const; }; class KModule { @@ -248,6 +286,10 @@ class KModule { constantMap; KConstant *getKConstant(const llvm::Constant *c); + std::unordered_map> + globalMap; + std::unique_ptr constantTable; // Functions which are part of KLEE runtime diff --git a/include/klee/Module/KValue.h b/include/klee/Module/KValue.h new file mode 100644 index 0000000000..1a6367fc26 --- /dev/null +++ b/include/klee/Module/KValue.h @@ -0,0 +1,60 @@ +#ifndef KVALUE_H +#define KVALUE_H + +namespace llvm { +class Value; +class StringRef; +} // namespace llvm + +namespace klee { + +struct KValue { +public: + /* Enum of kinds for llvm rtti purposes */ + enum Kind { + BLOCK, + CONSTANT, + GLOBAL_VARIABLE, + FUNCTION, + INLINE_ASM, + INSTRUCTION, + VALUE, + }; + +protected: + /* Wrapped llvm::Value */ + llvm::Value *const value; + + /* Kind of KValue required for llvm rtti purposes */ + const Kind kind; + + /* Inner constructor for setting kind */ + KValue(llvm::Value *const value, const Kind kind) + : value(value), kind(kind) {} + +public: + /* Construct KValue from raw llvm::Value. */ + KValue(llvm::Value *const value) : KValue(value, Kind::VALUE) { + /* NB: heirs of this class should use inner constructor instead. + This constructor exposes convenient public interface. */ + } + + /* Unwraps KValue to receive inner value. */ + [[nodiscard]] llvm::Value *unwrap() const; + + /* Returns name of inner value if so exists. */ + [[nodiscard]] virtual llvm::StringRef getName() const; + + [[nodiscard]] virtual bool operator<(const KValue &rhs) const; + [[nodiscard]] virtual unsigned hash() const; + + /* Kind of value. Serves for llvm rtti purposes. */ + [[nodiscard]] Kind getKind() const { return kind; } + [[nodiscard]] static bool classof(const KValue *rhs) { return true; } + + virtual ~KValue() = default; +}; + +} // namespace klee + +#endif // KVALUE_H diff --git a/include/klee/Module/LocationInfo.h b/include/klee/Module/LocationInfo.h index 36ac6bec4d..6aaa84b8a2 100644 --- a/include/klee/Module/LocationInfo.h +++ b/include/klee/Module/LocationInfo.h @@ -15,6 +15,7 @@ namespace llvm { class Function; +class GlobalVariable; class Instruction; class Module; } // namespace llvm @@ -29,6 +30,7 @@ struct LocationInfo { LocationInfo getLocationInfo(const llvm::Function *func); LocationInfo getLocationInfo(const llvm::Instruction *inst); +LocationInfo getLocationInfo(const llvm::GlobalVariable *global); } // namespace klee diff --git a/lib/Core/DistanceCalculator.cpp b/lib/Core/DistanceCalculator.cpp index 26aa37350a..c5877bb09a 100644 --- a/lib/Core/DistanceCalculator.cpp +++ b/lib/Core/DistanceCalculator.cpp @@ -106,7 +106,7 @@ DistanceResult DistanceCalculator::getDistance( unsigned int minCallWeight = UINT_MAX, minSfNum = UINT_MAX, sfNum = 0; auto sfi = frames.rbegin(), sfe = frames.rend(); bool strictlyAfterKB = - sfi != sfe && sfi->kf->parent->inMainModule(*sfi->kf->function); + sfi != sfe && sfi->kf->parent->inMainModule(*sfi->kf->function()); for (; sfi != sfe; sfi++, sfNum++) { unsigned callWeight; if (distanceInCallGraph(sfi->kf, kb, callWeight, distanceToTargetFunction, @@ -140,8 +140,8 @@ bool DistanceCalculator::distanceInCallGraph( KFunction *kf, KBlock *origKB, unsigned int &distance, const FunctionDistanceMap &distanceToTargetFunction, KBlock *targetKB, bool strictlyAfterKB) const { - auto &dist = codeGraphInfo.getDistance(origKB->basicBlock); - if (kf == targetKB->parent && dist.count(targetKB->basicBlock)) { + auto &dist = codeGraphInfo.getDistance(origKB->basicBlock()); + if (kf == targetKB->parent && dist.count(targetKB->basicBlock())) { distance = 0; return true; } @@ -149,7 +149,7 @@ bool DistanceCalculator::distanceInCallGraph( distance = UINT_MAX; bool cannotReachItself = strictlyAfterKB && !codeGraphInfo.hasCycle(origKB); for (auto kCallBlock : kf->kCallBlocks) { - if (!dist.count(kCallBlock->basicBlock) || + if (!dist.count(kCallBlock->basicBlock()) || (cannotReachItself && origKB == kCallBlock)) continue; for (auto calledFunction : kCallBlock->calledFunctions) { @@ -167,7 +167,7 @@ WeightResult DistanceCalculator::tryGetLocalWeight( const auto &dist = codeGraphInfo.getDistance(kb); weight = UINT_MAX; for (auto end : localTargets) { - auto it = dist.find(end->basicBlock); + auto it = dist.find(end->basicBlock()); if (it != dist.end()) weight = std::min(it->second, weight); } diff --git a/lib/Core/ExecutionState.cpp b/lib/Core/ExecutionState.cpp index 6c5d4f9128..1d4d06f927 100644 --- a/lib/Core/ExecutionState.cpp +++ b/lib/Core/ExecutionState.cpp @@ -208,7 +208,7 @@ ExecutionState *ExecutionState::withStackFrame(KInstIterator caller, ExecutionState *newState = new ExecutionState(*this); newState->setID(); newState->pushFrame(caller, kf); - newState->initPC = kf->blockMap[&*kf->function->begin()]->instructions; + newState->initPC = kf->blockMap[&*kf->function()->begin()]->instructions; newState->pc = newState->initPC; newState->prevPC = newState->pc; return newState; @@ -387,9 +387,9 @@ void ExecutionState::dumpStack(llvm::raw_ostream &out) const { const CallStackFrame &csf = stack.callStack().at(ri); const StackFrame &sf = stack.valueStack().at(ri); - Function *f = csf.kf->function; + Function *f = csf.kf->function(); out << "\t#" << i; - auto assemblyLine = target->getKModule()->getAsmLine(target->inst); + auto assemblyLine = target->getKModule()->getAsmLine(target->inst()); if (assemblyLine.has_value()) { std::stringstream AsmStream; AsmStream << std::setw(8) << std::setfill('0') << assemblyLine.value(); @@ -431,14 +431,16 @@ void ExecutionState::addCexPreference(const ref &cond) { } BasicBlock *ExecutionState::getInitPCBlock() const { - return initPC->inst->getParent(); + return initPC->inst()->getParent(); } BasicBlock *ExecutionState::getPrevPCBlock() const { - return prevPC->inst->getParent(); + return prevPC->inst()->getParent(); } -BasicBlock *ExecutionState::getPCBlock() const { return pc->inst->getParent(); } +BasicBlock *ExecutionState::getPCBlock() const { + return pc->inst()->getParent(); +} void ExecutionState::increaseLevel() { llvm::BasicBlock *srcbb = getPrevPCBlock(); @@ -446,7 +448,8 @@ void ExecutionState::increaseLevel() { KFunction *kf = prevPC->parent->parent; KModule *kmodule = kf->parent; - if (prevPC->inst->isTerminator() && kmodule->inMainModule(*kf->function)) { + if (prevPC->inst()->isTerminator() && + kmodule->inMainModule(*kf->function())) { auto srcLevel = stack.infoStack().back().multilevel[srcbb].second; stack.infoStack().back().multilevel.replace({srcbb, srcLevel + 1}); level.insert(prevPC->parent); diff --git a/lib/Core/ExecutionState.h b/lib/Core/ExecutionState.h index 74ba2c67d4..dd0fd13427 100644 --- a/lib/Core/ExecutionState.h +++ b/lib/Core/ExecutionState.h @@ -498,7 +498,7 @@ class ExecutionState { inline bool isCycled(unsigned long long bound) const { if (bound == 0) return false; - if (prevPC->inst->isTerminator() && stack.size() > 0) { + if (prevPC->inst()->isTerminator() && stack.size() > 0) { auto &ml = stack.infoStack().back().multilevel; auto level = ml.find(getPCBlock()); return level != ml.end() && level->second > bound; diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 8fab82715d..89fe7eb2f8 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -751,7 +751,7 @@ void Executor::initializeGlobalObject(ExecutionState &state, ObjectState *os, offset + i * elementSize); } else if (!isa(c) && !isa(c)) { unsigned StoreBits = targetData->getTypeStoreSizeInBits(c->getType()); - ref C = evalConstant(c, state.roundingMode); + ref C = evalConstant(c, state.roundingMode); if (c->getType()->isFloatingPointTy() && Context::get().getPointerWidth() == 32) { @@ -762,7 +762,7 @@ void Executor::initializeGlobalObject(ExecutionState &state, ObjectState *os, // Extend the constant if necessary; assert(StoreBits >= C->getWidth() && "Invalid store size!"); if (StoreBits > C->getWidth()) - C = C->ZExt(StoreBits); + C = ZExtExpr::create(C, StoreBits); os->write(offset, C); } @@ -903,10 +903,10 @@ void Executor::allocateGlobalObjects(ExecutionState &state) { for (const GlobalVariable &v : m->globals()) { std::size_t globalObjectAlignment = getAllocationAlignment(&v); Type *ty = v.getValueType(); - std::uint64_t size = 0; + ref size = Expr::createPointer(0); if (ty->isSized()) { // size includes padding - size = kmodule->targetData->getTypeAllocSize(ty); + size = Expr::createPointer(kmodule->targetData->getTypeAllocSize(ty)); } if (v.isDeclaration()) { // FIXME: We have no general way of handling unknown external @@ -922,30 +922,33 @@ void Executor::allocateGlobalObjects(ExecutionState &state) { // XXX - DWD - hardcode some things until we decide how to fix. #ifndef WINDOWS if (v.getName() == "_ZTVN10__cxxabiv117__class_type_infoE") { - size = 0x2C; + size = Expr::createPointer(0x2C); } else if (v.getName() == "_ZTVN10__cxxabiv120__si_class_type_infoE") { - size = 0x2C; + size = Expr::createPointer(0x2C); } else if (v.getName() == "_ZTVN10__cxxabiv121__vmi_class_type_infoE") { - size = 0x2C; + size = Expr::createPointer(0x2C); } #endif - if (size == 0) { - klee_warning("Unable to find size for global variable: %.*s (use will " - "result in out of bounds access)", + if (size->isZero()) { + const Array *array = makeArray( + Expr::createPointer(Context::get().getPointerWidthInBytes()), + SourceBuilder::irreproducible(v.getName().str())); + size = Expr::createTempRead(array, Context::get().getPointerWidth()); + klee_warning("Unable to find size for global variable: %.*s (model " + "size as symbolic with irreproducible content)", static_cast(v.getName().size()), v.getName().data()); } } - MemoryObject *mo = - memory->allocate(size, /*isLocal=*/false, - /*isGlobal=*/true, false, /*allocSite=*/&v, - /*alignment=*/globalObjectAlignment); + MemoryObject *mo = allocate(state, size, /*isLocal=*/false, + /*isGlobal=*/true, /*allocSite=*/&v, + /*alignment=*/globalObjectAlignment); if (!mo) klee_error("out of memory"); globalObjects.emplace(&v, mo); - globalAddresses.emplace(&v, mo->getBaseConstantExpr()); + globalAddresses.emplace(&v, mo->getBaseExpr()); } } @@ -998,26 +1001,32 @@ void Executor::initializeGlobalObjects(ExecutionState &state) { state, mo, typeSystemManager->getWrappedType(v.getType()), false, nullptr); - if (v.isDeclaration() && mo->size) { - // Program already running -> object already initialized. - // Read concrete value and write it to our copy. - void *addr; - if (v.getName() == "__dso_handle") { - addr = &__dso_handle; // wtf ? + if (v.isDeclaration()) { + if (isa(mo->getSizeExpr())) { + // Program already running -> object already initialized. + // Read concrete value and write it to our copy. + void *addr; + if (v.getName() == "__dso_handle") { + addr = &__dso_handle; // wtf ? + } else { + addr = externalDispatcher->resolveSymbol(v.getName().str()); + } + if (MockAllExternals && !addr) { + executeMakeSymbolic( + state, mo, typeSystemManager->getWrappedType(v.getType()), + SourceBuilder::irreproducible("mockExternGlobalObject"), false); + } else if (!addr) { + klee_error("Unable to load symbol(%.*s) while initializing globals", + static_cast(v.getName().size()), v.getName().data()); + } else { + for (unsigned offset = 0; offset < mo->size; offset++) { + os->write8(offset, static_cast(addr)[offset]); + } + } } else { - addr = externalDispatcher->resolveSymbol(v.getName().str()); - } - if (MockAllExternals && !addr) { executeMakeSymbolic( state, mo, typeSystemManager->getWrappedType(v.getType()), - SourceBuilder::irreproducible("mockExternGlobalObject"), false); - } else if (!addr) { - klee_error("Unable to load symbol(%.*s) while initializing globals", - static_cast(v.getName().size()), v.getName().data()); - } else { - for (unsigned offset = 0; offset < mo->size; offset++) { - os->write8(offset, static_cast(addr)[offset]); - } + SourceBuilder::irreproducible("unsizedGlobal"), false); } } else if (v.hasInitializer()) { if (!v.isConstant() && kmodule->inMainModule(v) && @@ -1544,7 +1553,7 @@ void Executor::addConstraint(ExecutionState &state, ref condition) { const Cell &Executor::eval(const KInstruction *ki, unsigned index, ExecutionState &state, StackFrame &sf, bool isSymbolic) { - assert(index < ki->inst->getNumOperands()); + assert(index < ki->inst()->getNumOperands()); int vnumber = ki->operands[index]; assert(vnumber != -1 && @@ -1698,7 +1707,7 @@ void Executor::printDebugInstructions(ExecutionState &state) { (*stream) << " " << state.pc->getSourceLocationString() << ':'; } { - auto asmLine = state.pc->getKModule()->getAsmLine(state.pc->inst); + auto asmLine = state.pc->getKModule()->getAsmLine(state.pc->inst()); if (asmLine.has_value()) { (*stream) << asmLine.value() << ':'; } @@ -1712,7 +1721,7 @@ void Executor::printDebugInstructions(ExecutionState &state) { if (DebugPrintInstructions.isSet(STDERR_ALL) || DebugPrintInstructions.isSet(FILE_ALL)) - (*stream) << ':' << *(state.pc->inst); + (*stream) << ':' << *(state.pc->inst()); (*stream) << '\n'; @@ -1733,7 +1742,7 @@ void Executor::stepInstruction(ExecutionState &state) { ++stats::instructions; ++state.steppedInstructions; - if (isa(state.pc->inst) || isa(state.pc->inst)) { + if (isa(state.pc->inst()) || isa(state.pc->inst())) { ++state.steppedMemoryInstructions; } state.prevPC = state.pc; @@ -1783,7 +1792,11 @@ MemoryObject *Executor::serializeLandingpad(ExecutionState &state, llvm::GlobalValue *clause_type = dyn_cast(clause_bitcast->getOperand(0)); - ti_addr = globalAddresses[clause_type]->getZExtValue(); + // Since global variable may have symbolic address, + // here we must guarantee that the address of clause is + // constant (which seems to be true). + ti_addr = + cast(globalAddresses[clause_type])->getZExtValue(); } else if (current_clause->isNullValue()) { ti_addr = 0; } else { @@ -1843,8 +1856,10 @@ MemoryObject *Executor::serializeLandingpad(ExecutionState &state, return nullptr; } + // We assume again that the clause_value is a + // constant global. std::uint64_t const ti_addr = - globalAddresses[clause_value]->getZExtValue(); + cast(globalAddresses[clause_value])->getZExtValue(); const std::size_t old_size = serialized.size(); serialized.resize(old_size + 8); @@ -1888,7 +1903,7 @@ void Executor::unwindToNextLandingpad(ExecutionState &state) { for (std::size_t i = startIndex; i > lowestStackIndex; i--) { auto const &sf = state.stack.callStack().at(i); - Instruction *inst = sf.caller ? sf.caller->inst : nullptr; + Instruction *inst = sf.caller ? sf.caller->inst() : nullptr; if (popFrames) { state.popFrame(); @@ -1993,7 +2008,7 @@ ref Executor::getEhTypeidFor(ref type_info) { void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, std::vector> &arguments) { - Instruction *i = ki->inst; + Instruction *i = ki->inst(); if (isa_and_nonnull(i)) return; if (f && f->isDeclaration()) { @@ -2316,7 +2331,7 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, KFunction *kf = kmodule->functionMap[f]; state.pushFrame(state.prevPC, kf); - transferToBasicBlock(&*kf->function->begin(), state.getPrevPCBlock(), + transferToBasicBlock(&*kf->function()->begin(), state.getPrevPCBlock(), state); if (statsTracker) @@ -2401,7 +2416,7 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, StackFrame &sf = state.stack.valueStack().back(); MemoryObject *mo = sf.varargs = - memory->allocate(size, true, false, false, state.prevPC->inst, + memory->allocate(size, true, false, false, state.prevPC->inst(), (requires16ByteAlignment ? 16 : 8)); if (!mo && size) { terminateStateOnExecError(state, "out of memory (varargs)"); @@ -2484,8 +2499,8 @@ void Executor::transferToBasicBlock(KBlock *kdst, BasicBlock *src, // XXX this lookup has to go ? state.pc = kdst->instructions; state.increaseLevel(); - if (state.pc->inst->getOpcode() == Instruction::PHI) { - PHINode *first = static_cast(state.pc->inst); + if (state.pc->inst()->getOpcode() == Instruction::PHI) { + PHINode *first = static_cast(state.pc->inst()); state.incomingBBIndex = first->getBasicBlockIndex(src); } increaseProgressVelocity(state, kdst); @@ -2525,7 +2540,7 @@ void Executor::checkNullCheckAfterDeref(ref cond, ExecutionState &state, } void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { - Instruction *i = ki->inst; + Instruction *i = ki->inst(); if (guidanceKind == GuidanceKind::ErrorGuidance) { for (auto kvp : state.targetForest) { @@ -2545,7 +2560,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { case Instruction::Ret: { ReturnInst *ri = cast(i); KInstIterator kcaller = state.stack.callStack().back().caller; - Instruction *caller = kcaller ? kcaller->inst : nullptr; + Instruction *caller = kcaller ? kcaller->inst() : nullptr; bool isVoidReturn = (ri->getNumOperands() == 0); ref result = ConstantExpr::alloc(0, Expr::Bool); @@ -2991,7 +3006,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { do { if (!first && MockExternalCalls) { free = nullptr; - if (ki->inst->getType()->isSized()) { + if (ki->inst()->getType()->isSized()) { prepareMockValue(state, "mockExternResult", ki); } } else { @@ -3280,7 +3295,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { executeMemoryOperation( state, false, typeSystemManager->getWrappedType( - cast(ki->inst)->getPointerOperandType()), + cast(ki->inst())->getPointerOperandType()), base, 0, ki); break; } @@ -3290,14 +3305,15 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { executeMemoryOperation( state, true, typeSystemManager->getWrappedType( - cast(ki->inst)->getPointerOperandType()), + cast(ki->inst())->getPointerOperandType()), base, value, ki); break; } case Instruction::GetElementPtr: { KGEPInstruction *kgepi = static_cast(ki); - GetElementPtrInst *gepInst = static_cast(kgepi->inst); + GetElementPtrInst *gepInst = + static_cast(kgepi->inst()); ref base = eval(ki, 0, state).value; ref offset = ConstantExpr::create(0, base->getWidth()); @@ -3368,7 +3384,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { case Instruction::BitCast: { ref result = eval(ki, 0, state).value; - BitCastInst *bc = cast(ki->inst); + BitCastInst *bc = cast(ki->inst()); llvm::Type *castToType = bc->getType(); @@ -4129,7 +4145,7 @@ void Executor::computeOffsetsSeqTy(KGEPInstruction *kgepi, const Value *operand = it.getOperand(); if (const Constant *c = dyn_cast(operand)) { ref index = - evalConstant(c, llvm::APFloat::rmNearestTiesToEven) + cast(evalConstant(c, llvm::APFloat::rmNearestTiesToEven)) ->SExt(Context::get().getPointerWidth()); ref addend = index->Mul( ConstantExpr::alloc(elementSize, Context::get().getPointerWidth())); @@ -4161,14 +4177,14 @@ void Executor::computeOffsets(KGEPInstruction *kgepi, TypeIt ib, TypeIt ie) { } void Executor::bindInstructionConstants(KInstruction *KI) { - if (GetElementPtrInst *gepi = dyn_cast(KI->inst)) { + if (GetElementPtrInst *gepi = dyn_cast(KI->inst())) { KGEPInstruction *kgepi = static_cast(KI); computeOffsets(kgepi, gep_type_begin(gepi), gep_type_end(gepi)); - } else if (InsertValueInst *ivi = dyn_cast(KI->inst)) { + } 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"); - } else if (ExtractValueInst *evi = dyn_cast(KI->inst)) { + } 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"); @@ -4408,7 +4424,7 @@ void Executor::reportProgressTowardsTargets(std::string prefix, repr << ": "; } repr << "in function " + - target->getBlock()->parent->function->getName().str(); + target->getBlock()->parent->function()->getName().str(); repr << " (lines "; repr << target->getBlock()->getFirstInstruction()->getLine(); repr << " to "; @@ -4784,10 +4800,10 @@ Executor::getLastNonKleeInternalInstruction(const ExecutionState &state) { itE--; const KInstruction *ki = nullptr; - if (kmodule->internalFunctions.count(it->kf->function) == 0) { + if (kmodule->internalFunctions.count(it->kf->function()) == 0) { ki = state.prevPC; // Cannot return yet because even though - // it->function is not an internal function it might of + // it->function() is not an internal function it might of // been called from an internal function. } @@ -4797,7 +4813,7 @@ Executor::getLastNonKleeInternalInstruction(const ExecutionState &state) { for (; it != itE; ++it) { // check calling instruction and if it is contained in a KLEE internal // function - const Function *f = (*it->caller).inst->getParent()->getParent(); + const Function *f = (*it->caller).inst()->getParent()->getParent(); if (kmodule->internalFunctions.count(f)) { ki = nullptr; continue; @@ -4871,7 +4887,7 @@ void Executor::terminateStateOnError(ExecutionState &state, std::string message = messaget.str(); static std::set> emittedErrors; const KInstruction *ki = getLastNonKleeInternalInstruction(state); - Instruction *lastInst = ki->inst; + Instruction *lastInst = ki->inst(); if ((EmitAllErrors || emittedErrors.insert(std::make_pair(lastInst, message)).second) && @@ -4892,7 +4908,7 @@ void Executor::terminateStateOnError(ExecutionState &state, if (!filepath.empty()) { msg << "File: " << filepath << '\n' << "Line: " << ki->getLine() << '\n'; { - auto asmLine = ki->getKModule()->getAsmLine(ki->inst); + auto asmLine = ki->getKModule()->getAsmLine(ki->inst()); if (asmLine.has_value()) { msg << "assembly.ll line: " << asmLine.value() << '\n'; } @@ -4964,7 +4980,7 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, std::vector> &arguments) { // check if specialFunctionHandler wants it if (const auto *func = dyn_cast(callable)) { - if (specialFunctionHandler->handle(state, func->function, target, + if (specialFunctionHandler->handle(state, func->function(), target, arguments)) return; } @@ -4991,9 +5007,9 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, if (AllExternalWarnings) klee_warning("%s", os.str().c_str()); else if (!SuppressExternalWarnings) - klee_warning_once(callable->getValue(), "%s", os.str().c_str()); + klee_warning_once(callable->unwrap(), "%s", os.str().c_str()); - if (target->inst->getType()->isSized()) { + if (target->inst()->getType()->isSized()) { prepareMockValue(state, "mockExternResult", target); } return; @@ -5102,7 +5118,7 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, if (AllExternalWarnings) klee_warning("%s", os.str().c_str()); else - klee_warning_once(callable->getValue(), "%s", os.str().c_str()); + klee_warning_once(callable->unwrap(), "%s", os.str().c_str()); } int roundingMode = LLVMRoundingModeToCRoundingMode(state.roundingMode); @@ -5113,12 +5129,12 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, return; } - bool success = externalDispatcher->executeCall(callable, target->inst, args, + bool success = externalDispatcher->executeCall(callable, target->inst(), args, roundingMode); if (!success) { if (MockExternalCalls) { - if (target->inst->getType()->isSized()) { + if (target->inst()->getType()->isSized()) { prepareMockValue(state, "mockExternResult", target); } } else { @@ -5142,7 +5158,7 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, (uint64_t)&error, assignment); #endif - Type *resultType = target->inst->getType(); + Type *resultType = target->inst()->getType(); if (resultType != Type::getVoidTy(kmodule->module->getContext())) { ref e = ConstantExpr::fromMemory((void *)args, getWidthForLLVMType(resultType)); @@ -5219,7 +5235,7 @@ void Executor::executeAlloc(ExecutionState &state, ref size, bool isLocal, const ObjectState *reallocFrom, size_t allocationAlignment, bool checkOutOfMemory) { static unsigned allocations = 0; - const llvm::Value *allocSite = state.prevPC->inst; + const llvm::Value *allocSite = state.prevPC->inst(); if (allocationAlignment == 0) { allocationAlignment = getAllocationAlignment(allocSite); } @@ -5578,10 +5594,13 @@ MemoryObject *Executor::allocate(ExecutionState &state, ref size, Expr::Width pointerWidthInBits = Context::get().getPointerWidth(); /* Create symbol for array */ - KInstruction *ki = nullptr; + KValue *ki = nullptr; if (!lazyInitializationSource) { - auto inst = cast(allocSite); - ki = kmodule->getKBlock(inst->getParent())->parent->instructionMap[inst]; + if (auto inst = dyn_cast(allocSite)) { + ki = kmodule->getKBlock(inst->getParent())->parent->instructionMap[inst]; + } else if (auto global = dyn_cast(allocSite)) { + ki = kmodule->globalMap[global].get(); + } } const Array *addressArray = makeArray( @@ -6046,7 +6065,8 @@ void Executor::collectReads( ref result = os->read(mo->getOffsetExpr(address), type); - if (X86FPAsX87FP80 && state.prevPC->inst->getType()->isFloatingPointTy() && + if (X86FPAsX87FP80 && + state.prevPC->inst()->getType()->isFloatingPointTy() && Context::get().getPointerWidth() == 32) { result = FPToX87FP80Ext(result); } @@ -6071,7 +6091,8 @@ void Executor::executeMemoryOperation( KInstruction *target /* undef if write */) { KInstruction *ki = estate.prevPC; if (X86FPAsX87FP80 && isWrite) { - auto valueOperand = cast(ki->inst)->getValueOperand(); + auto valueOperand = + cast(ki->inst())->getValueOperand(); if (valueOperand->getType()->isFloatingPointTy() && Context::get().getPointerWidth() == 32) { value = @@ -6080,7 +6101,7 @@ void Executor::executeMemoryOperation( } } Expr::Width type = (isWrite ? value->getWidth() - : getWidthForLLVMType(target->inst->getType())); + : getWidthForLLVMType(target->inst()->getType())); unsigned bytes = Expr::getMinBytesForWidth(type); ref base = address; @@ -6221,7 +6242,7 @@ void Executor::executeMemoryOperation( } else { result = os->read(mo->getOffsetExpr(address), type); - if (X86FPAsX87FP80 && ki->inst->getType()->isFloatingPointTy() && + if (X86FPAsX87FP80 && ki->inst()->getType()->isFloatingPointTy() && Context::get().getPointerWidth() == 32) { result = FPToX87FP80Ext(result); } @@ -6416,7 +6437,7 @@ void Executor::executeMemoryOperation( } else { ref result = os->read(mo->getOffsetExpr(address), type); - if (X86FPAsX87FP80 && ki->inst->getType()->isFloatingPointTy() && + if (X86FPAsX87FP80 && ki->inst()->getType()->isFloatingPointTy() && Context::get().getPointerWidth() == 32) { result = FPToX87FP80Ext(result); } @@ -6458,7 +6479,7 @@ bool Executor::lazyInitializeObject(ExecutionState &state, ref address, KType *targetType, uint64_t size, bool isLocal, IDType &id, bool isSymbolic) { assert(!isa(address)); - const llvm::Value *allocSite = target ? target->inst : nullptr; + const llvm::Value *allocSite = target ? target->inst() : nullptr; std::pair, ref> moBasePair; unsigned timestamp = 0; if (state.getBase(address, moBasePair)) { @@ -6533,7 +6554,7 @@ bool Executor::lazyInitializeObject(ExecutionState &state, ref address, IDType Executor::lazyInitializeLocalObject(ExecutionState &state, StackFrame &sf, ref address, const KInstruction *target) { - AllocaInst *ai = cast(target->inst); + AllocaInst *ai = cast(target->inst()); unsigned elementSize = kmodule->targetData->getTypeStoreSize(ai->getAllocatedType()); ref size = Expr::createPointer(elementSize); @@ -6800,7 +6821,7 @@ ExecutionState *Executor::formState(Function *f, int argc, char **argv, MemoryObject *arg = allocate(*state, Expr::createPointer(len + 1), /*isLocal=*/false, /*isGlobal=*/true, - /*allocSite=*/state->pc->inst, /*alignment=*/8); + /*allocSite=*/state->pc->inst(), /*alignment=*/8); if (!arg) klee_error("Could not allocate memory for function arguments"); @@ -6885,10 +6906,10 @@ void Executor::runFunctionAsMain(Function *f, int argc, char **argv, for (auto &startFunctionAndWhiteList : prepTargets) { auto kf = - kmodule->functionMap.at(startFunctionAndWhiteList.first->function); + kmodule->functionMap.at(startFunctionAndWhiteList.first->function()); if (startFunctionAndWhiteList.second->empty()) { klee_warning("No targets found for %s", - kf->function->getName().str().c_str()); + kf->function()->getName().str().c_str()); continue; } auto whitelist = startFunctionAndWhiteList.second; @@ -6994,7 +7015,7 @@ bool isReturnValueFromInitBlock(const ExecutionState &state, const llvm::Value *value) { return state.initPC->parent->getKBlockType() == KBlockType::Call && state.initPC == state.initPC->parent->getLastInstruction() && - state.initPC->parent->getFirstInstruction()->inst == value; + state.initPC->parent->getFirstInstruction()->inst() == value; } ref Executor::makeSymbolicValue(llvm::Value *value, @@ -7016,9 +7037,9 @@ ref Executor::makeSymbolicValue(llvm::Value *value, void Executor::prepareSymbolicValue(ExecutionState &state, StackFrame &frame, KInstruction *target) { - ref result = makeSymbolicValue(target->inst, state); + ref result = makeSymbolicValue(target->inst(), state); bindLocal(target, frame, result); - if (isa(target->inst)) { + if (isa(target->inst())) { lazyInitializeLocalObject(state, frame, result, target); } } @@ -7028,7 +7049,7 @@ void Executor::prepareMockValue(ExecutionState &state, StackFrame &frame, KInstruction *target) { ref result = makeMockValue(state, name, width); bindLocal(target, frame, result); - if (isa(target->inst)) { + if (isa(target->inst())) { lazyInitializeLocalObject(state, frame, result, target); } } @@ -7036,7 +7057,7 @@ void Executor::prepareMockValue(ExecutionState &state, StackFrame &frame, void Executor::prepareMockValue(ExecutionState &state, const std::string &name, KInstruction *target) { Expr::Width width = - kmodule->targetData->getTypeSizeInBits(target->inst->getType()); + kmodule->targetData->getTypeSizeInBits(target->inst()->getType()); prepareMockValue(state, state.stack.valueStack().back(), name, width, target); } @@ -7055,9 +7076,9 @@ void Executor::prepareSymbolicArg(ExecutionState &state, StackFrame &frame, unsigned index) { KFunction *kf = frame.kf; #if LLVM_VERSION_CODE >= LLVM_VERSION(10, 0) - Argument *arg = kf->function->getArg(index); + Argument *arg = kf->function()->getArg(index); #else - Argument *arg = &kf->function->arg_begin()[index]; + Argument *arg = &kf->function()->arg_begin()[index]; #endif ref result = makeSymbolicValue(arg, state); bindArgument(kf, index, frame, result); @@ -7065,7 +7086,7 @@ void Executor::prepareSymbolicArg(ExecutionState &state, StackFrame &frame, void Executor::prepareSymbolicArgs(ExecutionState &state, StackFrame &frame) { KFunction *kf = frame.kf; - unsigned argSize = kf->function->arg_size(); + unsigned argSize = kf->function()->arg_size(); for (unsigned argNo = 0; argNo < argSize; ++argNo) { prepareSymbolicArg(state, frame, argNo); } @@ -7598,7 +7619,7 @@ void Executor::dumpStates() { for (auto sfIt = es->stack.callStack().begin(), sf_ie = es->stack.callStack().end(); sfIt != sf_ie; ++sfIt) { - *os << "('" << sfIt->kf->function->getName().str() << "',"; + *os << "('" << sfIt->kf->function()->getName().str() << "',"; if (next == es->stack.callStack().end()) { *os << es->prevPC->getLine() << "), "; } else { diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index 0f8d8eaf69..1ed917040b 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -180,7 +180,7 @@ class Executor : public Interpreter { /// Map of globals to their bound address. This also includes /// globals that have no representative object (i.e. functions). - std::map> globalAddresses; + std::map> globalAddresses; /// Map of legal function addresses to the corresponding Function. /// Used to validate and dereference function pointers. @@ -531,9 +531,9 @@ class Executor : public Interpreter { /// Evaluates an LLVM constant expression. The optional argument ki /// is the instruction where this constant was encountered, or NULL /// if not applicable/unavailable. - ref evalConstantExpr(const llvm::ConstantExpr *c, - llvm::APFloat::roundingMode rm, - const KInstruction *ki = NULL); + ref evalConstantExpr(const llvm::ConstantExpr *c, + llvm::APFloat::roundingMode rm, + const KInstruction *ki = NULL); /// Evaluates an LLVM float comparison. the operands are two float /// expressions. @@ -543,9 +543,9 @@ class Executor : public Interpreter { /// Evaluates an LLVM constant. The optional argument ki is the /// instruction where this constant was encountered, or NULL if /// not applicable/unavailable. - ref evalConstant(const llvm::Constant *c, - llvm::APFloat::roundingMode rm, - const KInstruction *ki = NULL); + ref evalConstant(const llvm::Constant *c, + llvm::APFloat::roundingMode rm, + const KInstruction *ki = NULL); /// Return a unique constant value for the given expression in the /// given state, if it has one (i.e. it provably only has a single diff --git a/lib/Core/ExecutorUtil.cpp b/lib/Core/ExecutorUtil.cpp index ce19fa74bf..534f264fee 100644 --- a/lib/Core/ExecutorUtil.cpp +++ b/lib/Core/ExecutorUtil.cpp @@ -69,9 +69,9 @@ ref FPToX87FP80Ext(ref arg) { return result; } -ref Executor::evalConstant(const Constant *c, - llvm::APFloat::roundingMode rm, - const KInstruction *ki) { +ref Executor::evalConstant(const Constant *c, + llvm::APFloat::roundingMode rm, + const KInstruction *ki) { if (!ki) { KConstant *kc = kmodule->getKConstant(c); if (kc) @@ -98,7 +98,7 @@ ref Executor::evalConstant(const Constant *c, return Expr::createPointer(0); } else if (isa(c) || isa(c)) { if (getWidthForLLVMType(c->getType()) == 0) { - if (isa(ki->inst)) { + if (isa(ki->inst())) { klee_warning_once( 0, "Using zero size array fix for landingpad instruction filter"); return ConstantExpr::create(0, 1); @@ -274,12 +274,12 @@ ref Executor::evaluateFCmp(unsigned int predicate, return result; } -ref Executor::evalConstantExpr(const llvm::ConstantExpr *ce, - llvm::APFloat::roundingMode rm, - const KInstruction *ki) { +ref Executor::evalConstantExpr(const llvm::ConstantExpr *ce, + llvm::APFloat::roundingMode rm, + const KInstruction *ki) { llvm::Type *type = ce->getType(); - ref op1(0), op2(0), op3(0); + ref op1(0), op2(0), op3(0); int numOperands = ce->getNumOperands(); if (numOperands > 0) @@ -294,23 +294,28 @@ ref Executor::evalConstantExpr(const llvm::ConstantExpr *ce, case Instruction::SDiv: case Instruction::UDiv: case Instruction::SRem: - case Instruction::URem: - if (op2->getLimitedValue() == 0) { - std::string msg( - "Division/modulo by zero during constant folding at location "); - llvm::raw_string_ostream os(msg); - os << (ki ? ki->getSourceLocationString() : "[unknown]"); - klee_error("%s", os.str().c_str()); + case Instruction::URem: { + if (auto op2Const = dyn_cast(op2)) { + if (op2Const->getLimitedValue() == 0) { + std::string msg( + "Division/modulo by zero during constant folding at location "); + llvm::raw_string_ostream os(msg); + os << (ki ? ki->getSourceLocationString() : "[unknown]"); + klee_error("%s", os.str().c_str()); + } } break; + } case Instruction::Shl: case Instruction::LShr: case Instruction::AShr: - if (op2->getLimitedValue() >= op1->getWidth()) { - std::string msg("Overshift during constant folding at location "); - llvm::raw_string_ostream os(msg); - os << (ki ? ki->getSourceLocationString() : "[unknown]"); - klee_error("%s", os.str().c_str()); + if (auto op2Const = dyn_cast(op2)) { + if (op2Const->getLimitedValue() >= op1->getWidth()) { + std::string msg("Overshift during constant folding at location "); + llvm::raw_string_ostream os(msg); + os << (ki ? ki->getSourceLocationString() : "[unknown]"); + klee_error("%s", os.str().c_str()); + } } } @@ -324,37 +329,37 @@ ref Executor::evalConstantExpr(const llvm::ConstantExpr *ce, klee_error("%s", os.str().c_str()); case Instruction::Trunc: - return op1->Extract(0, getWidthForLLVMType(type)); + return ExtractExpr::create(op1, 0, getWidthForLLVMType(type)); case Instruction::ZExt: - return op1->ZExt(getWidthForLLVMType(type)); + return ZExtExpr::create(op1, getWidthForLLVMType(type)); case Instruction::SExt: - return op1->SExt(getWidthForLLVMType(type)); + return SExtExpr::create(op1, getWidthForLLVMType(type)); case Instruction::Add: - return op1->Add(op2); + return AddExpr::create(op1, op2); case Instruction::Sub: - return op1->Sub(op2); + return SubExpr::create(op1, op2); case Instruction::Mul: - return op1->Mul(op2); + return MulExpr::create(op1, op2); case Instruction::SDiv: - return op1->SDiv(op2); + return SDivExpr::create(op1, op2); case Instruction::UDiv: - return op1->UDiv(op2); + return UDivExpr::create(op1, op2); case Instruction::SRem: - return op1->SRem(op2); + return SRemExpr::create(op1, op2); case Instruction::URem: - return op1->URem(op2); + return URemExpr::create(op1, op2); case Instruction::And: - return op1->And(op2); + return AndExpr::create(op1, op2); case Instruction::Or: - return op1->Or(op2); + return OrExpr::create(op1, op2); case Instruction::Xor: - return op1->Xor(op2); + return XorExpr::create(op1, op2); case Instruction::Shl: - return op1->Shl(op2); + return ShlExpr::create(op1, op2); case Instruction::LShr: - return op1->LShr(op2); + return LShrExpr::create(op1, op2); case Instruction::AShr: - return op1->AShr(op2); + return AShrExpr::create(op1, op2); case Instruction::BitCast: { ref result = op1; @@ -373,37 +378,43 @@ ref Executor::evalConstantExpr(const llvm::ConstantExpr *ce, } case Instruction::IntToPtr: - return op1->ZExt(getWidthForLLVMType(type)); + return ZExtExpr::create(op1, getWidthForLLVMType(type)); case Instruction::PtrToInt: - return op1->ZExt(getWidthForLLVMType(type)); + return ZExtExpr::create(op1, getWidthForLLVMType(type)); case Instruction::GetElementPtr: { - ref base = op1->ZExt(Context::get().getPointerWidth()); + ref base = ZExtExpr::create(op1, Context::get().getPointerWidth()); for (gep_type_iterator ii = gep_type_begin(ce), ie = gep_type_end(ce); ii != ie; ++ii) { - ref indexOp = - evalConstant(cast(ii.getOperand()), rm, ki); + ref indexOp = evalConstant(cast(ii.getOperand()), rm, ki); if (indexOp->isZero()) continue; // Handle a struct index, which adds its field offset to the pointer. if (auto STy = ii.getStructTypeOrNull()) { - unsigned ElementIdx = indexOp->getZExtValue(); + auto indexOpConst = dyn_cast(indexOp); + if (!indexOpConst) { + klee_error( + "Found non-constant index in evaluation of llvm::ConstantExpr"); + } + unsigned ElementIdx = indexOpConst->getZExtValue(); const StructLayout *SL = kmodule->targetData->getStructLayout(STy); - base = base->Add( - ConstantExpr::alloc(APInt(Context::get().getPointerWidth(), - SL->getElementOffset(ElementIdx)))); + base = AddExpr::create( + base, ConstantExpr::alloc(APInt(Context::get().getPointerWidth(), + SL->getElementOffset(ElementIdx)))); continue; } // For array or vector indices, scale the index by the size of the type. // Indices can be negative - base = base->Add(indexOp->SExt(Context::get().getPointerWidth()) - ->Mul(ConstantExpr::alloc( - APInt(Context::get().getPointerWidth(), - kmodule->targetData->getTypeAllocSize( - ii.getIndexedType()))))); + base = AddExpr::create( + base, + MulExpr::create( + SExtExpr::create(indexOp, Context::get().getPointerWidth()), + ConstantExpr::alloc(APInt(Context::get().getPointerWidth(), + kmodule->targetData->getTypeAllocSize( + ii.getIndexedType()))))); } return base; } @@ -413,25 +424,25 @@ ref Executor::evalConstantExpr(const llvm::ConstantExpr *ce, default: assert(0 && "unhandled ICmp predicate"); case ICmpInst::ICMP_EQ: - return op1->Eq(op2); + return EqExpr::create(op1, op2); case ICmpInst::ICMP_NE: - return op1->Ne(op2); + return NeExpr::create(op1, op2); case ICmpInst::ICMP_UGT: - return op1->Ugt(op2); + return UgtExpr::create(op1, op2); case ICmpInst::ICMP_UGE: - return op1->Uge(op2); + return UgeExpr::create(op1, op2); case ICmpInst::ICMP_ULT: - return op1->Ult(op2); + return UltExpr::create(op1, op2); case ICmpInst::ICMP_ULE: - return op1->Ule(op2); + return UleExpr::create(op1, op2); case ICmpInst::ICMP_SGT: - return op1->Sgt(op2); + return SgtExpr::create(op1, op2); case ICmpInst::ICMP_SGE: - return op1->Sge(op2); + return SgeExpr::create(op1, op2); case ICmpInst::ICMP_SLT: - return op1->Slt(op2); + return SltExpr::create(op1, op2); case ICmpInst::ICMP_SLE: - return op1->Sle(op2); + return SleExpr::create(op1, op2); } } @@ -439,46 +450,43 @@ ref Executor::evalConstantExpr(const llvm::ConstantExpr *ce, return op1->isTrue() ? op2 : op3; case Instruction::FAdd: - return op1->FAdd(op2, rm); + return FAddExpr::create(op1, op2, rm); case Instruction::FSub: - return op1->FSub(op2, rm); + return FSubExpr::create(op1, op2, rm); case Instruction::FMul: - return op1->FMul(op2, rm); + return FMulExpr::create(op1, op2, rm); case Instruction::FDiv: - return op1->FDiv(op2, rm); + return FDivExpr::create(op1, op2, rm); case Instruction::FRem: { - return op1->FRem(op2, rm); + return FRemExpr::create(op1, op2, rm); } case Instruction::FPTrunc: { Expr::Width width = getWidthForLLVMType(ce->getType()); - return op1->FPTrunc(width, rm); + return FPTruncExpr::create(op1, width, rm); } case Instruction::FPExt: { Expr::Width width = getWidthForLLVMType(ce->getType()); - return op1->FPExt(width); + return FPExtExpr::create(op1, width); } case Instruction::UIToFP: { Expr::Width width = getWidthForLLVMType(ce->getType()); - return op1->UIToFP(width, rm); + return UIToFPExpr::create(op1, width, rm); } case Instruction::SIToFP: { Expr::Width width = getWidthForLLVMType(ce->getType()); - return op1->SIToFP(width, rm); + return SIToFPExpr::create(op1, width, rm); } case Instruction::FPToUI: { Expr::Width width = getWidthForLLVMType(ce->getType()); - return op1->FPToUI(width, rm); + return FPToUIExpr::create(op1, width, rm); } case Instruction::FPToSI: { Expr::Width width = getWidthForLLVMType(ce->getType()); - return op1->FPToSI(width, rm); + return FPToSIExpr::create(op1, width, rm); } case Instruction::FCmp: { - ref result = evaluateFCmp(ce->getPredicate(), op1, op2); - if (ConstantExpr *CE = dyn_cast(result)) { - return ref(CE); - } + return evaluateFCmp(ce->getPredicate(), op1, op2); } assert(0 && "floating point ConstantExprs unsupported"); } diff --git a/lib/Core/ExternalDispatcher.cpp b/lib/Core/ExternalDispatcher.cpp index 551c121f9d..642dd7a7ae 100644 --- a/lib/Core/ExternalDispatcher.cpp +++ b/lib/Core/ExternalDispatcher.cpp @@ -346,11 +346,11 @@ Function *ExternalDispatcherImpl::createDispatcher(KCallable *target, llvm::CallInst *result; if (auto *func = dyn_cast(target)) { auto dispatchTarget = module->getOrInsertFunction( - target->getName(), FTy, func->function->getAttributes()); + target->getName(), FTy, func->function()->getAttributes()); result = Builder.CreateCall(dispatchTarget, llvm::ArrayRef(args, args + i)); } else if (auto *asmValue = dyn_cast(target)) { - result = Builder.CreateCall(asmValue->getInlineAsm(), + result = Builder.CreateCall(asmValue->inlineAsm(), llvm::ArrayRef(args, args + i)); } else { assert(0 && "Unhandled KCallable derived class"); diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp index a9d7457a88..82dc7f5388 100644 --- a/lib/Core/SpecialFunctionHandler.cpp +++ b/lib/Core/SpecialFunctionHandler.cpp @@ -269,7 +269,7 @@ bool SpecialFunctionHandler::handle(ExecutionState &state, Function *f, Handler h = it->second.first; bool hasReturnValue = it->second.second; // FIXME: Check this... add test? - if (!hasReturnValue && !target->inst->use_empty()) { + if (!hasReturnValue && !target->inst()->use_empty()) { executor.terminateStateOnExecError( state, "expected return value from void special function"); } else { @@ -626,7 +626,7 @@ void SpecialFunctionHandler::handleWarning(ExecutionState &state, std::string msg_str = readStringAtAddress(state, arguments[0]); klee_warning("%s: %s", - state.stack.callStack().back().kf->function->getName().data(), + state.stack.callStack().back().kf->function()->getName().data(), msg_str.c_str()); } @@ -639,7 +639,7 @@ void SpecialFunctionHandler::handleWarningOnce( std::string msg_str = readStringAtAddress(state, arguments[0]); klee_warning_once( 0, "%s: %s", - state.stack.callStack().back().kf->function->getName().data(), + state.stack.callStack().back().kf->function()->getName().data(), msg_str.c_str()); } @@ -692,7 +692,7 @@ void SpecialFunctionHandler::handleGetObjSize( target, *it->second, ConstantExpr::create(mo->size, executor.kmodule->targetData->getTypeSizeInBits( - target->inst->getType()))); + target->inst()->getType()))); } } @@ -744,7 +744,7 @@ void SpecialFunctionHandler::handleErrnoLocation( target, state, ConstantExpr::create((uint64_t)errno_addr, executor.kmodule->targetData->getTypeSizeInBits( - target->inst->getType()))); + target->inst()->getType()))); } void SpecialFunctionHandler::handleCalloc(ExecutionState &state, KInstruction *target, @@ -864,7 +864,7 @@ void SpecialFunctionHandler::handleDefineFixedObject( uint64_t address = cast(arguments[0])->getZExtValue(); uint64_t size = cast(arguments[1])->getZExtValue(); MemoryObject *mo = - executor.memory->allocateFixed(address, size, state.prevPC->inst); + executor.memory->allocateFixed(address, size, state.prevPC->inst()); executor.bindObjectInState( state, mo, executor.typeSystemManager->getUnknownType(), false); mo->isUserSpecified = true; // XXX hack; diff --git a/lib/Core/StatsTracker.cpp b/lib/Core/StatsTracker.cpp index c2b9b4769d..4f25d8dbf0 100644 --- a/lib/Core/StatsTracker.cpp +++ b/lib/Core/StatsTracker.cpp @@ -244,12 +244,12 @@ StatsTracker::StatsTracker(Executor &_executor, std::string _objectFilename, if (OutputIStats) { unsigned id = ki->getGlobalIndex(); theStatisticManager->setIndex(id); - if (instructionIsCoverable(ki->inst)) { + if (instructionIsCoverable(ki->inst())) { ++stats::uncoveredInstructions; } } - if (BranchInst *bi = dyn_cast(ki->inst)) + if (BranchInst *bi = dyn_cast(ki->inst())) if (!bi->isUnconditional()) numBranches++; } @@ -390,7 +390,7 @@ void StatsTracker::stepInstruction(ExecutionState &es) { } } - Instruction *inst = es.pc->inst; + Instruction *inst = es.pc->inst(); const KInstruction *ki = es.pc; auto &sf = es.stack.infoStack().back(); theStatisticManager->setIndex(ki->getGlobalIndex()); @@ -444,7 +444,7 @@ void StatsTracker::framePushed(ExecutionState &es, if (UseCallPaths) { CallPathNode *parent = parentFrame ? parentFrame->callPathNode : 0; CallPathNode *cp = callPathManager.getCallPath( - parent, csf.caller ? csf.caller->inst : 0, csf.kf->function); + parent, csf.caller ? csf.caller->inst() : 0, csf.kf->function()); isf.callPathNode = cp; cp->count++; } diff --git a/lib/Core/TargetCalculator.cpp b/lib/Core/TargetCalculator.cpp index 36c23a9026..1b19982b34 100644 --- a/lib/Core/TargetCalculator.cpp +++ b/lib/Core/TargetCalculator.cpp @@ -123,8 +123,8 @@ void TargetCalculator::update( for (auto state : localStates) { KFunction *kf = state->prevPC->parent->parent; KModule *km = kf->parent; - if (state->prevPC->inst->isTerminator() && - km->inMainModule(*kf->function)) { + if (state->prevPC->inst()->isTerminator() && + km->inMainModule(*kf->function())) { update(*state); } } @@ -169,8 +169,8 @@ bool TargetCalculator::uncoveredBlockPredicate(ExecutionState *state, calledKFunction->numInstructions; } if (fBranches.at(kblock) != cb) { - result |= - kblock->basicBlock->getTerminator()->getNumSuccessors() > cb.size(); + result |= kblock->basicBlock()->getTerminator()->getNumSuccessors() > + cb.size(); } } } @@ -185,7 +185,8 @@ TargetHashSet TargetCalculator::calculate(ExecutionState &state) { KBlock *kb = kf->blockMap[bb]; kb = !isa(kb) || (kb->getLastInstruction() != state.pc) ? kb - : kf->blockMap[state.pc->parent->basicBlock->getTerminator() + : kf->blockMap[state.pc->parent->basicBlock() + ->getTerminator() ->getSuccessor(0)]; for (auto sfi = state.stack.callStack().rbegin(), sfe = state.stack.callStack().rend(); @@ -225,7 +226,7 @@ TargetHashSet TargetCalculator::calculate(ExecutionState &state) { if (fBranches.at(block) != cb) { for (unsigned index = 0; index < - block->basicBlock->getTerminator()->getNumSuccessors(); + block->basicBlock()->getTerminator()->getNumSuccessors(); ++index) { if (!cb.count(index)) targets.insert(CoverBranchTarget::create(block, index)); @@ -244,7 +245,8 @@ TargetHashSet TargetCalculator::calculate(ExecutionState &state) { kb = !isa(kb) || (kb->getLastInstruction() != sfi->caller) ? kb - : kf->blockMap[sfi->caller->parent->basicBlock->getTerminator() + : kf->blockMap[sfi->caller->parent->basicBlock() + ->getTerminator() ->getSuccessor(0)]; } } diff --git a/lib/Core/TargetManager.cpp b/lib/Core/TargetManager.cpp index 9dcaedcd86..f72e329135 100644 --- a/lib/Core/TargetManager.cpp +++ b/lib/Core/TargetManager.cpp @@ -111,7 +111,8 @@ void TargetManager::updateReached(ExecutionState &state) { auto kf = prevKI->parent->parent; auto kmodule = kf->parent; - if (prevKI->inst->isTerminator() && kmodule->inMainModule(*kf->function)) { + if (prevKI->inst()->isTerminator() && + kmodule->inMainModule(*kf->function())) { ref target; if (state.getPrevPCBlock()->getTerminator()->getNumSuccessors() == 0) { @@ -262,9 +263,9 @@ bool TargetManager::isReachedTarget(const ExecutionState &state, if (isa(target)) { if (state.prevPC->parent == target->getBlock()) { if (state.prevPC == target->getBlock()->getLastInstruction() && - state.prevPC->inst->getSuccessor( + state.prevPC->inst()->getSuccessor( cast(target)->getBranchCase()) == - state.pc->parent->basicBlock) { + state.pc->parent->basicBlock()) { result = Done; } else { result = Continue; diff --git a/lib/Core/TargetedExecutionManager.cpp b/lib/Core/TargetedExecutionManager.cpp index ab4b67f3df..98862ede39 100644 --- a/lib/Core/TargetedExecutionManager.cpp +++ b/lib/Core/TargetedExecutionManager.cpp @@ -322,7 +322,7 @@ TargetedExecutionManager::prepareAllLocations(KModule *kmodule, fileNameToFunctions; for (const auto &kfunc : kmodule->functions) { - fileNameToFunctions[kfunc->getSourceFilepath()].insert(kfunc->function); + fileNameToFunctions[kfunc->getSourceFilepath()].insert(kfunc->function()); } for (auto it = locations.begin(); it != locations.end(); ++it) { @@ -379,18 +379,18 @@ bool TargetedExecutionManager::canReach(const ref &from, } const auto &blockDist = codeGraphInfo.getDistance(fromBlock); - if (blockDist.count(toBlock->basicBlock) != 0) { + if (blockDist.count(toBlock->basicBlock()) != 0) { return true; } } else { const auto &funcDist = codeGraphInfo.getDistance(fromKf); - if (funcDist.count(toKf->function) != 0) { + if (funcDist.count(toKf->function()) != 0) { return true; } const auto &backwardFuncDist = codeGraphInfo.getBackwardDistance(fromKf); - if (backwardFuncDist.count(toKf->function) != 0) { + if (backwardFuncDist.count(toKf->function()) != 0) { return true; } } @@ -464,9 +464,9 @@ KFunction *TargetedExecutionManager::tryResolveEntryFunction( KFunction *curKf = nullptr; for (size_t m = 0; m < currKFs.size() && !curKf; ++m) { curKf = currKFs.at(m); - if (funcDist.count(curKf->function) == 0) { + if (funcDist.count(curKf->function()) == 0) { const auto &curFuncDist = codeGraphInfo.getDistance(curKf); - if (curFuncDist.count(resKf->function) == 0) { + if (curFuncDist.count(resKf->function()) == 0) { curKf = nullptr; } else { i = j; diff --git a/lib/Expr/ExprPPrinter.cpp b/lib/Expr/ExprPPrinter.cpp index 5ffba87725..4d5fdc2554 100644 --- a/lib/Expr/ExprPPrinter.cpp +++ b/lib/Expr/ExprPPrinter.cpp @@ -390,7 +390,20 @@ class PPrinter : public ExprPPrinter { s->constantValues.print(PC.getStream(), Density::Sparse); } else if (auto s = dyn_cast(source)) { PC << s->version << " "; - s->allocSite->getID().print(PC.getStream()); + switch (s->allocSite->getKind()) { + case KValue::Kind::INSTRUCTION: { + cast(s->allocSite)->getID().print(PC.getStream()); + break; + } + case KValue::Kind::GLOBAL_VARIABLE: { + PC.getStream() << "[" << cast(s->allocSite)->getName() + << "]"; + break; + } + default: { + llvm_unreachable("unknown kind of alloc site"); + } + } PC << " " << s->size; } else if (auto s = dyn_cast(source)) { PC << s->version << " "; diff --git a/lib/Expr/Parser.cpp b/lib/Expr/Parser.cpp index a144437fd8..95c2d09a38 100644 --- a/lib/Expr/Parser.cpp +++ b/lib/Expr/Parser.cpp @@ -608,10 +608,10 @@ SourceResult ParserImpl::ParseArgumentSource() { auto argNo = dyn_cast(argNoExpr.get())->getZExtValue(); auto index = dyn_cast(indexExpr.get())->getZExtValue(); #if LLVM_VERSION_CODE >= LLVM_VERSION(10, 0) - auto arg = km->functionNameMap[name.getString()]->function->getArg(argNo); + auto arg = km->functionNameMap[name.getString()]->function()->getArg(argNo); #else auto arg = - &km->functionNameMap[name.getString()]->function->arg_begin()[argNo]; + &km->functionNameMap[name.getString()]->function()->arg_begin()[argNo]; #endif return SourceBuilder::argument(*arg, index, km); } @@ -628,7 +628,7 @@ SourceResult ParserImpl::ParseInstructionSource() { auto KF = km->functionNameMap[FName.getString()]; auto KB = KF->getLabelMap().at(Label.getString()); auto KI = KB->instructions[KIIndex]; - return SourceBuilder::instruction(*KI->inst, index, km); + return SourceBuilder::instruction(*KI->inst(), index, km); } SourceResult ParserImpl::ParseAlphaSource() { diff --git a/lib/Expr/Path.cpp b/lib/Expr/Path.cpp index 829e73b374..e3be1e0d25 100644 --- a/lib/Expr/Path.cpp +++ b/lib/Expr/Path.cpp @@ -150,7 +150,7 @@ Path Path::parse(const std::string &str, const KModule &km) { Path::TransitionKind Path::getTransitionKind(KBlock *a, KBlock *b) { if (auto cb = dyn_cast(a)) { - if (cb->calledFunctions.count(b->parent->function) && + if (cb->calledFunctions.count(b->parent->function()) && b == b->parent->entryKBlock) { return TransitionKind::StepInto; } diff --git a/lib/Expr/SourceBuilder.cpp b/lib/Expr/SourceBuilder.cpp index 866f89da6d..680cc747b6 100644 --- a/lib/Expr/SourceBuilder.cpp +++ b/lib/Expr/SourceBuilder.cpp @@ -3,6 +3,7 @@ #include "klee/Expr/Expr.h" #include "klee/Expr/SymbolicSource.h" #include "klee/Module/KModule.h" +#include "klee/Module/KValue.h" using namespace klee; @@ -21,7 +22,7 @@ SourceBuilder::uninitialized(unsigned version, const KInstruction *allocSite) { } ref SourceBuilder::symbolicSizeConstantAddress( - unsigned version, const KInstruction *allocSite, ref size) { + unsigned version, const KValue *allocSite, ref size) { ref r( new SymbolicSizeConstantAddressSource(version, allocSite, size)); r->computeHash(); diff --git a/lib/Expr/SymbolicSource.cpp b/lib/Expr/SymbolicSource.cpp index 1f78147c2b..f0321ec55a 100644 --- a/lib/Expr/SymbolicSource.cpp +++ b/lib/Expr/SymbolicSource.cpp @@ -5,6 +5,7 @@ #include "klee/Expr/ExprUtil.h" #include "klee/Module/KInstruction.h" #include "klee/Module/KModule.h" +#include "klee/Module/KValue.h" DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS @@ -102,8 +103,11 @@ int SymbolicSizeConstantAddressSource::internalCompare( return size < ub.size ? -1 : 1; } if (allocSite != ub.allocSite) { - return allocSite->getGlobalIndex() < ub.allocSite->getGlobalIndex() ? -1 - : 1; + if (allocSite->getKind() == ub.allocSite->getKind()) { + return *allocSite < *ub.allocSite ? -1 : 1; + } else { + return allocSite->getKind() < ub.allocSite->getKind() ? -1 : 1; + } } return 0; diff --git a/lib/Module/CMakeLists.txt b/lib/Module/CMakeLists.txt index bca27a10ea..19d9c11dbe 100644 --- a/lib/Module/CMakeLists.txt +++ b/lib/Module/CMakeLists.txt @@ -18,6 +18,7 @@ set(KLEE_MODULE_COMPONENT_SRCS KInstruction.cpp KModule.cpp KType.cpp + KValue.cpp LowerSwitch.cpp ModuleUtil.cpp Optimize.cpp diff --git a/lib/Module/CodeGraphInfo.cpp b/lib/Module/CodeGraphInfo.cpp index 71bb259ee1..4823460b87 100644 --- a/lib/Module/CodeGraphInfo.cpp +++ b/lib/Module/CodeGraphInfo.cpp @@ -68,7 +68,7 @@ void CodeGraphInfo::calculateBackwardDistance(Block *bb) { } void CodeGraphInfo::calculateDistance(KFunction *kf) { - auto f = kf->function; + auto f = kf->function(); auto &functionMap = kf->parent->functionMap; auto &dist = functionDistance[f]; auto &sort = functionSortedDistance[f]; @@ -83,7 +83,7 @@ void CodeGraphInfo::calculateDistance(KFunction *kf) { if (!calledFunction || calledFunction->isDeclaration()) continue; if (dist.count(calledFunction) == 0) { - auto d = dist[currKF->function] + 1; + auto d = dist[currKF->function()] + 1; dist[calledFunction] = d; sort.emplace_back(calledFunction, d); auto callKF = functionMap[calledFunction]; @@ -96,7 +96,7 @@ void CodeGraphInfo::calculateDistance(KFunction *kf) { } void CodeGraphInfo::calculateBackwardDistance(KFunction *kf) { - auto f = kf->function; + auto f = kf->function(); auto &callMap = kf->parent->callMap; auto &bdist = functionBackwardDistance[f]; auto &bsort = functionSortedBackwardDistance[f]; @@ -124,7 +124,7 @@ void CodeGraphInfo::calculateFunctionBranches(KFunction *kf) { for (auto &kb : kf->blocks) { fbranches[kb.get()]; for (unsigned branch = 0; - branch < kb->basicBlock->getTerminator()->getNumSuccessors(); + branch < kb->basicBlock()->getTerminator()->getNumSuccessors(); ++branch) { fbranches[kb.get()].insert(branch); } @@ -134,10 +134,10 @@ void CodeGraphInfo::calculateFunctionConditionalBranches(KFunction *kf) { std::map> &fbranches = functionConditionalBranches[kf]; for (auto &kb : kf->blocks) { - if (kb->basicBlock->getTerminator()->getNumSuccessors() > 1) { + if (kb->basicBlock()->getTerminator()->getNumSuccessors() > 1) { fbranches[kb.get()]; for (unsigned branch = 0; - branch < kb->basicBlock->getTerminator()->getNumSuccessors(); + branch < kb->basicBlock()->getTerminator()->getNumSuccessors(); ++branch) { fbranches[kb.get()].insert(branch); } @@ -158,31 +158,31 @@ const BlockDistanceMap &CodeGraphInfo::getDistance(Block *b) { } bool CodeGraphInfo::hasCycle(KBlock *kb) { - auto b = kb->basicBlock; + auto b = kb->basicBlock(); if (!blockDistance.count(b)) calculateDistance(b); return blockCycles.count(b); } const BlockDistanceMap &CodeGraphInfo::getDistance(KBlock *kb) { - return getDistance(kb->basicBlock); + return getDistance(kb->basicBlock()); } const BlockDistanceMap &CodeGraphInfo::getBackwardDistance(KBlock *kb) { - if (blockBackwardDistance.count(kb->basicBlock) == 0) - calculateBackwardDistance(kb->basicBlock); - return blockBackwardDistance.at(kb->basicBlock); + if (blockBackwardDistance.count(kb->basicBlock()) == 0) + calculateBackwardDistance(kb->basicBlock()); + return blockBackwardDistance.at(kb->basicBlock()); } const FunctionDistanceMap &CodeGraphInfo::getDistance(KFunction *kf) { - auto f = kf->function; + auto f = kf->function(); if (functionDistance.count(f) == 0) calculateDistance(kf); return functionDistance.at(f); } const FunctionDistanceMap &CodeGraphInfo::getBackwardDistance(KFunction *kf) { - auto f = kf->function; + auto f = kf->function(); if (functionBackwardDistance.count(f) == 0) calculateBackwardDistance(kf); return functionBackwardDistance.at(f); @@ -204,7 +204,7 @@ void CodeGraphInfo::getNearestPredicateSatisfying(KBlock *from, if (predicate(currBB) && currBB != from) { result.insert(currBB); } else { - for (auto succ : successors(currBB->basicBlock)) { + for (auto succ : successors(currBB->basicBlock())) { if (visited.count(blockMap[succ]) == 0) { nodes.push_back(blockMap[succ]); } diff --git a/lib/Module/KInstruction.cpp b/lib/Module/KInstruction.cpp index 09497d344c..97f9002385 100644 --- a/lib/Module/KInstruction.cpp +++ b/lib/Module/KInstruction.cpp @@ -50,9 +50,10 @@ KInstruction::KInstruction( &_instructionToRegisterMap, llvm::Instruction *_inst, KModule *_km, KBlock *_kb, unsigned &_globalIndexInc) - : inst(_inst), parent(_kb), globalIndex(_globalIndexInc++) { - if (isa(inst) || isa(inst)) { - const llvm::CallBase &cs = cast(*inst); + : KValue(_inst, KValue::Kind::INSTRUCTION), parent(_kb), + globalIndex(_globalIndexInc++) { + if (isa(inst()) || isa(inst())) { + const llvm::CallBase &cs = cast(*inst()); Value *val = cs.getCalledOperand(); unsigned numArgs = cs.arg_size(); operands = new int[numArgs + 1]; @@ -62,10 +63,10 @@ KInstruction::KInstruction( operands[j + 1] = getOperandNum(v, _instructionToRegisterMap, _km, this); } } else { - unsigned numOperands = inst->getNumOperands(); + unsigned numOperands = inst()->getNumOperands(); operands = new int[numOperands]; for (unsigned j = 0; j < numOperands; j++) { - Value *v = inst->getOperand(j); + Value *v = inst()->getOperand(j); operands[j] = getOperandNum(v, _instructionToRegisterMap, _km, this); } } @@ -74,17 +75,17 @@ KInstruction::KInstruction( KInstruction::~KInstruction() { delete[] operands; } size_t KInstruction::getLine() const { - auto locationInfo = getLocationInfo(inst); + auto locationInfo = getLocationInfo(inst()); return locationInfo.line; } size_t KInstruction::getColumn() const { - auto locationInfo = getLocationInfo(inst); + auto locationInfo = getLocationInfo(inst()); return locationInfo.column; } std::string KInstruction::getSourceFilepath() const { - auto locationInfo = getLocationInfo(inst); + auto locationInfo = getLocationInfo(inst()); return locationInfo.file; } @@ -101,7 +102,7 @@ std::string KInstruction::getSourceLocationString() const { std::string KInstruction::toString() const { return llvm::utostr(getIndex()) + " at " + parent->toString() + " (" + - inst->getOpcodeName() + ")"; + inst()->getOpcodeName() + ")"; } unsigned KInstruction::getGlobalIndex() const { return globalIndex; } diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index 64e1d3037c..6d686f1a6e 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -401,11 +401,16 @@ void KModule::manifest(InterpreterHandler *ih, functions.push_back(std::move(kf)); } + for (auto &global : module->globals()) { + globalMap.emplace(&global, new KGlobalVariable(&global)); + } + /* Compute various interesting properties */ for (auto &kf : functions) { - if (functionEscapes(kf->function)) - escapingFunctions.insert(kf->function); + if (functionEscapes(kf->function())) { + escapingFunctions.insert(kf->function()); + } } for (auto &declaration : declarations) { @@ -416,18 +421,18 @@ void KModule::manifest(InterpreterHandler *ih, for (auto &kfp : functions) { for (auto kcb : kfp->kCallBlocks) { bool isInlineAsm = false; - const CallBase &cs = cast(*kcb->kcallInstruction->inst); + const CallBase &cs = cast(*kcb->kcallInstruction->inst()); if (isa(cs.getCalledOperand())) { isInlineAsm = true; } if (kcb->calledFunctions.empty() && !isInlineAsm && (guidance != Interpreter::GuidanceKind::ErrorGuidance || - !inMainModule(*kfp->function))) { + !inMainModule(*kfp->function()))) { kcb->calledFunctions.insert(escapingFunctions.begin(), escapingFunctions.end()); } for (auto calledFunction : kcb->calledFunctions) { - callMap[calledFunction].insert(kfp->function); + callMap[calledFunction].insert(kfp->function()); } } } @@ -546,17 +551,28 @@ unsigned KModule::getGlobalIndex(const llvm::Instruction *inst) const { /***/ -KConstant::KConstant(llvm::Constant *_ct, unsigned _id, KInstruction *_ki) { - ct = _ct; +KConstant::KConstant(llvm::Constant *_ct, unsigned _id, KInstruction *_ki) + : KValue(_ct, Kind::CONSTANT) { id = _id; ki = _ki; } +KGlobalVariable::KGlobalVariable(llvm::GlobalVariable *global) + : KValue(global, KValue::Kind::GLOBAL_VARIABLE) {} + +std::string KGlobalVariable::getSourceFilepath() const { + getLocationInfo(globalVariable()).file; +} +// Line number where the global variable is defined +size_t KGlobalVariable::getLine() const { + getLocationInfo(globalVariable()).line; +} + KFunction::KFunction(llvm::Function *_function, KModule *_km, unsigned &globalIndexInc) - : KCallable(CK_Function), globalIndex(globalIndexInc++), parent(_km), - function(_function), entryKBlock(nullptr), numInstructions(0) { - for (auto &BasicBlock : *function) { + : KCallable(_function, Kind::FUNCTION), globalIndex(globalIndexInc++), + parent(_km), entryKBlock(nullptr), numInstructions(0) { + for (auto &BasicBlock : *function()) { numInstructions += BasicBlock.size(); } instructions = new KInstruction *[numInstructions]; @@ -565,14 +581,14 @@ KFunction::KFunction(llvm::Function *_function, KModule *_km, unsigned n = 0; // The first arg_size() registers are reserved for formals. unsigned rnum = getNumArgs(); - for (auto &bb : *function) { + for (auto &bb : *function()) { for (auto &instr : bb) { instructionToRegisterMap[&instr] = rnum++; } } - for (llvm::Function::iterator bbit = function->begin(), - bbie = function->end(); + for (llvm::Function::iterator bbit = function()->begin(), + bbie = function()->end(); bbit != bbie; ++bbit) { KBlock *kb; Instruction *fit = &bbit->front(); @@ -599,25 +615,25 @@ KFunction::KFunction(llvm::Function *_function, KModule *_km, &instructions[n], globalIndexInc); } for (unsigned i = 0, ie = kb->getNumInstructions(); i < ie; i++, n++) { - instructionMap[instructions[n]->inst] = instructions[n]; + instructionMap[instructions[n]->inst()] = instructions[n]; } blockMap[&*bbit] = kb; blocks.push_back(std::unique_ptr(kb)); } if (blocks.size() > 0) { - assert(function->begin() != function->end()); - entryKBlock = blockMap[&*function->begin()]; + assert(function()->begin() != function()->end()); + entryKBlock = blockMap[&*function()->begin()]; } } size_t KFunction::getLine() const { - auto locationInfo = getLocationInfo(function); + auto locationInfo = getLocationInfo(function()); return locationInfo.line; } std::string KFunction::getSourceFilepath() const { - auto locationInfo = getLocationInfo(function); + auto locationInfo = getLocationInfo(function()); return locationInfo.file; } @@ -631,7 +647,7 @@ KBlock::KBlock( KFunction *_kfunction, llvm::BasicBlock *block, KModule *km, const std::unordered_map &instructionToRegisterMap, KInstruction **instructionsKF, unsigned &globalIndexInc) - : parent(_kfunction), basicBlock(block) { + : KValue(block, KValue::Kind::BLOCK), parent(_kfunction) { instructions = instructionsKF; for (auto &it : *block) { @@ -696,21 +712,21 @@ KReturnBlock::KReturnBlock( std::string KBlock::getLabel() const { std::string _label; llvm::raw_string_ostream label_stream(_label); - basicBlock->printAsOperand(label_stream, false); + basicBlock()->printAsOperand(label_stream, false); std::string label = label_stream.str(); return label; } std::string KBlock::toString() const { - return getLabel() + " in function " + parent->function->getName().str(); + return getLabel() + " in function " + parent->function()->getName().str(); } uintptr_t KBlock::getId() const { return instructions - parent->instructions; } KInstruction *KFunction::getInstructionByRegister(size_t reg) const { - return instructions[reg - function->arg_size()]; + return instructions[reg - function()->arg_size()]; } -size_t KFunction::getNumArgs() const { return function->arg_size(); } +size_t KFunction::getNumArgs() const { return function()->arg_size(); } size_t KFunction::getNumRegisters() const { - return function->arg_size() + numInstructions; + return function()->arg_size() + numInstructions; } diff --git a/lib/Module/KValue.cpp b/lib/Module/KValue.cpp new file mode 100644 index 0000000000..b540906e52 --- /dev/null +++ b/lib/Module/KValue.cpp @@ -0,0 +1,30 @@ +#include "klee/Support/CompilerWarning.h" +#include + +DISABLE_WARNING_PUSH +DISABLE_WARNING_DEPRECATED_DECLARATIONS +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Value.h" +DISABLE_WARNING_POP + +#include +#include + +using namespace klee; + +llvm::Value *KValue::unwrap() const { return value; } + +llvm::StringRef KValue::getName() const { + return value && value->hasName() ? value->getName() : ""; +} + +bool KValue::operator<(const KValue &rhs) const { + if (getName() != rhs.getName()) { + return getName() < rhs.getName(); + } + return std::less{}(unwrap(), rhs.unwrap()); +} + +[[nodiscard]] unsigned KValue::hash() const { + return std::hash{}(getName().str()); +} diff --git a/lib/Module/LocationInfo.cpp b/lib/Module/LocationInfo.cpp index 274a55e25d..6395970b08 100644 --- a/lib/Module/LocationInfo.cpp +++ b/lib/Module/LocationInfo.cpp @@ -12,6 +12,7 @@ DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS +#include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/DebugInfoMetadata.h" @@ -60,4 +61,26 @@ LocationInfo getLocationInfo(const llvm::Instruction *inst) { return getLocationInfo(inst->getParent()->getParent()); } +LocationInfo getLocationInfo(const llvm::GlobalVariable *globalVar) { + // Retrieve debug information associated with global variable. + // LLVM does not expose API for getting single DINode with location + // information. + llvm::SmallVector debugInfo; + globalVar->getDebugInfo(debugInfo); + + for (const llvm::DIGlobalVariableExpression *debugInfoEntry : debugInfo) { + // Return location from any debug info for global variable. + if (const llvm::DIGlobalVariable *debugInfoGlobalVar = + debugInfoEntry->getVariable()) { + // Assume that global variable declared at line 0. + return {debugInfoGlobalVar->getFilename().str(), + debugInfoGlobalVar->getLine(), 0}; + } + } + + // Fallback to empty location if there is no appropriate debug + // info. + return {"", 0, 0}; +} + } // namespace klee diff --git a/lib/Module/SarifReport.cpp b/lib/Module/SarifReport.cpp index 6cc323a87a..aa1b403e89 100644 --- a/lib/Module/SarifReport.cpp +++ b/lib/Module/SarifReport.cpp @@ -335,8 +335,8 @@ bool Location::isInside(KBlock *block, const Instructions &origInsts) const { } else { for (unsigned i = 0, ie = block->getNumInstructions(); i < ie; ++i) { auto inst = block->instructions[i]; - auto opCode = block->instructions[i]->inst->getOpcode(); - if (!isa(block->instructions[i]->inst) && + auto opCode = block->instructions[i]->inst()->getOpcode(); + if (!isa(block->instructions[i]->inst()) && inst->getLine() <= endLine && inst->getLine() >= startLine && inst->getColumn() <= *endColumn && inst->getColumn() >= *startColumn && diff --git a/lib/Solver/BitwuzlaSolver.cpp b/lib/Solver/BitwuzlaSolver.cpp index 3b5d9acfe1..8c53cf506d 100644 --- a/lib/Solver/BitwuzlaSolver.cpp +++ b/lib/Solver/BitwuzlaSolver.cpp @@ -771,7 +771,7 @@ class BitwuzlaIncNativeSolver { Bitwuzla &getOrInit(); bool isConsistent() const { - klee_warning("Empty isConsistent() check"); + // klee_warning("Empty isConsistent() check"); return true; } diff --git a/test/Feature/SymbolicSizes/SymbolicSizeUnsizedGlobal.c b/test/Feature/SymbolicSizes/SymbolicSizeUnsizedGlobal.c new file mode 100644 index 0000000000..37383aee60 --- /dev/null +++ b/test/Feature/SymbolicSizes/SymbolicSizeUnsizedGlobal.c @@ -0,0 +1,14 @@ +// RUN: %clang %s -g -emit-llvm %O0opt -c -o %t1.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --use-sym-size-alloc --symbolic-allocation-threshold=0 %t1.bc 2>&1 | FileCheck %s + +extern int GLOBAL[]; + +int main() { + // CHECK: SymbolicSizeUnsizedGlobal.c:[[@LINE+1]]: memory error: out of bound pointer + GLOBAL[1] = 0; + // CHECK: SymbolicSizeUnsizedGlobal.c:[[@LINE+1]]: memory error: out of bound pointer + GLOBAL[2] = 0; + // CHECK-NOT: SymbolicSizeUnsizedGlobal.c:[[@LINE+1]]: memory error: out of bound pointer + GLOBAL[0] = 0; +}