//===-- Executor.cpp ------------------------------------------------------===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Executor.h" #include "Context.h" #include "CoreStats.h" #include "ExternalDispatcher.h" #include "ImpliedValue.h" #include "Memory.h" #include "MemoryManager.h" #include "PTree.h" #include "Searcher.h" #include "SeedInfo.h" #include "SpecialFunctionHandler.h" #include "StatsTracker.h" #include "TimingSolver.h" #include "UserSearcher.h" #include "ExecutorTimerInfo.h" #include "klee/ExecutionState.h" #include "klee/Expr.h" #include "klee/Interpreter.h" #include "klee/TimerStatIncrementer.h" #include "klee/CommandLine.h" #include "klee/Common.h" #include "klee/util/Assignment.h" #include "klee/util/ExprPPrinter.h" #include "klee/util/ExprSMTLIBPrinter.h" #include "klee/util/ExprUtil.h" #include "klee/util/GetElementPtrTypeIterator.h" #include "klee/Config/Version.h" #include "klee/Internal/ADT/KTest.h" #include "klee/Internal/ADT/RNG.h" #include "klee/Internal/Module/Cell.h" #include "klee/Internal/Module/InstructionInfoTable.h" #include "klee/Internal/Module/KInstruction.h" #include "klee/Internal/Module/KModule.h" #include "klee/Internal/Support/ErrorHandling.h" #include "klee/Internal/Support/FloatEvaluation.h" #include "klee/Internal/Support/ModuleUtil.h" #include "klee/Internal/System/Time.h" #include "klee/Internal/System/MemoryUsage.h" #include "klee/SolverStats.h" #include "llvm/IR/Function.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/TypeBuilder.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" #if LLVM_VERSION_CODE < LLVM_VERSION(3, 5) #include "llvm/Support/CallSite.h" #else #include "llvm/IR/CallSite.h" #endif #ifdef HAVE_ZLIB_H #include "klee/Internal/Support/CompressionStream.h" #endif #include #include #include #include #include #include #include #include #include #include #include using namespace llvm; using namespace klee; namespace { cl::opt DumpStatesOnHalt("dump-states-on-halt", cl::init(true), cl::desc("Dump test cases for all active states on exit (default=on)")); cl::opt AllowExternalSymCalls("allow-external-sym-calls", cl::init(false), cl::desc("Allow calls with symbolic arguments to external functions. This concretizes the symbolic arguments. (default=off)")); /// The different query logging solvers that can switched on/off enum PrintDebugInstructionsType { STDERR_ALL, /// STDERR_SRC, STDERR_COMPACT, FILE_ALL, /// FILE_SRC, /// FILE_COMPACT /// }; llvm::cl::bits DebugPrintInstructions( "debug-print-instructions", llvm::cl::desc("Log instructions during execution."), llvm::cl::values( clEnumValN(STDERR_ALL, "all:stderr", "Log all instructions to stderr " "in format [src, inst_id, " "llvm_inst]"), clEnumValN(STDERR_SRC, "src:stderr", "Log all instructions to stderr in format [src, inst_id]"), clEnumValN(STDERR_COMPACT, "compact:stderr", "Log all instructions to stderr in format [inst_id]"), clEnumValN(FILE_ALL, "all:file", "Log all instructions to file " "instructions.txt in format [src, " "inst_id, llvm_inst]"), clEnumValN(FILE_SRC, "src:file", "Log all instructions to file " "instructions.txt in format [src, " "inst_id]"), clEnumValN(FILE_COMPACT, "compact:file", "Log all instructions to file instructions.txt in format " "[inst_id]") KLEE_LLVM_CL_VAL_END), llvm::cl::CommaSeparated); #ifdef HAVE_ZLIB_H cl::opt DebugCompressInstructions( "debug-compress-instructions", cl::init(false), cl::desc("Compress the logged instructions in gzip format.")); #endif cl::opt DebugCheckForImpliedValues("debug-check-for-implied-values"); cl::opt SimplifySymIndices("simplify-sym-indices", cl::init(false), cl::desc("Simplify symbolic accesses using equalities from other constraints (default=off)")); cl::opt EqualitySubstitution("equality-substitution", cl::init(true), cl::desc("Simplify equality expressions before querying the solver (default=on).")); cl::opt MaxSymArraySize("max-sym-array-size", cl::init(0)); cl::opt SuppressExternalWarnings("suppress-external-warnings", cl::init(false), cl::desc("Supress warnings about calling external functions.")); cl::opt AllExternalWarnings("all-external-warnings", cl::init(false), cl::desc("Issue an warning everytime an external call is made," "as opposed to once per function (default=off)")); cl::opt OnlyOutputStatesCoveringNew("only-output-states-covering-new", cl::init(false), cl::desc("Only output test cases covering new code (default=off).")); cl::opt EmitAllErrors("emit-all-errors", cl::init(false), cl::desc("Generate tests cases for all errors " "(default=off, i.e. one per (error,instruction) pair)")); cl::opt NoExternals("no-externals", cl::desc("Do not allow external function calls (default=off)")); cl::opt AlwaysOutputSeeds("always-output-seeds", cl::init(true)); cl::opt OnlyReplaySeeds("only-replay-seeds", cl::init(false), cl::desc("Discard states that do not have a seed (default=off).")); cl::opt OnlySeed("only-seed", cl::init(false), cl::desc("Stop execution after seeding is done without doing regular search (default=off).")); cl::opt AllowSeedExtension("allow-seed-extension", cl::init(false), cl::desc("Allow extra (unbound) values to become symbolic during seeding (default=false).")); cl::opt ZeroSeedExtension("zero-seed-extension", cl::init(false), cl::desc("(default=off)")); cl::opt AllowSeedTruncation("allow-seed-truncation", cl::init(false), cl::desc("Allow smaller buffers than in seeds (default=off).")); cl::opt NamedSeedMatching("named-seed-matching", cl::init(false), cl::desc("Use names to match symbolic objects to inputs (default=off).")); cl::opt MaxStaticForkPct("max-static-fork-pct", cl::init(1.), cl::desc("(default=1.0)")); cl::opt MaxStaticSolvePct("max-static-solve-pct", cl::init(1.), cl::desc("(default=1.0)")); cl::opt MaxStaticCPForkPct("max-static-cpfork-pct", cl::init(1.), cl::desc("(default=1.0)")); cl::opt MaxStaticCPSolvePct("max-static-cpsolve-pct", cl::init(1.), cl::desc("(default=1.0)")); cl::opt MaxInstructionTime("max-instruction-time", cl::desc("Only allow a single instruction to take this much time (default=0s (off)). Enables --use-forked-solver"), cl::init(0)); cl::opt SeedTime("seed-time", cl::desc("Amount of time to dedicate to seeds, before normal search (default=0 (off))"), cl::init(0)); cl::list ExitOnErrorType("exit-on-error-type", cl::desc("Stop execution after reaching a specified condition. (default=off)"), cl::values( clEnumValN(Executor::Abort, "Abort", "The program crashed"), clEnumValN(Executor::Assert, "Assert", "An assertion was hit"), clEnumValN(Executor::BadVectorAccess, "BadVectorAccess", "Vector accessed out of bounds"), clEnumValN(Executor::Exec, "Exec", "Trying to execute an unexpected instruction"), clEnumValN(Executor::External, "External", "External objects referenced"), clEnumValN(Executor::Free, "Free", "Freeing invalid memory"), clEnumValN(Executor::Model, "Model", "Memory model limit hit"), clEnumValN(Executor::Overflow, "Overflow", "An overflow occurred"), clEnumValN(Executor::Ptr, "Ptr", "Pointer error"), clEnumValN(Executor::ReadOnly, "ReadOnly", "Write to read-only memory"), clEnumValN(Executor::ReportError, "ReportError", "klee_report_error called"), clEnumValN(Executor::User, "User", "Wrong klee_* functions invocation"), clEnumValN(Executor::Unhandled, "Unhandled", "Unhandled instruction hit") KLEE_LLVM_CL_VAL_END), cl::ZeroOrMore); cl::opt StopAfterNInstructions("stop-after-n-instructions", cl::desc("Stop execution after specified number of instructions (default=0 (off))"), cl::init(0)); cl::opt MaxForks("max-forks", cl::desc("Only fork this many times (default=-1 (off))"), cl::init(~0u)); cl::opt MaxDepth("max-depth", cl::desc("Only allow this many symbolic branches (default=0 (off))"), cl::init(0)); cl::opt MaxMemory("max-memory", cl::desc("Refuse to fork when above this amount of memory (in MB, default=2000)"), cl::init(2000)); cl::opt MaxMemoryInhibit("max-memory-inhibit", cl::desc("Inhibit forking at memory cap (vs. random terminate) (default=on)"), cl::init(true)); } namespace klee { RNG theRNG; } const char *Executor::TerminateReasonNames[] = { [ Abort ] = "abort", [ Assert ] = "assert", [ BadVectorAccess ] = "bad_vector_access", [ Exec ] = "exec", [ External ] = "external", [ Free ] = "free", [ Model ] = "model", [ Overflow ] = "overflow", [ Ptr ] = "ptr", [ ReadOnly ] = "readonly", [ ReportError ] = "reporterror", [ User ] = "user", [ Unhandled ] = "xxx", }; Executor::Executor(LLVMContext &ctx, const InterpreterOptions &opts, InterpreterHandler *ih) : Interpreter(opts), kmodule(0), interpreterHandler(ih), searcher(0), externalDispatcher(new ExternalDispatcher(ctx)), statsTracker(0), pathWriter(0), symPathWriter(0), specialFunctionHandler(0), processTree(0), replayKTest(0), replayPath(0), usingSeeds(0), atMemoryLimit(false), inhibitForking(false), haltExecution(false), ivcEnabled(false), coreSolverTimeout(MaxCoreSolverTime != 0 && MaxInstructionTime != 0 ? std::min(MaxCoreSolverTime, MaxInstructionTime) : std::max(MaxCoreSolverTime, MaxInstructionTime)), debugInstFile(0), debugLogBuffer(debugBufferString) { if (coreSolverTimeout) UseForkedCoreSolver = true; Solver *coreSolver = klee::createCoreSolver(CoreSolverToUse); if (!coreSolver) { klee_error("Failed to create core solver\n"); } Solver *solver = constructSolverChain( coreSolver, interpreterHandler->getOutputFilename(ALL_QUERIES_SMT2_FILE_NAME), interpreterHandler->getOutputFilename(SOLVER_QUERIES_SMT2_FILE_NAME), interpreterHandler->getOutputFilename(ALL_QUERIES_KQUERY_FILE_NAME), interpreterHandler->getOutputFilename(SOLVER_QUERIES_KQUERY_FILE_NAME)); this->solver = new TimingSolver(solver, EqualitySubstitution); memory = new MemoryManager(&arrayCache); initializeSearchOptions(); if (DebugPrintInstructions.isSet(FILE_ALL) || DebugPrintInstructions.isSet(FILE_COMPACT) || DebugPrintInstructions.isSet(FILE_SRC)) { std::string debug_file_name = interpreterHandler->getOutputFilename("instructions.txt"); std::string ErrorInfo; #ifdef HAVE_ZLIB_H if (!DebugCompressInstructions) { #endif #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) std::error_code ec; debugInstFile = new llvm::raw_fd_ostream(debug_file_name.c_str(), ec, llvm::sys::fs::OpenFlags::F_Text); if (ec) ErrorInfo = ec.message(); #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 5) debugInstFile = new llvm::raw_fd_ostream(debug_file_name.c_str(), ErrorInfo, llvm::sys::fs::OpenFlags::F_Text); #else debugInstFile = new llvm::raw_fd_ostream(debug_file_name.c_str(), ErrorInfo); #endif #ifdef HAVE_ZLIB_H } else { debugInstFile = new compressed_fd_ostream( (debug_file_name + ".gz").c_str(), ErrorInfo); } #endif if (ErrorInfo != "") { klee_error("Could not open file %s : %s", debug_file_name.c_str(), ErrorInfo.c_str()); } } } const Module *Executor::setModule(llvm::Module *module, const ModuleOptions &opts) { assert(!kmodule && module && "can only register one module"); // XXX gross kmodule = new KModule(module); // Initialize the context. DataLayout *TD = kmodule->targetData; Context::initialize(TD->isLittleEndian(), (Expr::Width) TD->getPointerSizeInBits()); specialFunctionHandler = new SpecialFunctionHandler(*this); specialFunctionHandler->prepare(); kmodule->prepare(opts, interpreterHandler); specialFunctionHandler->bind(); if (StatsTracker::useStatistics() || userSearcherRequiresMD2U()) { statsTracker = new StatsTracker(*this, interpreterHandler->getOutputFilename("assembly.ll"), userSearcherRequiresMD2U()); } return module; } Executor::~Executor() { delete memory; delete externalDispatcher; delete processTree; delete specialFunctionHandler; delete statsTracker; delete solver; delete kmodule; while(!timers.empty()) { delete timers.back(); timers.pop_back(); } delete debugInstFile; } /***/ void Executor::initializeGlobalObject(ExecutionState &state, ObjectState *os, const Constant *c, unsigned offset) { DataLayout *targetData = kmodule->targetData; if (const ConstantVector *cp = dyn_cast(c)) { unsigned elementSize = targetData->getTypeStoreSize(cp->getType()->getElementType()); for (unsigned i=0, e=cp->getNumOperands(); i != e; ++i) initializeGlobalObject(state, os, cp->getOperand(i), offset + i*elementSize); } else if (isa(c)) { unsigned i, size = targetData->getTypeStoreSize(c->getType()); for (i=0; iwrite8(offset+i, (uint8_t) 0); } else if (const ConstantArray *ca = dyn_cast(c)) { unsigned elementSize = targetData->getTypeStoreSize(ca->getType()->getElementType()); for (unsigned i=0, e=ca->getNumOperands(); i != e; ++i) initializeGlobalObject(state, os, ca->getOperand(i), offset + i*elementSize); } else if (const ConstantStruct *cs = dyn_cast(c)) { const StructLayout *sl = targetData->getStructLayout(cast(cs->getType())); for (unsigned i=0, e=cs->getNumOperands(); i != e; ++i) initializeGlobalObject(state, os, cs->getOperand(i), offset + sl->getElementOffset(i)); } else if (const ConstantDataSequential *cds = dyn_cast(c)) { unsigned elementSize = targetData->getTypeStoreSize(cds->getElementType()); for (unsigned i=0, e=cds->getNumElements(); i != e; ++i) initializeGlobalObject(state, os, cds->getElementAsConstant(i), offset + i*elementSize); } else if (!isa(c)) { unsigned StoreBits = targetData->getTypeStoreSizeInBits(c->getType()); ref C = evalConstant(c); // Extend the constant if necessary; assert(StoreBits >= C->getWidth() && "Invalid store size!"); if (StoreBits > C->getWidth()) C = C->ZExt(StoreBits); os->write(offset, C); } } MemoryObject * Executor::addExternalObject(ExecutionState &state, void *addr, unsigned size, bool isReadOnly) { MemoryObject *mo = memory->allocateFixed((uint64_t) (unsigned long) addr, size, 0); ObjectState *os = bindObjectInState(state, mo, false); for(unsigned i = 0; i < size; i++) os->write8(i, ((uint8_t*)addr)[i]); if(isReadOnly) os->setReadOnly(true); return mo; } extern void *__dso_handle __attribute__ ((__weak__)); void Executor::initializeGlobals(ExecutionState &state) { Module *m = kmodule->module; if (m->getModuleInlineAsm() != "") klee_warning("executable has module level assembly (ignoring)"); // represent function globals using the address of the actual llvm function // object. given that we use malloc to allocate memory in states this also // ensures that we won't conflict. we don't need to allocate a memory object // since reading/writing via a function pointer is unsupported anyway. for (Module::iterator i = m->begin(), ie = m->end(); i != ie; ++i) { Function *f = &*i; ref addr(0); // If the symbol has external weak linkage then it is implicitly // not defined in this module; if it isn't resolvable then it // should be null. if (f->hasExternalWeakLinkage() && !externalDispatcher->resolveSymbol(f->getName())) { addr = Expr::createPointer(0); } else { addr = Expr::createPointer((unsigned long) (void*) f); legalFunctions.insert((uint64_t) (unsigned long) (void*) f); } globalAddresses.insert(std::make_pair(f, addr)); } #ifndef WINDOWS int *errno_addr = getErrnoLocation(state); MemoryObject *errnoObj = addExternalObject(state, (void *)errno_addr, sizeof *errno_addr, false); // Copy values from and to program space explicitly errnoObj->isUserSpecified = true; #endif // Disabled, we don't want to promote use of live externals. #ifdef HAVE_CTYPE_EXTERNALS #ifndef WINDOWS #ifndef DARWIN /* from /usr/include/ctype.h: These point into arrays of 384, so they can be indexed by any `unsigned char' value [0,255]; by EOF (-1); or by any `signed char' value [-128,-1). ISO C requires that the ctype functions work for `unsigned */ const uint16_t **addr = __ctype_b_loc(); addExternalObject(state, const_cast(*addr-128), 384 * sizeof **addr, true); addExternalObject(state, addr, sizeof(*addr), true); const int32_t **lower_addr = __ctype_tolower_loc(); addExternalObject(state, const_cast(*lower_addr-128), 384 * sizeof **lower_addr, true); addExternalObject(state, lower_addr, sizeof(*lower_addr), true); const int32_t **upper_addr = __ctype_toupper_loc(); addExternalObject(state, const_cast(*upper_addr-128), 384 * sizeof **upper_addr, true); addExternalObject(state, upper_addr, sizeof(*upper_addr), true); #endif #endif #endif // allocate and initialize globals, done in two passes since we may // need address of a global in order to initialize some other one. // allocate memory objects for all globals for (Module::const_global_iterator i = m->global_begin(), e = m->global_end(); i != e; ++i) { const GlobalVariable *v = &*i; size_t globalObjectAlignment = getAllocationAlignment(v); if (i->isDeclaration()) { // FIXME: We have no general way of handling unknown external // symbols. If we really cared about making external stuff work // better we could support user definition, or use the EXE style // hack where we check the object file information. Type *ty = i->getType()->getElementType(); uint64_t size = 0; if (ty->isSized()) { size = kmodule->targetData->getTypeStoreSize(ty); } else { klee_warning("Type for %.*s is not sized", (int)i->getName().size(), i->getName().data()); } // XXX - DWD - hardcode some things until we decide how to fix. #ifndef WINDOWS if (i->getName() == "_ZTVN10__cxxabiv117__class_type_infoE") { size = 0x2C; } else if (i->getName() == "_ZTVN10__cxxabiv120__si_class_type_infoE") { size = 0x2C; } else if (i->getName() == "_ZTVN10__cxxabiv121__vmi_class_type_infoE") { size = 0x2C; } #endif if (size == 0) { klee_warning("Unable to find size for global variable: %.*s (use will result in out of bounds access)", (int)i->getName().size(), i->getName().data()); } MemoryObject *mo = memory->allocate(size, /*isLocal=*/false, /*isGlobal=*/true, /*allocSite=*/v, /*alignment=*/globalObjectAlignment); ObjectState *os = bindObjectInState(state, mo, false); globalObjects.insert(std::make_pair(v, mo)); globalAddresses.insert(std::make_pair(v, mo->getBaseExpr())); // Program already running = object already initialized. Read // concrete value and write it to our copy. if (size) { void *addr; if (i->getName() == "__dso_handle") { addr = &__dso_handle; // wtf ? } else { addr = externalDispatcher->resolveSymbol(i->getName()); } if (!addr) klee_error("unable to load symbol(%s) while initializing globals.", i->getName().data()); for (unsigned offset=0; offsetsize; offset++) os->write8(offset, ((unsigned char*)addr)[offset]); } } else { Type *ty = i->getType()->getElementType(); uint64_t size = kmodule->targetData->getTypeStoreSize(ty); MemoryObject *mo = memory->allocate(size, /*isLocal=*/false, /*isGlobal=*/true, /*allocSite=*/v, /*alignment=*/globalObjectAlignment); if (!mo) llvm::report_fatal_error("out of memory"); ObjectState *os = bindObjectInState(state, mo, false); globalObjects.insert(std::make_pair(v, mo)); globalAddresses.insert(std::make_pair(v, mo->getBaseExpr())); if (!i->hasInitializer()) os->initializeToRandom(); } } // link aliases to their definitions (if bound) for (Module::alias_iterator i = m->alias_begin(), ie = m->alias_end(); i != ie; ++i) { // Map the alias to its aliasee's address. This works because we have // addresses for everything, even undefined functions. globalAddresses.insert(std::make_pair(&*i, evalConstant(i->getAliasee()))); } // once all objects are allocated, do the actual initialization for (Module::const_global_iterator i = m->global_begin(), e = m->global_end(); i != e; ++i) { if (i->hasInitializer()) { const GlobalVariable *v = &*i; MemoryObject *mo = globalObjects.find(v)->second; const ObjectState *os = state.addressSpace.findObject(mo); assert(os); ObjectState *wos = state.addressSpace.getWriteable(mo, os); initializeGlobalObject(state, wos, i->getInitializer(), 0); // if(i->isConstant()) os->setReadOnly(true); } } } void Executor::branch(ExecutionState &state, const std::vector< ref > &conditions, std::vector &result) { TimerStatIncrementer timer(stats::forkTime); unsigned N = conditions.size(); assert(N); if (MaxForks!=~0u && stats::forks >= MaxForks) { unsigned next = theRNG.getInt32() % N; for (unsigned i=0; ibranch(); addedStates.push_back(ns); result.push_back(ns); es->ptreeNode->data = 0; std::pair res = processTree->split(es->ptreeNode, ns, es); ns->ptreeNode = res.first; es->ptreeNode = res.second; } } // If necessary redistribute seeds to match conditions, killing // states if necessary due to OnlyReplaySeeds (inefficient but // simple). std::map< ExecutionState*, std::vector >::iterator it = seedMap.find(&state); if (it != seedMap.end()) { std::vector seeds = it->second; seedMap.erase(it); // Assume each seed only satisfies one condition (necessarily true // when conditions are mutually exclusive and their conjunction is // a tautology). for (std::vector::iterator siit = seeds.begin(), siie = seeds.end(); siit != siie; ++siit) { unsigned i; for (i=0; i res; bool success = solver->getValue(state, siit->assignment.evaluate(conditions[i]), res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (res->isTrue()) break; } // If we didn't find a satisfying condition randomly pick one // (the seed will be patched). if (i==N) i = theRNG.getInt32() % N; // Extra check in case we're replaying seeds with a max-fork if (result[i]) seedMap[result[i]].push_back(*siit); } if (OnlyReplaySeeds) { for (unsigned i=0; i condition, bool isInternal) { Solver::Validity res; std::map< ExecutionState*, std::vector >::iterator it = seedMap.find(¤t); bool isSeeding = it != seedMap.end(); if (!isSeeding && !isa(condition) && (MaxStaticForkPct!=1. || MaxStaticSolvePct != 1. || MaxStaticCPForkPct!=1. || MaxStaticCPSolvePct != 1.) && statsTracker->elapsed() > 60.) { StatisticManager &sm = *theStatisticManager; CallPathNode *cpn = current.stack.back().callPathNode; if ((MaxStaticForkPct<1. && sm.getIndexedValue(stats::forks, sm.getIndex()) > stats::forks*MaxStaticForkPct) || (MaxStaticCPForkPct<1. && cpn && (cpn->statistics.getValue(stats::forks) > stats::forks*MaxStaticCPForkPct)) || (MaxStaticSolvePct<1 && sm.getIndexedValue(stats::solverTime, sm.getIndex()) > stats::solverTime*MaxStaticSolvePct) || (MaxStaticCPForkPct<1. && cpn && (cpn->statistics.getValue(stats::solverTime) > stats::solverTime*MaxStaticCPSolvePct))) { ref value; bool success = solver->getValue(current, condition, value); assert(success && "FIXME: Unhandled solver failure"); (void) success; addConstraint(current, EqExpr::create(value, condition)); condition = value; } } double timeout = coreSolverTimeout; if (isSeeding) timeout *= it->second.size(); solver->setTimeout(timeout); bool success = solver->evaluate(current, condition, res); solver->setTimeout(0); if (!success) { current.pc = current.prevPC; terminateStateEarly(current, "Query timed out (fork)."); return StatePair(0, 0); } if (!isSeeding) { if (replayPath && !isInternal) { assert(replayPositionsize() && "ran out of branches in replay path mode"); bool branch = (*replayPath)[replayPosition++]; if (res==Solver::True) { assert(branch && "hit invalid branch in replay path mode"); } else if (res==Solver::False) { assert(!branch && "hit invalid branch in replay path mode"); } else { // add constraints if(branch) { res = Solver::True; addConstraint(current, condition); } else { res = Solver::False; addConstraint(current, Expr::createIsZero(condition)); } } } else if (res==Solver::Unknown) { assert(!replayKTest && "in replay mode, only one branch can be true."); if ((MaxMemoryInhibit && atMemoryLimit) || current.forkDisabled || inhibitForking || (MaxForks!=~0u && stats::forks >= MaxForks)) { if (MaxMemoryInhibit && atMemoryLimit) klee_warning_once(0, "skipping fork (memory cap exceeded)"); else if (current.forkDisabled) klee_warning_once(0, "skipping fork (fork disabled on current path)"); else if (inhibitForking) klee_warning_once(0, "skipping fork (fork disabled globally)"); else klee_warning_once(0, "skipping fork (max-forks reached)"); TimerStatIncrementer timer(stats::forkTime); if (theRNG.getBool()) { addConstraint(current, condition); res = Solver::True; } else { addConstraint(current, Expr::createIsZero(condition)); res = Solver::False; } } } } // Fix branch in only-replay-seed mode, if we don't have both true // and false seeds. if (isSeeding && (current.forkDisabled || OnlyReplaySeeds) && res == Solver::Unknown) { bool trueSeed=false, falseSeed=false; // Is seed extension still ok here? for (std::vector::iterator siit = it->second.begin(), siie = it->second.end(); siit != siie; ++siit) { ref res; bool success = solver->getValue(current, siit->assignment.evaluate(condition), res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (res->isTrue()) { trueSeed = true; } else { falseSeed = true; } if (trueSeed && falseSeed) break; } if (!(trueSeed && falseSeed)) { assert(trueSeed || falseSeed); res = trueSeed ? Solver::True : Solver::False; addConstraint(current, trueSeed ? condition : Expr::createIsZero(condition)); } } // XXX - even if the constraint is provable one way or the other we // can probably benefit by adding this constraint and allowing it to // reduce the other constraints. For example, if we do a binary // search on a particular value, and then see a comparison against // the value it has been fixed at, we should take this as a nice // hint to just use the single constraint instead of all the binary // search ones. If that makes sense. if (res==Solver::True) { if (!isInternal) { if (pathWriter) { current.pathOS << "1"; } } return StatePair(¤t, 0); } else if (res==Solver::False) { if (!isInternal) { if (pathWriter) { current.pathOS << "0"; } } return StatePair(0, ¤t); } else { TimerStatIncrementer timer(stats::forkTime); ExecutionState *falseState, *trueState = ¤t; ++stats::forks; falseState = trueState->branch(); addedStates.push_back(falseState); if (it != seedMap.end()) { std::vector seeds = it->second; it->second.clear(); std::vector &trueSeeds = seedMap[trueState]; std::vector &falseSeeds = seedMap[falseState]; for (std::vector::iterator siit = seeds.begin(), siie = seeds.end(); siit != siie; ++siit) { ref res; bool success = solver->getValue(current, siit->assignment.evaluate(condition), res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (res->isTrue()) { trueSeeds.push_back(*siit); } else { falseSeeds.push_back(*siit); } } bool swapInfo = false; if (trueSeeds.empty()) { if (¤t == trueState) swapInfo = true; seedMap.erase(trueState); } if (falseSeeds.empty()) { if (¤t == falseState) swapInfo = true; seedMap.erase(falseState); } if (swapInfo) { std::swap(trueState->coveredNew, falseState->coveredNew); std::swap(trueState->coveredLines, falseState->coveredLines); } } current.ptreeNode->data = 0; std::pair res = processTree->split(current.ptreeNode, falseState, trueState); falseState->ptreeNode = res.first; trueState->ptreeNode = res.second; if (pathWriter) { // Need to update the pathOS.id field of falseState, otherwise the same id // is used for both falseState and trueState. falseState->pathOS = pathWriter->open(current.pathOS); if (!isInternal) { trueState->pathOS << "1"; falseState->pathOS << "0"; } } if (symPathWriter) { falseState->symPathOS = symPathWriter->open(current.symPathOS); if (!isInternal) { trueState->symPathOS << "1"; falseState->symPathOS << "0"; } } addConstraint(*trueState, condition); addConstraint(*falseState, Expr::createIsZero(condition)); // Kinda gross, do we even really still want this option? if (MaxDepth && MaxDepth<=trueState->depth) { terminateStateEarly(*trueState, "max-depth exceeded."); terminateStateEarly(*falseState, "max-depth exceeded."); return StatePair(0, 0); } return StatePair(trueState, falseState); } } void Executor::addConstraint(ExecutionState &state, ref condition) { if (ConstantExpr *CE = dyn_cast(condition)) { if (!CE->isTrue()) llvm::report_fatal_error("attempt to add invalid constraint"); return; } // Check to see if this constraint violates seeds. std::map< ExecutionState*, std::vector >::iterator it = seedMap.find(&state); if (it != seedMap.end()) { bool warn = false; for (std::vector::iterator siit = it->second.begin(), siie = it->second.end(); siit != siie; ++siit) { bool res; bool success = solver->mustBeFalse(state, siit->assignment.evaluate(condition), res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (res) { siit->patchSeed(state, condition, solver); warn = true; } } if (warn) klee_warning("seeds patched for violating constraint"); } state.addConstraint(condition); if (ivcEnabled) doImpliedValueConcretization(state, condition, ConstantExpr::alloc(1, Expr::Bool)); } const Cell& Executor::eval(KInstruction *ki, unsigned index, ExecutionState &state) const { assert(index < ki->inst->getNumOperands()); int vnumber = ki->operands[index]; assert(vnumber != -1 && "Invalid operand to eval(), not a value or constant!"); // Determine if this is a constant or not. if (vnumber < 0) { unsigned index = -vnumber - 2; return kmodule->constantTable[index]; } else { unsigned index = vnumber; StackFrame &sf = state.stack.back(); return sf.locals[index]; } } void Executor::bindLocal(KInstruction *target, ExecutionState &state, ref value) { getDestCell(state, target).value = value; } void Executor::bindArgument(KFunction *kf, unsigned index, ExecutionState &state, ref value) { getArgumentCell(state, kf, index).value = value; } ref Executor::toUnique(const ExecutionState &state, ref &e) { ref result = e; if (!isa(e)) { ref value; bool isTrue = false; solver->setTimeout(coreSolverTimeout); if (solver->getValue(state, e, value) && solver->mustBeTrue(state, EqExpr::create(e, value), isTrue) && isTrue) result = value; solver->setTimeout(0); } 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) { e = state.constraints.simplifyExpr(e); if (ConstantExpr *CE = dyn_cast(e)) return CE; ref value; bool success = solver->getValue(state, e, value); assert(success && "FIXME: Unhandled solver failure"); (void) success; std::string str; llvm::raw_string_ostream os(str); os << "silently concretizing (reason: " << reason << ") expression " << e << " to value " << value << " (" << (*(state.pc)).info->file << ":" << (*(state.pc)).info->line << ")"; if (AllExternalWarnings) klee_warning(reason, os.str().c_str()); else klee_warning_once(reason, "%s", os.str().c_str()); addConstraint(state, EqExpr::create(e, value)); return value; } void Executor::executeGetValue(ExecutionState &state, ref e, KInstruction *target) { e = state.constraints.simplifyExpr(e); std::map< ExecutionState*, std::vector >::iterator it = seedMap.find(&state); if (it==seedMap.end() || isa(e)) { ref value; bool success = solver->getValue(state, e, value); assert(success && "FIXME: Unhandled solver failure"); (void) success; bindLocal(target, state, value); } else { std::set< ref > values; for (std::vector::iterator siit = it->second.begin(), siie = it->second.end(); siit != siie; ++siit) { ref value; bool success = solver->getValue(state, siit->assignment.evaluate(e), value); assert(success && "FIXME: Unhandled solver failure"); (void) success; values.insert(value); } std::vector< ref > conditions; for (std::set< ref >::iterator vit = values.begin(), vie = values.end(); vit != vie; ++vit) conditions.push_back(EqExpr::create(e, *vit)); std::vector branches; branch(state, conditions, branches); std::vector::iterator bit = branches.begin(); for (std::set< ref >::iterator vit = values.begin(), vie = values.end(); vit != vie; ++vit) { ExecutionState *es = *bit; if (es) bindLocal(target, *es, *vit); ++bit; } } } void Executor::printDebugInstructions(ExecutionState &state) { // check do not print if (DebugPrintInstructions.getBits() == 0) return; llvm::raw_ostream *stream = 0; if (DebugPrintInstructions.isSet(STDERR_ALL) || DebugPrintInstructions.isSet(STDERR_SRC) || DebugPrintInstructions.isSet(STDERR_COMPACT)) stream = &llvm::errs(); else stream = &debugLogBuffer; if (!DebugPrintInstructions.isSet(STDERR_COMPACT) && !DebugPrintInstructions.isSet(FILE_COMPACT)) { (*stream) << " "; state.pc->printFileLine(*stream); (*stream) << ":"; } (*stream) << state.pc->info->assemblyLine; if (DebugPrintInstructions.isSet(STDERR_ALL) || DebugPrintInstructions.isSet(FILE_ALL)) (*stream) << ":" << *(state.pc->inst); (*stream) << "\n"; if (DebugPrintInstructions.isSet(FILE_ALL) || DebugPrintInstructions.isSet(FILE_COMPACT) || DebugPrintInstructions.isSet(FILE_SRC)) { debugLogBuffer.flush(); (*debugInstFile) << debugLogBuffer.str(); debugBufferString = ""; } } void Executor::stepInstruction(ExecutionState &state) { printDebugInstructions(state); if (statsTracker) statsTracker->stepInstruction(state); ++stats::instructions; ++state.steppedInstructions; state.prevPC = state.pc; ++state.pc; if (stats::instructions==StopAfterNInstructions) haltExecution = true; } void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f, std::vector< ref > &arguments) { Instruction *i = ki->inst; if (f && f->isDeclaration()) { switch(f->getIntrinsicID()) { case Intrinsic::not_intrinsic: // state may be destroyed by this call, cannot touch callExternalFunction(state, ki, f, arguments); break; // va_arg is handled by caller and intrinsic lowering, see comment for // ExecutionState::varargs case Intrinsic::vastart: { StackFrame &sf = state.stack.back(); // varargs can be zero if no varargs were provided if (!sf.varargs) return; // FIXME: This is really specific to the architecture, not the pointer // 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, arguments[0], sf.varargs->getBaseExpr(), 0); } else { assert(WordSize == Expr::Int64 && "Unknown word size!"); // 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, arguments[0], ConstantExpr::create(48, 32), 0); // gp_offset executeMemoryOperation(state, true, AddExpr::create(arguments[0], ConstantExpr::create(4, 64)), ConstantExpr::create(304, 32), 0); // fp_offset executeMemoryOperation(state, true, AddExpr::create(arguments[0], ConstantExpr::create(8, 64)), sf.varargs->getBaseExpr(), 0); // overflow_arg_area executeMemoryOperation(state, true, AddExpr::create(arguments[0], ConstantExpr::create(16, 64)), ConstantExpr::create(0, 64), 0); // reg_save_area } break; } case Intrinsic::vaend: // va_end is a noop for the interpreter. // // FIXME: We should validate that the target didn't do something bad // with va_end, however (like call it twice). break; case Intrinsic::vacopy: // va_copy should have been lowered. // // FIXME: It would be nice to check for errors in the usage of this as // well. default: klee_error("unknown intrinsic: %s", f->getName().data()); } if (InvokeInst *ii = dyn_cast(i)) transferToBasicBlock(ii->getNormalDest(), i->getParent(), state); } else { // FIXME: I'm not really happy about this reliance on prevPC but it is ok, I // guess. This just done to avoid having to pass KInstIterator everywhere // instead of the actual instruction, since we can't make a KInstIterator // from just an instruction (unlike LLVM). KFunction *kf = kmodule->functionMap[f]; state.pushFrame(state.prevPC, kf); state.pc = kf->instructions; if (statsTracker) statsTracker->framePushed(state, &state.stack[state.stack.size()-2]); // TODO: support "byval" parameter attribute // TODO: support zeroext, signext, sret attributes unsigned callingArgs = arguments.size(); unsigned funcArgs = f->arg_size(); if (!f->isVarArg()) { if (callingArgs > funcArgs) { klee_warning_once(f, "calling %s with extra arguments.", f->getName().data()); } else if (callingArgs < funcArgs) { terminateStateOnError(state, "calling function with too few arguments", User); return; } } else { Expr::Width WordSize = Context::get().getPointerWidth(); if (callingArgs < funcArgs) { terminateStateOnError(state, "calling function with too few arguments", User); return; } StackFrame &sf = state.stack.back(); unsigned size = 0; bool requires16ByteAlignment = false; for (unsigned i = funcArgs; i < callingArgs; i++) { // FIXME: This is really specific to the architecture, not the pointer // size. This happens to work for x86-32 and x86-64, however. if (WordSize == Expr::Int32) { size += Expr::getMinBytesForWidth(arguments[i]->getWidth()); } else { Expr::Width argWidth = arguments[i]->getWidth(); // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a // 16 byte boundary if alignment needed by type exceeds 8 byte // boundary. // // Alignment requirements for scalar types is the same as their size if (argWidth > Expr::Int64) { size = llvm::RoundUpToAlignment(size, 16); requires16ByteAlignment = true; } size += llvm::RoundUpToAlignment(argWidth, WordSize) / 8; } } MemoryObject *mo = sf.varargs = memory->allocate(size, true, false, state.prevPC->inst, (requires16ByteAlignment ? 16 : 8)); if (!mo && size) { terminateStateOnExecError(state, "out of memory (varargs)"); return; } if (mo) { if ((WordSize == Expr::Int64) && (mo->address & 15) && requires16ByteAlignment) { // Both 64bit Linux/Glibc and 64bit MacOSX should align to 16 bytes. klee_warning_once( 0, "While allocating varargs: malloc did not align to 16 bytes."); } ObjectState *os = bindObjectInState(state, mo, true); unsigned offset = 0; for (unsigned i = funcArgs; i < callingArgs; i++) { // FIXME: This is really specific to the architecture, not the pointer // size. This happens to work for x86-32 and x86-64, however. if (WordSize == Expr::Int32) { os->write(offset, arguments[i]); offset += Expr::getMinBytesForWidth(arguments[i]->getWidth()); } else { assert(WordSize == Expr::Int64 && "Unknown word size!"); Expr::Width argWidth = arguments[i]->getWidth(); if (argWidth > Expr::Int64) { offset = llvm::RoundUpToAlignment(offset, 16); } os->write(offset, arguments[i]); offset += llvm::RoundUpToAlignment(argWidth, WordSize) / 8; } } } } unsigned numFormals = f->arg_size(); for (unsigned i=0; ibasicBlockEntry[dst]; state.pc = &kf->instructions[entry]; if (state.pc->inst->getOpcode() == Instruction::PHI) { PHINode *first = static_cast(state.pc->inst); state.incomingBBIndex = first->getBasicBlockIndex(src); } } /// Compute the true target of a function call, resolving LLVM and KLEE aliases /// and bitcasts. Function* Executor::getTargetFunction(Value *calledVal, ExecutionState &state) { SmallPtrSet Visited; Constant *c = dyn_cast(calledVal); if (!c) return 0; while (true) { if (GlobalValue *gv = dyn_cast(c)) { #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) if (!Visited.insert(gv).second) return 0; #else if (!Visited.insert(gv)) return 0; #endif std::string alias = state.getFnAlias(gv->getName()); if (alias != "") { llvm::Module* currModule = kmodule->module; GlobalValue *old_gv = gv; gv = currModule->getNamedValue(alias); if (!gv) { klee_error("Function %s(), alias for %s not found!\n", alias.c_str(), old_gv->getName().str().c_str()); } } if (Function *f = dyn_cast(gv)) return f; else if (GlobalAlias *ga = dyn_cast(gv)) c = ga->getAliasee(); else return 0; } else if (llvm::ConstantExpr *ce = dyn_cast(c)) { if (ce->getOpcode()==Instruction::BitCast) c = ce->getOperand(0); else return 0; } else return 0; } } /// TODO remove? static bool isDebugIntrinsic(const Function *f, KModule *KM) { return false; } static inline const llvm::fltSemantics * fpWidthToSemantics(unsigned width) { switch(width) { case Expr::Int32: return &llvm::APFloat::IEEEsingle; case Expr::Int64: return &llvm::APFloat::IEEEdouble; case Expr::Fl80: return &llvm::APFloat::x87DoubleExtended; default: return 0; } } void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { Instruction *i = ki->inst; switch (i->getOpcode()) { // Control flow case Instruction::Ret: { ReturnInst *ri = cast(i); KInstIterator kcaller = state.stack.back().caller; Instruction *caller = kcaller ? kcaller->inst : 0; bool isVoidReturn = (ri->getNumOperands() == 0); ref result = ConstantExpr::alloc(0, Expr::Bool); if (!isVoidReturn) { result = eval(ki, 0, state).value; } if (state.stack.size() <= 1) { assert(!caller && "caller set on initial stack frame"); terminateStateOnExit(state); } else { state.popFrame(); if (statsTracker) statsTracker->framePopped(state); if (InvokeInst *ii = dyn_cast(caller)) { transferToBasicBlock(ii->getNormalDest(), caller->getParent(), state); } else { state.pc = kcaller; ++state.pc; } if (!isVoidReturn) { Type *t = caller->getType(); if (t != Type::getVoidTy(i->getContext())) { // may need to do coercion due to bitcasts Expr::Width from = result->getWidth(); Expr::Width to = getWidthForLLVMType(t); if (from != to) { CallSite cs = (isa(caller) ? CallSite(cast(caller)) : CallSite(cast(caller))); // XXX need to check other param attrs ? bool isSExt = cs.paramHasAttr(0, llvm::Attribute::SExt); if (isSExt) { result = SExtExpr::create(result, to); } else { result = ZExtExpr::create(result, to); } } bindLocal(kcaller, state, result); } } else { // We check that the return value has no users instead of // checking the type, since C defaults to returning int for // undeclared functions. if (!caller->use_empty()) { terminateStateOnExecError(state, "return void when caller expected a result"); } } } break; } case Instruction::Br: { BranchInst *bi = cast(i); if (bi->isUnconditional()) { transferToBasicBlock(bi->getSuccessor(0), bi->getParent(), state); } else { // FIXME: Find a way that we don't have this hidden dependency. assert(bi->getCondition() == bi->getOperand(0) && "Wrong operand index!"); ref cond = eval(ki, 0, state).value; Executor::StatePair branches = fork(state, cond, false); // NOTE: There is a hidden dependency here, markBranchVisited // requires that we still be in the context of the branch // instruction (it reuses its statistic id). Should be cleaned // up with convenient instruction specific data. if (statsTracker && state.stack.back().kf->trackCoverage) statsTracker->markBranchVisited(branches.first, branches.second); if (branches.first) transferToBasicBlock(bi->getSuccessor(0), bi->getParent(), *branches.first); if (branches.second) transferToBasicBlock(bi->getSuccessor(1), bi->getParent(), *branches.second); } break; } case Instruction::IndirectBr: { // implements indirect branch to a label within the current function const auto bi = cast(i); auto address = eval(ki, 0, state).value; address = toUnique(state, address); // concrete address if (const auto CE = dyn_cast(address.get())) { const auto bb_address = (BasicBlock *) CE->getZExtValue(Context::get().getPointerWidth()); transferToBasicBlock(bb_address, bi->getParent(), state); break; } // symbolic address const auto numDestinations = bi->getNumDestinations(); std::vector targets; targets.reserve(numDestinations); std::vector> expressions; expressions.reserve(numDestinations); ref errorCase = ConstantExpr::alloc(1, Expr::Bool); SmallPtrSet destinations; // collect and check destinations from label list for (unsigned k = 0; k < numDestinations; ++k) { // filter duplicates const auto d = bi->getDestination(k); if (destinations.count(d)) continue; destinations.insert(d); // create address expression const auto PE = Expr::createPointer((uint64_t) (unsigned long) (void *) d); ref e = EqExpr::create(address, PE); // exclude address from errorCase errorCase = AndExpr::create(errorCase, Expr::createIsZero(e)); // check feasibility bool result; bool success __attribute__ ((unused)) = solver->mayBeTrue(state, e, result); assert(success && "FIXME: Unhandled solver failure"); if (result) { targets.push_back(d); expressions.push_back(e); } } // check errorCase feasibility bool result; bool success __attribute__ ((unused)) = solver->mayBeTrue(state, errorCase, result); assert(success && "FIXME: Unhandled solver failure"); if (result) { expressions.push_back(errorCase); } // fork states std::vector branches; branch(state, expressions, branches); // terminate error state if (result) { terminateStateOnExecError(*branches.back(), "indirectbr: illegal label address"); branches.pop_back(); } // branch states to resp. target blocks assert(targets.size() == branches.size()); for (std::vector::size_type k = 0; k < branches.size(); ++k) { if (branches[k]) { transferToBasicBlock(targets[k], bi->getParent(), *branches[k]); } } break; } case Instruction::Switch: { SwitchInst *si = cast(i); ref cond = eval(ki, 0, state).value; BasicBlock *bb = si->getParent(); cond = toUnique(state, cond); if (ConstantExpr *CE = dyn_cast(cond)) { // Somewhat gross to create these all the time, but fine till we // switch to an internal rep. llvm::IntegerType *Ty = cast(si->getCondition()->getType()); ConstantInt *ci = ConstantInt::get(Ty, CE->getZExtValue()); unsigned index = si->findCaseValue(ci).getSuccessorIndex(); transferToBasicBlock(si->getSuccessor(index), si->getParent(), state); } else { // Handle possible different branch targets // We have the following assumptions: // - each case value is mutual exclusive to all other values including the // default value // - order of case branches is based on the order of the expressions of // the scase values, still default is handled last std::vector bbOrder; std::map > branchTargets; std::map, BasicBlock *> expressionOrder; // Iterate through all non-default cases and order them by expressions #if LLVM_VERSION_CODE > LLVM_VERSION(3, 4) for (auto i : si->cases()) { #else for (SwitchInst::CaseIt i = si->case_begin(), e = si->case_end(); i != e; ++i) { #endif ref value = evalConstant(i.getCaseValue()); BasicBlock *caseSuccessor = i.getCaseSuccessor(); expressionOrder.insert(std::make_pair(value, caseSuccessor)); } // Track default branch values ref defaultValue = ConstantExpr::alloc(1, Expr::Bool); // iterate through all non-default cases but in order of the expressions for (std::map, BasicBlock *>::iterator it = expressionOrder.begin(), itE = expressionOrder.end(); it != itE; ++it) { ref match = EqExpr::create(cond, it->first); // Make sure that the default value does not contain this target's value defaultValue = AndExpr::create(defaultValue, Expr::createIsZero(match)); // Check if control flow could take this case bool result; bool success = solver->mayBeTrue(state, match, result); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (result) { BasicBlock *caseSuccessor = it->second; // Handle the case that a basic block might be the target of multiple // switch cases. // Currently we generate an expression containing all switch-case // values for the same target basic block. We spare us forking too // many times but we generate more complex condition expressions // TODO Add option to allow to choose between those behaviors std::pair >::iterator, bool> res = branchTargets.insert(std::make_pair( caseSuccessor, ConstantExpr::alloc(0, Expr::Bool))); res.first->second = OrExpr::create(match, res.first->second); // Only add basic blocks which have not been target of a branch yet if (res.second) { bbOrder.push_back(caseSuccessor); } } } // Check if control could take the default case bool res; bool success = solver->mayBeTrue(state, defaultValue, res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (res) { std::pair >::iterator, bool> ret = branchTargets.insert( std::make_pair(si->getDefaultDest(), defaultValue)); if (ret.second) { bbOrder.push_back(si->getDefaultDest()); } } // Fork the current state with each state having one of the possible // successors of this switch std::vector< ref > conditions; for (std::vector::iterator it = bbOrder.begin(), ie = bbOrder.end(); it != ie; ++it) { conditions.push_back(branchTargets[*it]); } std::vector branches; branch(state, conditions, branches); std::vector::iterator bit = branches.begin(); for (std::vector::iterator it = bbOrder.begin(), ie = bbOrder.end(); it != ie; ++it) { ExecutionState *es = *bit; if (es) transferToBasicBlock(*it, bb, *es); ++bit; } } break; } case Instruction::Unreachable: // Note that this is not necessarily an internal bug, llvm will // generate unreachable instructions in cases where it knows the // program will crash. So it is effectively a SEGV or internal // error. terminateStateOnExecError(state, "reached \"unreachable\" instruction"); break; case Instruction::Invoke: case Instruction::Call: { CallSite cs(i); unsigned numArgs = cs.arg_size(); Value *fp = cs.getCalledValue(); Function *f = getTargetFunction(fp, state); // Skip debug intrinsics, we can't evaluate their metadata arguments. if (f && isDebugIntrinsic(f, kmodule)) break; if (isa(fp)) { terminateStateOnExecError(state, "inline assembly is unsupported"); break; } // evaluate arguments std::vector< ref > arguments; arguments.reserve(numArgs); for (unsigned j=0; j(cast(f->getType())->getElementType()); const FunctionType *fpType = dyn_cast(cast(fp->getType())->getElementType()); // special case the call with a bitcast case if (fType != fpType) { assert(fType && fpType && "unable to get function type"); // XXX check result coercion // XXX this really needs thought and validation unsigned i=0; for (std::vector< ref >::iterator ai = arguments.begin(), ie = arguments.end(); ai != ie; ++ai) { Expr::Width to, from = (*ai)->getWidth(); if (igetNumParams()) { to = getWidthForLLVMType(fType->getParamType(i)); if (from != to) { // XXX need to check other param attrs ? bool isSExt = cs.paramHasAttr(i+1, llvm::Attribute::SExt); if (isSExt) { arguments[i] = SExtExpr::create(arguments[i], to); } else { arguments[i] = ZExtExpr::create(arguments[i], to); } } } i++; } } executeCall(state, ki, f, arguments); } else { ref v = eval(ki, 0, state).value; ExecutionState *free = &state; bool hasInvalid = false, first = true; /* XXX This is wasteful, no need to do a full evaluate since we have already got a value. But in the end the caches should handle it for us, albeit with some overhead. */ do { ref value; bool success = solver->getValue(*free, v, value); assert(success && "FIXME: Unhandled solver failure"); (void) success; StatePair res = fork(*free, EqExpr::create(v, value), true); if (res.first) { uint64_t addr = value->getZExtValue(); if (legalFunctions.count(addr)) { f = (Function*) addr; // Don't give warning on unique resolution if (res.second || !first) klee_warning_once((void*) (unsigned long) addr, "resolved symbolic function pointer to: %s", f->getName().data()); executeCall(*res.first, ki, f, arguments); } else { if (!hasInvalid) { terminateStateOnExecError(state, "invalid function pointer"); hasInvalid = true; } } } first = false; free = res.second; } while (free); } break; } case Instruction::PHI: { ref result = eval(ki, state.incomingBBIndex, state).value; bindLocal(ki, state, result); break; } // Special instructions case Instruction::Select: { // NOTE: It is not required that operands 1 and 2 be of scalar type. ref cond = eval(ki, 0, state).value; ref tExpr = eval(ki, 1, state).value; ref fExpr = eval(ki, 2, state).value; ref result = SelectExpr::create(cond, tExpr, fExpr); bindLocal(ki, state, result); break; } case Instruction::VAArg: terminateStateOnExecError(state, "unexpected VAArg instruction"); break; // Arithmetic / logical case Instruction::Add: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; bindLocal(ki, state, AddExpr::create(left, right)); break; } case Instruction::Sub: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; bindLocal(ki, state, SubExpr::create(left, right)); break; } case Instruction::Mul: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; bindLocal(ki, state, MulExpr::create(left, right)); break; } case Instruction::UDiv: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = UDivExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::SDiv: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = SDivExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::URem: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = URemExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::SRem: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = SRemExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::And: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = AndExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::Or: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = OrExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::Xor: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = XorExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::Shl: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = ShlExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::LShr: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = LShrExpr::create(left, right); bindLocal(ki, state, result); break; } case Instruction::AShr: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = AShrExpr::create(left, right); bindLocal(ki, state, result); break; } // Compare case Instruction::ICmp: { CmpInst *ci = cast(i); ICmpInst *ii = cast(ci); switch(ii->getPredicate()) { case ICmpInst::ICMP_EQ: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = EqExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_NE: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = NeExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_UGT: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = UgtExpr::create(left, right); bindLocal(ki, state,result); break; } case ICmpInst::ICMP_UGE: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = UgeExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_ULT: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = UltExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_ULE: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = UleExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_SGT: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = SgtExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_SGE: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = SgeExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_SLT: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = SltExpr::create(left, right); bindLocal(ki, state, result); break; } case ICmpInst::ICMP_SLE: { ref left = eval(ki, 0, state).value; ref right = eval(ki, 1, state).value; ref result = SleExpr::create(left, right); bindLocal(ki, state, result); break; } default: terminateStateOnExecError(state, "invalid ICmp predicate"); } break; } // Memory instructions... case Instruction::Alloca: { AllocaInst *ai = cast(i); unsigned elementSize = kmodule->targetData->getTypeStoreSize(ai->getAllocatedType()); ref size = Expr::createPointer(elementSize); if (ai->isArrayAllocation()) { ref count = eval(ki, 0, state).value; count = Expr::createZExtToPointerWidth(count); size = MulExpr::create(size, count); } executeAlloc(state, size, true, ki); break; } case Instruction::Load: { ref base = eval(ki, 0, state).value; executeMemoryOperation(state, false, base, 0, ki); break; } case Instruction::Store: { ref base = eval(ki, 1, state).value; ref value = eval(ki, 0, state).value; executeMemoryOperation(state, true, base, value, 0); break; } case Instruction::GetElementPtr: { KGEPInstruction *kgepi = static_cast(ki); ref base = eval(ki, 0, state).value; for (std::vector< std::pair >::iterator it = kgepi->indices.begin(), ie = kgepi->indices.end(); it != ie; ++it) { uint64_t elementSize = it->second; ref index = eval(ki, it->first, state).value; base = AddExpr::create(base, MulExpr::create(Expr::createSExtToPointerWidth(index), Expr::createPointer(elementSize))); } if (kgepi->offset) base = AddExpr::create(base, Expr::createPointer(kgepi->offset)); bindLocal(ki, state, base); break; } // Conversion case Instruction::Trunc: { CastInst *ci = cast(i); ref result = ExtractExpr::create(eval(ki, 0, state).value, 0, getWidthForLLVMType(ci->getType())); bindLocal(ki, state, result); break; } case Instruction::ZExt: { CastInst *ci = cast(i); ref result = ZExtExpr::create(eval(ki, 0, state).value, getWidthForLLVMType(ci->getType())); bindLocal(ki, state, result); break; } case Instruction::SExt: { CastInst *ci = cast(i); ref result = SExtExpr::create(eval(ki, 0, state).value, getWidthForLLVMType(ci->getType())); bindLocal(ki, state, result); break; } case Instruction::IntToPtr: { CastInst *ci = cast(i); Expr::Width pType = getWidthForLLVMType(ci->getType()); ref arg = eval(ki, 0, state).value; bindLocal(ki, state, ZExtExpr::create(arg, pType)); break; } case Instruction::PtrToInt: { CastInst *ci = cast(i); Expr::Width iType = getWidthForLLVMType(ci->getType()); ref arg = eval(ki, 0, state).value; bindLocal(ki, state, ZExtExpr::create(arg, iType)); break; } case Instruction::BitCast: { ref result = eval(ki, 0, state).value; bindLocal(ki, state, result); break; } // Floating point instructions case Instruction::FAdd: { ref left = toConstant(state, eval(ki, 0, state).value, "floating point"); ref right = toConstant(state, eval(ki, 1, state).value, "floating point"); if (!fpWidthToSemantics(left->getWidth()) || !fpWidthToSemantics(right->getWidth())) return terminateStateOnExecError(state, "Unsupported FAdd operation"); llvm::APFloat Res(*fpWidthToSemantics(left->getWidth()), left->getAPValue()); Res.add(APFloat(*fpWidthToSemantics(right->getWidth()),right->getAPValue()), APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(Res.bitcastToAPInt())); break; } case Instruction::FSub: { ref left = toConstant(state, eval(ki, 0, state).value, "floating point"); ref right = toConstant(state, eval(ki, 1, state).value, "floating point"); if (!fpWidthToSemantics(left->getWidth()) || !fpWidthToSemantics(right->getWidth())) return terminateStateOnExecError(state, "Unsupported FSub operation"); llvm::APFloat Res(*fpWidthToSemantics(left->getWidth()), left->getAPValue()); Res.subtract(APFloat(*fpWidthToSemantics(right->getWidth()), right->getAPValue()), APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(Res.bitcastToAPInt())); break; } case Instruction::FMul: { ref left = toConstant(state, eval(ki, 0, state).value, "floating point"); ref right = toConstant(state, eval(ki, 1, state).value, "floating point"); if (!fpWidthToSemantics(left->getWidth()) || !fpWidthToSemantics(right->getWidth())) return terminateStateOnExecError(state, "Unsupported FMul operation"); llvm::APFloat Res(*fpWidthToSemantics(left->getWidth()), left->getAPValue()); Res.multiply(APFloat(*fpWidthToSemantics(right->getWidth()), right->getAPValue()), APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(Res.bitcastToAPInt())); break; } case Instruction::FDiv: { ref left = toConstant(state, eval(ki, 0, state).value, "floating point"); ref right = toConstant(state, eval(ki, 1, state).value, "floating point"); if (!fpWidthToSemantics(left->getWidth()) || !fpWidthToSemantics(right->getWidth())) return terminateStateOnExecError(state, "Unsupported FDiv operation"); llvm::APFloat Res(*fpWidthToSemantics(left->getWidth()), left->getAPValue()); Res.divide(APFloat(*fpWidthToSemantics(right->getWidth()), right->getAPValue()), APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(Res.bitcastToAPInt())); break; } case Instruction::FRem: { ref left = toConstant(state, eval(ki, 0, state).value, "floating point"); ref right = toConstant(state, eval(ki, 1, state).value, "floating point"); if (!fpWidthToSemantics(left->getWidth()) || !fpWidthToSemantics(right->getWidth())) return terminateStateOnExecError(state, "Unsupported FRem operation"); llvm::APFloat Res(*fpWidthToSemantics(left->getWidth()), left->getAPValue()); Res.mod(APFloat(*fpWidthToSemantics(right->getWidth()),right->getAPValue()), APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(Res.bitcastToAPInt())); break; } case Instruction::FPTrunc: { FPTruncInst *fi = cast(i); Expr::Width resultType = getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (!fpWidthToSemantics(arg->getWidth()) || resultType > arg->getWidth()) return terminateStateOnExecError(state, "Unsupported FPTrunc operation"); llvm::APFloat Res(*fpWidthToSemantics(arg->getWidth()), arg->getAPValue()); bool losesInfo = false; Res.convert(*fpWidthToSemantics(resultType), llvm::APFloat::rmNearestTiesToEven, &losesInfo); bindLocal(ki, state, ConstantExpr::alloc(Res)); break; } case Instruction::FPExt: { FPExtInst *fi = cast(i); Expr::Width resultType = getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (!fpWidthToSemantics(arg->getWidth()) || arg->getWidth() > resultType) return terminateStateOnExecError(state, "Unsupported FPExt operation"); llvm::APFloat Res(*fpWidthToSemantics(arg->getWidth()), arg->getAPValue()); bool losesInfo = false; Res.convert(*fpWidthToSemantics(resultType), llvm::APFloat::rmNearestTiesToEven, &losesInfo); bindLocal(ki, state, ConstantExpr::alloc(Res)); break; } case Instruction::FPToUI: { FPToUIInst *fi = cast(i); Expr::Width resultType = getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (!fpWidthToSemantics(arg->getWidth()) || resultType > 64) return terminateStateOnExecError(state, "Unsupported FPToUI operation"); llvm::APFloat Arg(*fpWidthToSemantics(arg->getWidth()), arg->getAPValue()); uint64_t value = 0; bool isExact = true; Arg.convertToInteger(&value, resultType, false, llvm::APFloat::rmTowardZero, &isExact); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); break; } case Instruction::FPToSI: { FPToSIInst *fi = cast(i); Expr::Width resultType = getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (!fpWidthToSemantics(arg->getWidth()) || resultType > 64) return terminateStateOnExecError(state, "Unsupported FPToSI operation"); llvm::APFloat Arg(*fpWidthToSemantics(arg->getWidth()), arg->getAPValue()); uint64_t value = 0; bool isExact = true; Arg.convertToInteger(&value, resultType, true, llvm::APFloat::rmTowardZero, &isExact); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); break; } case Instruction::UIToFP: { UIToFPInst *fi = cast(i); Expr::Width resultType = getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); const llvm::fltSemantics *semantics = fpWidthToSemantics(resultType); if (!semantics) return terminateStateOnExecError(state, "Unsupported UIToFP operation"); llvm::APFloat f(*semantics, 0); f.convertFromAPInt(arg->getAPValue(), false, llvm::APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(f)); break; } case Instruction::SIToFP: { SIToFPInst *fi = cast(i); Expr::Width resultType = getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); const llvm::fltSemantics *semantics = fpWidthToSemantics(resultType); if (!semantics) return terminateStateOnExecError(state, "Unsupported SIToFP operation"); llvm::APFloat f(*semantics, 0); f.convertFromAPInt(arg->getAPValue(), true, llvm::APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(f)); break; } case Instruction::FCmp: { FCmpInst *fi = cast(i); ref left = toConstant(state, eval(ki, 0, state).value, "floating point"); ref right = toConstant(state, eval(ki, 1, state).value, "floating point"); if (!fpWidthToSemantics(left->getWidth()) || !fpWidthToSemantics(right->getWidth())) return terminateStateOnExecError(state, "Unsupported FCmp operation"); APFloat LHS(*fpWidthToSemantics(left->getWidth()),left->getAPValue()); APFloat RHS(*fpWidthToSemantics(right->getWidth()),right->getAPValue()); APFloat::cmpResult CmpRes = LHS.compare(RHS); bool Result = false; switch( fi->getPredicate() ) { // Predicates which only care about whether or not the operands are NaNs. case FCmpInst::FCMP_ORD: Result = CmpRes != APFloat::cmpUnordered; break; case FCmpInst::FCMP_UNO: Result = CmpRes == APFloat::cmpUnordered; break; // Ordered comparisons return false if either operand is NaN. Unordered // comparisons return true if either operand is NaN. case FCmpInst::FCMP_UEQ: if (CmpRes == APFloat::cmpUnordered) { Result = true; break; } case FCmpInst::FCMP_OEQ: Result = CmpRes == APFloat::cmpEqual; break; case FCmpInst::FCMP_UGT: if (CmpRes == APFloat::cmpUnordered) { Result = true; break; } case FCmpInst::FCMP_OGT: Result = CmpRes == APFloat::cmpGreaterThan; break; case FCmpInst::FCMP_UGE: if (CmpRes == APFloat::cmpUnordered) { Result = true; break; } case FCmpInst::FCMP_OGE: Result = CmpRes == APFloat::cmpGreaterThan || CmpRes == APFloat::cmpEqual; break; case FCmpInst::FCMP_ULT: if (CmpRes == APFloat::cmpUnordered) { Result = true; break; } case FCmpInst::FCMP_OLT: Result = CmpRes == APFloat::cmpLessThan; break; case FCmpInst::FCMP_ULE: if (CmpRes == APFloat::cmpUnordered) { Result = true; break; } case FCmpInst::FCMP_OLE: Result = CmpRes == APFloat::cmpLessThan || CmpRes == APFloat::cmpEqual; break; case FCmpInst::FCMP_UNE: Result = CmpRes == APFloat::cmpUnordered || CmpRes != APFloat::cmpEqual; break; case FCmpInst::FCMP_ONE: Result = CmpRes != APFloat::cmpUnordered && CmpRes != APFloat::cmpEqual; break; default: assert(0 && "Invalid FCMP predicate!"); case FCmpInst::FCMP_FALSE: Result = false; break; case FCmpInst::FCMP_TRUE: Result = true; break; } bindLocal(ki, state, ConstantExpr::alloc(Result, Expr::Bool)); break; } case Instruction::InsertValue: { KGEPInstruction *kgepi = static_cast(ki); ref agg = eval(ki, 0, state).value; ref val = eval(ki, 1, state).value; ref l = NULL, r = NULL; unsigned lOffset = kgepi->offset*8, rOffset = kgepi->offset*8 + val->getWidth(); if (lOffset > 0) l = ExtractExpr::create(agg, 0, lOffset); if (rOffset < agg->getWidth()) r = ExtractExpr::create(agg, rOffset, agg->getWidth() - rOffset); ref result; if (!l.isNull() && !r.isNull()) result = ConcatExpr::create(r, ConcatExpr::create(val, l)); else if (!l.isNull()) result = ConcatExpr::create(val, l); else if (!r.isNull()) result = ConcatExpr::create(r, val); else result = val; bindLocal(ki, state, result); break; } case Instruction::ExtractValue: { KGEPInstruction *kgepi = static_cast(ki); ref agg = eval(ki, 0, state).value; ref result = ExtractExpr::create(agg, kgepi->offset*8, getWidthForLLVMType(i->getType())); bindLocal(ki, state, result); break; } case Instruction::Fence: { // Ignore for now break; } case Instruction::InsertElement: { InsertElementInst *iei = cast(i); ref vec = eval(ki, 0, state).value; ref newElt = eval(ki, 1, state).value; ref idx = eval(ki, 2, state).value; ConstantExpr *cIdx = dyn_cast(idx); if (cIdx == NULL) { terminateStateOnError( state, "InsertElement, support for symbolic index not implemented", Unhandled); return; } uint64_t iIdx = cIdx->getZExtValue(); const llvm::VectorType *vt = iei->getType(); unsigned EltBits = getWidthForLLVMType(vt->getElementType()); if (iIdx >= vt->getNumElements()) { // Out of bounds write terminateStateOnError(state, "Out of bounds write when inserting element", BadVectorAccess); return; } const unsigned elementCount = vt->getNumElements(); llvm::SmallVector, 8> elems; elems.reserve(elementCount); for (unsigned i = elementCount; i != 0; --i) { auto of = i - 1; unsigned bitOffset = EltBits * of; elems.push_back( of == iIdx ? newElt : ExtractExpr::create(vec, bitOffset, EltBits)); } assert(Context::get().isLittleEndian() && "FIXME:Broken for big endian"); ref Result = ConcatExpr::createN(elementCount, elems.data()); bindLocal(ki, state, Result); break; } case Instruction::ExtractElement: { ExtractElementInst *eei = cast(i); ref vec = eval(ki, 0, state).value; ref idx = eval(ki, 1, state).value; ConstantExpr *cIdx = dyn_cast(idx); if (cIdx == NULL) { terminateStateOnError( state, "ExtractElement, support for symbolic index not implemented", Unhandled); return; } uint64_t iIdx = cIdx->getZExtValue(); const llvm::VectorType *vt = eei->getVectorOperandType(); unsigned EltBits = getWidthForLLVMType(vt->getElementType()); if (iIdx >= vt->getNumElements()) { // Out of bounds read terminateStateOnError(state, "Out of bounds read when extracting element", BadVectorAccess); return; } unsigned bitOffset = EltBits * iIdx; ref Result = ExtractExpr::create(vec, bitOffset, EltBits); bindLocal(ki, state, Result); break; } case Instruction::ShuffleVector: // Should never happen due to Scalarizer pass removing ShuffleVector // instructions. terminateStateOnExecError(state, "Unexpected ShuffleVector instruction"); break; // Other instructions... // Unhandled default: terminateStateOnExecError(state, "illegal instruction"); break; } } void Executor::updateStates(ExecutionState *current) { if (searcher) { searcher->update(current, addedStates, removedStates); searcher->update(nullptr, continuedStates, pausedStates); pausedStates.clear(); continuedStates.clear(); } states.insert(addedStates.begin(), addedStates.end()); addedStates.clear(); for (std::vector::iterator it = removedStates.begin(), ie = removedStates.end(); it != ie; ++it) { ExecutionState *es = *it; std::set::iterator it2 = states.find(es); assert(it2!=states.end()); states.erase(it2); std::map >::iterator it3 = seedMap.find(es); if (it3 != seedMap.end()) seedMap.erase(it3); processTree->remove(es->ptreeNode); delete es; } removedStates.clear(); } template void Executor::computeOffsets(KGEPInstruction *kgepi, TypeIt ib, TypeIt ie) { ref constantOffset = ConstantExpr::alloc(0, Context::get().getPointerWidth()); uint64_t index = 1; for (TypeIt ii = ib; ii != ie; ++ii) { if (StructType *st = dyn_cast(*ii)) { 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())); } else { const SequentialType *set = cast(*ii); uint64_t elementSize = kmodule->targetData->getTypeStoreSize(set->getElementType()); Value *operand = ii.getOperand(); if (Constant *c = dyn_cast(operand)) { ref index = evalConstant(c)->SExt(Context::get().getPointerWidth()); ref addend = index->Mul(ConstantExpr::alloc(elementSize, Context::get().getPointerWidth())); constantOffset = constantOffset->Add(addend); } else { kgepi->indices.push_back(std::make_pair(index, elementSize)); } } index++; } kgepi->offset = constantOffset->getZExtValue(); } void Executor::bindInstructionConstants(KInstruction *KI) { KGEPInstruction *kgepi = static_cast(KI); if (GetElementPtrInst *gepi = dyn_cast(KI->inst)) { computeOffsets(kgepi, gep_type_begin(gepi), gep_type_end(gepi)); } else if (InsertValueInst *ivi = dyn_cast(KI->inst)) { 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)) { computeOffsets(kgepi, ev_type_begin(evi), ev_type_end(evi)); assert(kgepi->indices.empty() && "ExtractValue constant offset expected"); } } void Executor::bindModuleConstants() { for (std::vector::iterator it = kmodule->functions.begin(), ie = kmodule->functions.end(); it != ie; ++it) { KFunction *kf = *it; for (unsigned i=0; inumInstructions; ++i) bindInstructionConstants(kf->instructions[i]); } kmodule->constantTable = new Cell[kmodule->constants.size()]; for (unsigned i=0; iconstants.size(); ++i) { Cell &c = kmodule->constantTable[i]; c.value = evalConstant(kmodule->constants[i]); } } void Executor::checkMemoryUsage() { if (!MaxMemory) return; if ((stats::instructions & 0xFFFF) == 0) { // We need to avoid calling GetTotalMallocUsage() often because it // is O(elts on freelist). This is really bad since we start // to pummel the freelist once we hit the memory cap. unsigned mbs = (util::GetTotalMallocUsage() >> 20) + (memory->getUsedDeterministicSize() >> 20); if (mbs > MaxMemory) { if (mbs > MaxMemory + 100) { // just guess at how many to kill unsigned numStates = states.size(); unsigned toKill = std::max(1U, numStates - numStates * MaxMemory / mbs); klee_warning("killing %d states (over memory cap)", toKill); std::vector arr(states.begin(), states.end()); for (unsigned i = 0, N = arr.size(); N && i < toKill; ++i, --N) { unsigned idx = rand() % N; // Make two pulls to try and not hit a state that // covered new code. if (arr[idx]->coveredNew) idx = rand() % N; std::swap(arr[idx], arr[N - 1]); terminateStateEarly(*arr[N - 1], "Memory limit exceeded."); } } atMemoryLimit = true; } else { atMemoryLimit = false; } } } void Executor::doDumpStates() { if (!DumpStatesOnHalt || states.empty()) return; klee_message("halting execution, dumping remaining states"); for (const auto &state : states) terminateStateEarly(*state, "Execution halting."); updateStates(nullptr); } void Executor::run(ExecutionState &initialState) { bindModuleConstants(); // Delay init till now so that ticks don't accrue during // optimization and such. initTimers(); states.insert(&initialState); if (usingSeeds) { std::vector &v = seedMap[&initialState]; for (std::vector::const_iterator it = usingSeeds->begin(), ie = usingSeeds->end(); it != ie; ++it) v.push_back(SeedInfo(*it)); int lastNumSeeds = usingSeeds->size()+10; double lastTime, startTime = lastTime = util::getWallTime(); ExecutionState *lastState = 0; while (!seedMap.empty()) { if (haltExecution) { doDumpStates(); return; } std::map >::iterator it = seedMap.upper_bound(lastState); if (it == seedMap.end()) it = seedMap.begin(); lastState = it->first; unsigned numSeeds = it->second.size(); ExecutionState &state = *lastState; KInstruction *ki = state.pc; stepInstruction(state); executeInstruction(state, ki); processTimers(&state, MaxInstructionTime * numSeeds); updateStates(&state); if ((stats::instructions % 1000) == 0) { int numSeeds = 0, numStates = 0; for (std::map >::iterator it = seedMap.begin(), ie = seedMap.end(); it != ie; ++it) { numSeeds += it->second.size(); numStates++; } double time = util::getWallTime(); if (SeedTime>0. && time > startTime + SeedTime) { klee_warning("seed time expired, %d seeds remain over %d states", numSeeds, numStates); break; } else if (numSeeds<=lastNumSeeds-10 || time >= lastTime+10) { lastTime = time; lastNumSeeds = numSeeds; klee_message("%d seeds remaining over: %d states", numSeeds, numStates); } } } klee_message("seeding done (%d states remain)", (int) states.size()); // XXX total hack, just because I like non uniform better but want // seed results to be equally weighted. for (std::set::iterator it = states.begin(), ie = states.end(); it != ie; ++it) { (*it)->weight = 1.; } if (OnlySeed) { doDumpStates(); return; } } searcher = constructUserSearcher(*this); std::vector newStates(states.begin(), states.end()); searcher->update(0, newStates, std::vector()); while (!states.empty() && !haltExecution) { ExecutionState &state = searcher->selectState(); KInstruction *ki = state.pc; stepInstruction(state); executeInstruction(state, ki); processTimers(&state, MaxInstructionTime); checkMemoryUsage(); updateStates(&state); } delete searcher; searcher = 0; doDumpStates(); } std::string Executor::getAddressInfo(ExecutionState &state, ref address) const{ std::string Str; llvm::raw_string_ostream info(Str); info << "\taddress: " << address << "\n"; uint64_t example; if (ConstantExpr *CE = dyn_cast(address)) { example = CE->getZExtValue(); } else { ref value; bool success = solver->getValue(state, address, value); assert(success && "FIXME: Unhandled solver failure"); (void) success; example = value->getZExtValue(); info << "\texample: " << example << "\n"; std::pair< ref, ref > res = solver->getRange(state, address); info << "\trange: [" << res.first << ", " << res.second <<"]\n"; } MemoryObject hack((unsigned) example); MemoryMap::iterator lower = state.addressSpace.objects.upper_bound(&hack); info << "\tnext: "; if (lower==state.addressSpace.objects.end()) { info << "none\n"; } else { const MemoryObject *mo = lower->first; std::string alloc_info; mo->getAllocInfo(alloc_info); info << "object at " << mo->address << " of size " << mo->size << "\n" << "\t\t" << alloc_info << "\n"; } if (lower!=state.addressSpace.objects.begin()) { --lower; info << "\tprev: "; if (lower==state.addressSpace.objects.end()) { info << "none\n"; } else { const MemoryObject *mo = lower->first; std::string alloc_info; mo->getAllocInfo(alloc_info); info << "object at " << mo->address << " of size " << mo->size << "\n" << "\t\t" << alloc_info << "\n"; } } return info.str(); } void Executor::pauseState(ExecutionState &state){ auto it = std::find(continuedStates.begin(), continuedStates.end(), &state); // If the state was to be continued, but now gets paused again if (it != continuedStates.end()){ // ...just don't continue it std::swap(*it, continuedStates.back()); continuedStates.pop_back(); } else { pausedStates.push_back(&state); } } void Executor::continueState(ExecutionState &state){ auto it = std::find(pausedStates.begin(), pausedStates.end(), &state); // If the state was to be paused, but now gets continued again if (it != pausedStates.end()){ // ...don't pause it std::swap(*it, pausedStates.back()); pausedStates.pop_back(); } else { continuedStates.push_back(&state); } } void Executor::terminateState(ExecutionState &state) { if (replayKTest && replayPosition!=replayKTest->numObjects) { klee_warning_once(replayKTest, "replay did not consume all objects in test input."); } interpreterHandler->incPathsExplored(); std::vector::iterator it = std::find(addedStates.begin(), addedStates.end(), &state); if (it==addedStates.end()) { state.pc = state.prevPC; removedStates.push_back(&state); } else { // never reached searcher, just delete immediately std::map< ExecutionState*, std::vector >::iterator it3 = seedMap.find(&state); if (it3 != seedMap.end()) seedMap.erase(it3); addedStates.erase(it); processTree->remove(state.ptreeNode); delete &state; } } void Executor::terminateStateEarly(ExecutionState &state, const Twine &message) { if (!OnlyOutputStatesCoveringNew || state.coveredNew || (AlwaysOutputSeeds && seedMap.count(&state))) interpreterHandler->processTestCase(state, (message + "\n").str().c_str(), "early"); terminateState(state); } void Executor::terminateStateOnExit(ExecutionState &state) { if (!OnlyOutputStatesCoveringNew || state.coveredNew || (AlwaysOutputSeeds && seedMap.count(&state))) interpreterHandler->processTestCase(state, 0, 0); terminateState(state); } const InstructionInfo & Executor::getLastNonKleeInternalInstruction(const ExecutionState &state, Instruction ** lastInstruction) { // unroll the stack of the applications state and find // the last instruction which is not inside a KLEE internal function ExecutionState::stack_ty::const_reverse_iterator it = state.stack.rbegin(), itE = state.stack.rend(); // don't check beyond the outermost function (i.e. main()) itE--; const InstructionInfo * ii = 0; if (kmodule->internalFunctions.count(it->kf->function) == 0){ ii = state.prevPC->info; *lastInstruction = state.prevPC->inst; // Cannot return yet because even though // it->function is not an internal function it might of // been called from an internal function. } // Wind up the stack and check if we are in a KLEE internal function. // We visit the entire stack because we want to return a CallInstruction // that was not reached via any KLEE internal functions. for (;it != itE; ++it) { // check calling instruction and if it is contained in a KLEE internal function const Function * f = (*it->caller).inst->getParent()->getParent(); if (kmodule->internalFunctions.count(f)){ ii = 0; continue; } if (!ii){ ii = (*it->caller).info; *lastInstruction = (*it->caller).inst; } } if (!ii) { // something went wrong, play safe and return the current instruction info *lastInstruction = state.prevPC->inst; return *state.prevPC->info; } return *ii; } bool Executor::shouldExitOn(enum TerminateReason termReason) { std::vector::iterator s = ExitOnErrorType.begin(); std::vector::iterator e = ExitOnErrorType.end(); for (; s != e; ++s) if (termReason == *s) return true; return false; } void Executor::terminateStateOnError(ExecutionState &state, const llvm::Twine &messaget, enum TerminateReason termReason, const char *suffix, const llvm::Twine &info) { std::string message = messaget.str(); static std::set< std::pair > emittedErrors; Instruction * lastInst; const InstructionInfo &ii = getLastNonKleeInternalInstruction(state, &lastInst); if (EmitAllErrors || emittedErrors.insert(std::make_pair(lastInst, message)).second) { if (ii.file != "") { klee_message("ERROR: %s:%d: %s", ii.file.c_str(), ii.line, message.c_str()); } else { klee_message("ERROR: (location information missing) %s", message.c_str()); } if (!EmitAllErrors) klee_message("NOTE: now ignoring this error at this location"); std::string MsgString; llvm::raw_string_ostream msg(MsgString); msg << "Error: " << message << "\n"; if (ii.file != "") { msg << "File: " << ii.file << "\n"; msg << "Line: " << ii.line << "\n"; msg << "assembly.ll line: " << ii.assemblyLine << "\n"; } msg << "Stack: \n"; state.dumpStack(msg); std::string info_str = info.str(); if (info_str != "") msg << "Info: \n" << info_str; std::string suffix_buf; if (!suffix) { suffix_buf = TerminateReasonNames[termReason]; suffix_buf += ".err"; suffix = suffix_buf.c_str(); } interpreterHandler->processTestCase(state, msg.str().c_str(), suffix); } terminateState(state); if (shouldExitOn(termReason)) haltExecution = true; } // XXX shoot me static const char *okExternalsList[] = { "printf", "fprintf", "puts", "getpid" }; static std::set okExternals(okExternalsList, okExternalsList + (sizeof(okExternalsList)/sizeof(okExternalsList[0]))); void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, Function *function, std::vector< ref > &arguments) { // check if specialFunctionHandler wants it if (specialFunctionHandler->handle(state, function, target, arguments)) return; if (NoExternals && !okExternals.count(function->getName())) { klee_warning("Disallowed call to external function: %s\n", function->getName().str().c_str()); terminateStateOnError(state, "externals disallowed", User); return; } // normal external function handling path // allocate 128 bits for each argument (+return value) to support fp80's; // we could iterate through all the arguments first and determine the exact // size we need, but this is faster, and the memory usage isn't significant. uint64_t *args = (uint64_t*) alloca(2*sizeof(*args) * (arguments.size() + 1)); memset(args, 0, 2 * sizeof(*args) * (arguments.size() + 1)); unsigned wordIndex = 2; for (std::vector >::iterator ai = arguments.begin(), ae = arguments.end(); ai!=ae; ++ai) { if (AllowExternalSymCalls) { // don't bother checking uniqueness ref ce; bool success = solver->getValue(state, *ai, ce); assert(success && "FIXME: Unhandled solver failure"); (void) success; ce->toMemory(&args[wordIndex]); wordIndex += (ce->getWidth()+63)/64; } else { ref arg = toUnique(state, *ai); if (ConstantExpr *ce = dyn_cast(arg)) { // XXX kick toMemory functions from here ce->toMemory(&args[wordIndex]); wordIndex += (ce->getWidth()+63)/64; } else { terminateStateOnExecError(state, "external call with symbolic argument: " + function->getName()); return; } } } // Prepare external memory for invoking the function state.addressSpace.copyOutConcretes(); #ifndef WINDOWS // Update external errno state with local state value int *errno_addr = getErrnoLocation(state); ObjectPair result; bool resolved = state.addressSpace.resolveOne( ConstantExpr::create((uint64_t)errno_addr, Expr::Int64), result); if (!resolved) klee_error("Could not resolve memory object for errno"); ref errValueExpr = result.second->read(0, sizeof(*errno_addr) * 8); ConstantExpr *errnoValue = dyn_cast(errValueExpr); if (!errnoValue) { terminateStateOnExecError(state, "external call with errno value symbolic: " + function->getName()); return; } externalDispatcher->setLastErrno( errnoValue->getZExtValue(sizeof(*errno_addr) * 8)); #endif if (!SuppressExternalWarnings) { std::string TmpStr; llvm::raw_string_ostream os(TmpStr); os << "calling external: " << function->getName().str() << "("; for (unsigned i=0; iprintFileLine(os); if (AllExternalWarnings) klee_warning("%s", os.str().c_str()); else klee_warning_once(function, "%s", os.str().c_str()); } bool success = externalDispatcher->executeCall(function, target->inst, args); if (!success) { terminateStateOnError(state, "failed external call: " + function->getName(), External); return; } if (!state.addressSpace.copyInConcretes()) { terminateStateOnError(state, "external modified read-only object", External); return; } #ifndef WINDOWS // Update errno memory object with the errno value from the call int error = externalDispatcher->getLastErrno(); state.addressSpace.copyInConcrete(result.first, result.second, (uint64_t)&error); #endif Type *resultType = target->inst->getType(); if (resultType != Type::getVoidTy(function->getContext())) { ref e = ConstantExpr::fromMemory((void*) args, getWidthForLLVMType(resultType)); bindLocal(target, state, e); } } /***/ ref Executor::replaceReadWithSymbolic(ExecutionState &state, ref e) { unsigned n = interpreterOpts.MakeConcreteSymbolic; if (!n || replayKTest || replayPath) return e; // right now, we don't replace symbolics (is there any reason to?) if (!isa(e)) return e; if (n != 1 && random() % n) return e; // create a new fresh location, assert it is equal to concrete value in e // and return it. static unsigned id; const Array *array = arrayCache.CreateArray("rrws_arr" + llvm::utostr(++id), Expr::getMinBytesForWidth(e->getWidth())); ref res = Expr::createTempRead(array, e->getWidth()); ref eq = NotOptimizedExpr::create(EqExpr::create(e, res)); llvm::errs() << "Making symbolic: " << eq << "\n"; state.addConstraint(eq); return res; } ObjectState *Executor::bindObjectInState(ExecutionState &state, const MemoryObject *mo, bool isLocal, const Array *array) { 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 // will put multiple copies on this list, but it doesn't really // matter because all we use this list for is to unbind the object // on function return. if (isLocal) state.stack.back().allocas.push_back(mo); return os; } void Executor::executeAlloc(ExecutionState &state, ref size, bool isLocal, KInstruction *target, bool zeroMemory, const ObjectState *reallocFrom) { size = toUnique(state, size); if (ConstantExpr *CE = dyn_cast(size)) { const llvm::Value *allocSite = state.prevPC->inst; size_t allocationAlignment = getAllocationAlignment(allocSite); MemoryObject *mo = memory->allocate(CE->getZExtValue(), isLocal, /*isGlobal=*/false, allocSite, allocationAlignment); if (!mo) { bindLocal(target, state, ConstantExpr::alloc(0, Context::get().getPointerWidth())); } else { ObjectState *os = bindObjectInState(state, mo, isLocal); if (zeroMemory) { os->initializeToZero(); } else { os->initializeToRandom(); } bindLocal(target, state, mo->getBaseExpr()); if (reallocFrom) { unsigned count = std::min(reallocFrom->size, os->size); for (unsigned i=0; iwrite(i, reallocFrom->read8(i)); state.addressSpace.unbindObject(reallocFrom->getObject()); } } } else { // XXX For now we just pick a size. Ideally we would support // symbolic sizes fully but even if we don't it would be better to // "smartly" pick a value, for example we could fork and pick the // min and max values and perhaps some intermediate (reasonable // value). // // It would also be nice to recognize the case when size has // exactly two values and just fork (but we need to get rid of // return argument first). This shows up in pcre when llvm // collapses the size expression with a select. ref example; bool success = solver->getValue(state, size, example); assert(success && "FIXME: Unhandled solver failure"); (void) success; // Try and start with a small example. Expr::Width W = example->getWidth(); while (example->Ugt(ConstantExpr::alloc(128, W))->isTrue()) { ref tmp = example->LShr(ConstantExpr::alloc(1, W)); bool res; bool success = solver->mayBeTrue(state, EqExpr::create(tmp, size), res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (!res) break; example = tmp; } StatePair fixedSize = fork(state, EqExpr::create(example, size), true); if (fixedSize.second) { // Check for exactly two values ref tmp; bool success = solver->getValue(*fixedSize.second, size, tmp); assert(success && "FIXME: Unhandled solver failure"); (void) success; bool res; success = solver->mustBeTrue(*fixedSize.second, EqExpr::create(tmp, size), res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (res) { executeAlloc(*fixedSize.second, tmp, isLocal, target, zeroMemory, reallocFrom); } else { // See if a *really* big value is possible. If so assume // malloc will fail for it, so lets fork and return 0. StatePair hugeSize = fork(*fixedSize.second, UltExpr::create(ConstantExpr::alloc(1U<<31, W), size), true); if (hugeSize.first) { klee_message("NOTE: found huge malloc, returning 0"); bindLocal(target, *hugeSize.first, ConstantExpr::alloc(0, Context::get().getPointerWidth())); } if (hugeSize.second) { std::string Str; llvm::raw_string_ostream info(Str); ExprPPrinter::printOne(info, " size expr", size); info << " concretization : " << example << "\n"; info << " unbound example: " << tmp << "\n"; terminateStateOnError(*hugeSize.second, "concretized symbolic size", Model, NULL, info.str()); } } } if (fixedSize.first) // can be zero when fork fails executeAlloc(*fixedSize.first, example, isLocal, target, zeroMemory, reallocFrom); } } void Executor::executeFree(ExecutionState &state, ref address, KInstruction *target) { StatePair zeroPointer = fork(state, Expr::createIsZero(address), true); if (zeroPointer.first) { if (target) bindLocal(target, *zeroPointer.first, Expr::createPointer(0)); } if (zeroPointer.second) { // address != 0 ExactResolutionList rl; resolveExact(*zeroPointer.second, address, rl, "free"); for (Executor::ExactResolutionList::iterator it = rl.begin(), ie = rl.end(); it != ie; ++it) { const MemoryObject *mo = it->first.first; if (mo->isLocal) { terminateStateOnError(*it->second, "free of alloca", Free, NULL, getAddressInfo(*it->second, address)); } else if (mo->isGlobal) { terminateStateOnError(*it->second, "free of global", Free, NULL, getAddressInfo(*it->second, address)); } else { it->second->addressSpace.unbindObject(mo); if (target) bindLocal(target, *it->second, Expr::createPointer(0)); } } } } void Executor::resolveExact(ExecutionState &state, ref p, ExactResolutionList &results, const std::string &name) { // XXX we may want to be capping this? ResolutionList rl; state.addressSpace.resolve(state, solver, p, rl); ExecutionState *unbound = &state; for (ResolutionList::iterator it = rl.begin(), ie = rl.end(); it != ie; ++it) { ref inBounds = EqExpr::create(p, it->first->getBaseExpr()); StatePair branches = fork(*unbound, inBounds, true); if (branches.first) results.push_back(std::make_pair(*it, branches.first)); unbound = branches.second; if (!unbound) // Fork failure break; } if (unbound) { terminateStateOnError(*unbound, "memory error: invalid pointer: " + name, Ptr, NULL, getAddressInfo(*unbound, p)); } } void Executor::executeMemoryOperation(ExecutionState &state, bool isWrite, ref address, ref value /* undef if read */, KInstruction *target /* undef if write */) { Expr::Width type = (isWrite ? value->getWidth() : getWidthForLLVMType(target->inst->getType())); unsigned bytes = Expr::getMinBytesForWidth(type); if (SimplifySymIndices) { if (!isa(address)) address = state.constraints.simplifyExpr(address); if (isWrite && !isa(value)) value = state.constraints.simplifyExpr(value); } // fast path: single in-bounds resolution ObjectPair op; bool success; solver->setTimeout(coreSolverTimeout); if (!state.addressSpace.resolveOne(state, solver, address, op, success)) { address = toConstant(state, address, "resolveOne failure"); success = state.addressSpace.resolveOne(cast(address), op); } solver->setTimeout(0); if (success) { const MemoryObject *mo = op.first; if (MaxSymArraySize && mo->size>=MaxSymArraySize) { address = toConstant(state, address, "max-sym-array-size"); } ref offset = mo->getOffsetExpr(address); bool inBounds; solver->setTimeout(coreSolverTimeout); bool success = solver->mustBeTrue(state, mo->getBoundsCheckOffset(offset, bytes), inBounds); solver->setTimeout(0); if (!success) { state.pc = state.prevPC; terminateStateEarly(state, "Query timed out (bounds check)."); return; } if (inBounds) { const ObjectState *os = op.second; if (isWrite) { if (os->readOnly) { terminateStateOnError(state, "memory error: object read only", ReadOnly); } else { ObjectState *wos = state.addressSpace.getWriteable(mo, os); wos->write(offset, value); } } else { ref result = os->read(offset, type); if (interpreterOpts.MakeConcreteSymbolic) result = replaceReadWithSymbolic(state, result); bindLocal(target, state, result); } return; } } // we are on an error path (no resolution, multiple resolution, one // resolution with out of bounds) ResolutionList rl; solver->setTimeout(coreSolverTimeout); bool incomplete = state.addressSpace.resolve(state, solver, address, rl, 0, coreSolverTimeout); solver->setTimeout(0); // XXX there is some query wasteage here. who cares? ExecutionState *unbound = &state; for (ResolutionList::iterator i = rl.begin(), ie = rl.end(); i != ie; ++i) { const MemoryObject *mo = i->first; const ObjectState *os = i->second; ref inBounds = mo->getBoundsCheckPointer(address, bytes); StatePair branches = fork(*unbound, inBounds, true); ExecutionState *bound = branches.first; // bound can be 0 on failure or overlapped if (bound) { if (isWrite) { if (os->readOnly) { terminateStateOnError(*bound, "memory error: object read only", ReadOnly); } else { ObjectState *wos = bound->addressSpace.getWriteable(mo, os); wos->write(mo->getOffsetExpr(address), value); } } else { ref result = os->read(mo->getOffsetExpr(address), type); bindLocal(target, *bound, result); } } unbound = branches.second; if (!unbound) break; } // XXX should we distinguish out of bounds and overlapped cases? if (unbound) { if (incomplete) { terminateStateEarly(*unbound, "Query timed out (resolve)."); } else { terminateStateOnError(*unbound, "memory error: out of bound pointer", Ptr, NULL, getAddressInfo(*unbound, address)); } } } void Executor::executeMakeSymbolic(ExecutionState &state, const MemoryObject *mo, const std::string &name) { // Create a new object state for the memory object (instead of a copy). if (!replayKTest) { // Find a unique name for this array. First try the original name, // or if that fails try adding a unique identifier. unsigned id = 0; std::string uniqueName = name; while (!state.arrayNames.insert(uniqueName).second) { uniqueName = name + "_" + llvm::utostr(++id); } const Array *array = arrayCache.CreateArray(uniqueName, mo->size); bindObjectInState(state, mo, false, array); state.addSymbolic(mo, array); std::map< ExecutionState*, std::vector >::iterator it = seedMap.find(&state); if (it!=seedMap.end()) { // In seed mode we need to add this as a // binding. for (std::vector::iterator siit = it->second.begin(), siie = it->second.end(); siit != siie; ++siit) { SeedInfo &si = *siit; KTestObject *obj = si.getNextInput(mo, NamedSeedMatching); if (!obj) { if (ZeroSeedExtension) { std::vector &values = si.assignment.bindings[array]; values = std::vector(mo->size, '\0'); } else if (!AllowSeedExtension) { terminateStateOnError(state, "ran out of inputs during seeding", User); break; } } else { if (obj->numBytes != mo->size && ((!(AllowSeedExtension || ZeroSeedExtension) && obj->numBytes < mo->size) || (!AllowSeedTruncation && obj->numBytes > mo->size))) { std::stringstream msg; msg << "replace size mismatch: " << mo->name << "[" << mo->size << "]" << " vs " << obj->name << "[" << obj->numBytes << "]" << " in test\n"; terminateStateOnError(state, msg.str(), User); break; } else { std::vector &values = si.assignment.bindings[array]; values.insert(values.begin(), obj->bytes, obj->bytes + std::min(obj->numBytes, mo->size)); if (ZeroSeedExtension) { for (unsigned i=obj->numBytes; isize; ++i) values.push_back('\0'); } } } } } } else { ObjectState *os = bindObjectInState(state, mo, false); if (replayPosition >= replayKTest->numObjects) { terminateStateOnError(state, "replay count mismatch", User); } else { KTestObject *obj = &replayKTest->objects[replayPosition++]; if (obj->numBytes != mo->size) { terminateStateOnError(state, "replay size mismatch", User); } else { for (unsigned i=0; isize; i++) os->write8(i, obj->bytes[i]); } } } } /***/ void Executor::runFunctionAsMain(Function *f, int argc, char **argv, char **envp) { std::vector > arguments; // force deterministic initialization of memory objects srand(1); srandom(1); MemoryObject *argvMO = 0; // In order to make uclibc happy and be closer to what the system is // doing we lay out the environments at the end of the argv array // (both are terminated by a null). There is also a final terminating // null that uclibc seems to expect, possibly the ELF header? int envc; for (envc=0; envp[envc]; ++envc) ; unsigned NumPtrBytes = Context::get().getPointerWidth() / 8; KFunction *kf = kmodule->functionMap[f]; assert(kf); Function::arg_iterator ai = f->arg_begin(), ae = f->arg_end(); if (ai!=ae) { arguments.push_back(ConstantExpr::alloc(argc, Expr::Int32)); if (++ai!=ae) { Instruction *first = &*(f->begin()->begin()); argvMO = memory->allocate((argc + 1 + envc + 1 + 1) * NumPtrBytes, /*isLocal=*/false, /*isGlobal=*/true, /*allocSite=*/first, /*alignment=*/8); if (!argvMO) klee_error("Could not allocate memory for function arguments"); arguments.push_back(argvMO->getBaseExpr()); if (++ai!=ae) { uint64_t envp_start = argvMO->address + (argc+1)*NumPtrBytes; arguments.push_back(Expr::createPointer(envp_start)); if (++ai!=ae) klee_error("invalid main function (expect 0-3 arguments)"); } } } ExecutionState *state = new ExecutionState(kmodule->functionMap[f]); if (pathWriter) state->pathOS = pathWriter->open(); if (symPathWriter) state->symPathOS = symPathWriter->open(); if (statsTracker) statsTracker->framePushed(*state, 0); assert(arguments.size() == f->arg_size() && "wrong number of arguments"); for (unsigned i = 0, e = f->arg_size(); i != e; ++i) bindArgument(kf, i, *state, arguments[i]); if (argvMO) { ObjectState *argvOS = bindObjectInState(*state, argvMO, false); for (int i=0; i=argc+1+envc) { // Write NULL pointer argvOS->write(i * NumPtrBytes, Expr::createPointer(0)); } else { char *s = iallocate(len + 1, /*isLocal=*/false, /*isGlobal=*/true, /*allocSite=*/state->pc->inst, /*alignment=*/8); if (!arg) klee_error("Could not allocate memory for function arguments"); ObjectState *os = bindObjectInState(*state, arg, false); for (j=0; jwrite8(j, s[j]); // Write pointer to newly allocated and initialised argv/envp c-string argvOS->write(i * NumPtrBytes, arg->getBaseExpr()); } } } initializeGlobals(*state); processTree = new PTree(state); state->ptreeNode = processTree->root; run(*state); delete processTree; processTree = 0; // hack to clear memory objects delete memory; memory = new MemoryManager(NULL); globalObjects.clear(); globalAddresses.clear(); if (statsTracker) statsTracker->done(); } unsigned Executor::getPathStreamID(const ExecutionState &state) { assert(pathWriter); return state.pathOS.getID(); } unsigned Executor::getSymbolicPathStreamID(const ExecutionState &state) { assert(symPathWriter); return state.symPathOS.getID(); } void Executor::getConstraintLog(const ExecutionState &state, std::string &res, Interpreter::LogType logFormat) { switch (logFormat) { case STP: { Query query(state.constraints, ConstantExpr::alloc(0, Expr::Bool)); char *log = solver->getConstraintLog(query); res = std::string(log); free(log); } break; case KQUERY: { std::string Str; llvm::raw_string_ostream info(Str); ExprPPrinter::printConstraints(info, state.constraints); res = info.str(); } break; case SMTLIB2: { std::string Str; llvm::raw_string_ostream info(Str); ExprSMTLIBPrinter printer; printer.setOutput(info); Query query(state.constraints, ConstantExpr::alloc(0, Expr::Bool)); printer.setQuery(query); printer.generateOutput(); res = info.str(); } break; default: klee_warning("Executor::getConstraintLog() : Log format not supported!"); } } bool Executor::getSymbolicSolution(const ExecutionState &state, std::vector< std::pair > > &res) { solver->setTimeout(coreSolverTimeout); ExecutionState tmp(state); // Go through each byte in every test case and attempt to restrict // it to the constraints contained in cexPreferences. (Note: // usually this means trying to make it an ASCII character (0-127) // and therefore human readable. It is also possible to customize // the preferred constraints. See test/Features/PreferCex.c for // an example) While this process can be very expensive, it can // also make understanding individual test cases much easier. for (unsigned i = 0; i != state.symbolics.size(); ++i) { const MemoryObject *mo = state.symbolics[i].first; std::vector< ref >::const_iterator pi = mo->cexPreferences.begin(), pie = mo->cexPreferences.end(); for (; pi != pie; ++pi) { bool mustBeTrue; // Attempt to bound byte to constraints held in cexPreferences bool success = solver->mustBeTrue(tmp, Expr::createIsZero(*pi), mustBeTrue); // If it isn't possible to constrain this particular byte in the desired // way (normally this would mean that the byte can't be constrained to // be between 0 and 127 without making the entire constraint list UNSAT) // then just continue on to the next byte. if (!success) break; // If the particular constraint operated on in this iteration through // the loop isn't implied then add it to the list of constraints. if (!mustBeTrue) tmp.addConstraint(*pi); } if (pi!=pie) break; } std::vector< std::vector > values; std::vector objects; for (unsigned i = 0; i != state.symbolics.size(); ++i) objects.push_back(state.symbolics[i].second); bool success = solver->getInitialValues(tmp, objects, values); solver->setTimeout(0); if (!success) { klee_warning("unable to compute initial values (invalid constraints?)!"); ExprPPrinter::printQuery(llvm::errs(), state.constraints, ConstantExpr::alloc(0, Expr::Bool)); return false; } for (unsigned i = 0; i != state.symbolics.size(); ++i) res.push_back(std::make_pair(state.symbolics[i].first->name, values[i])); return true; } void Executor::getCoveredLines(const ExecutionState &state, std::map > &res) { res = state.coveredLines; } void Executor::doImpliedValueConcretization(ExecutionState &state, ref e, ref value) { abort(); // FIXME: Broken until we sort out how to do the write back. if (DebugCheckForImpliedValues) ImpliedValue::checkForImpliedValues(solver->solver, e, value); ImpliedValueList results; ImpliedValue::getImpliedValues(e, value, results); for (ImpliedValueList::iterator it = results.begin(), ie = results.end(); it != ie; ++it) { ReadExpr *re = it->first.get(); if (ConstantExpr *CE = dyn_cast(re->index)) { // FIXME: This is the sole remaining usage of the Array object // variable. Kill me. const MemoryObject *mo = 0; //re->updates.root->object; const ObjectState *os = state.addressSpace.findObject(mo); if (!os) { // object has been free'd, no need to concretize (although as // in other cases we would like to concretize the outstanding // reads, but we have no facility for that yet) } else { assert(!os->readOnly && "not possible? read only object with static read?"); ObjectState *wos = state.addressSpace.getWriteable(mo, os); wos->write(CE, it->second); } } } } Expr::Width Executor::getWidthForLLVMType(llvm::Type *type) const { return kmodule->targetData->getTypeSizeInBits(type); } size_t Executor::getAllocationAlignment(const llvm::Value *allocSite) const { // FIXME: 8 was the previous default. We shouldn't hard code this // and should fetch the default from elsewhere. const size_t forcedAlignment = 8; size_t alignment = 0; llvm::Type *type = NULL; std::string allocationSiteName(allocSite->getName().str()); if (const GlobalValue *GV = dyn_cast(allocSite)) { alignment = GV->getAlignment(); if (const GlobalVariable *globalVar = dyn_cast(GV)) { // All GlobalVariables's have pointer type llvm::PointerType *ptrType = dyn_cast(globalVar->getType()); assert(ptrType && "globalVar's type is not a pointer"); type = ptrType->getElementType(); } else { type = GV->getType(); } } else if (const AllocaInst *AI = dyn_cast(allocSite)) { alignment = AI->getAlignment(); type = AI->getAllocatedType(); } else if (isa(allocSite) || isa(allocSite)) { // FIXME: Model the semantics of the call to use the right alignment llvm::Value *allocSiteNonConst = const_cast(allocSite); const CallSite cs = (isa(allocSiteNonConst) ? CallSite(cast(allocSiteNonConst)) : CallSite(cast(allocSiteNonConst))); llvm::Function *fn = klee::getDirectCallTarget(cs, /*moduleIsFullyLinked=*/true); if (fn) allocationSiteName = fn->getName().str(); klee_warning_once(fn != NULL ? fn : allocSite, "Alignment of memory from call \"%s\" is not " "modelled. Using alignment of %zu.", allocationSiteName.c_str(), forcedAlignment); alignment = forcedAlignment; } else { llvm_unreachable("Unhandled allocation site"); } if (alignment == 0) { assert(type != NULL); // No specified alignment. Get the alignment for the type. if (type->isSized()) { alignment = kmodule->targetData->getPrefTypeAlignment(type); } else { klee_warning_once(allocSite, "Cannot determine memory alignment for " "\"%s\". Using alignment of %zu.", allocationSiteName.c_str(), forcedAlignment); alignment = forcedAlignment; } } // Currently we require alignment be a power of 2 if (!bits64::isPowerOfTwo(alignment)) { klee_warning_once(allocSite, "Alignment of %zu requested for %s but this " "not supported. Using alignment of %zu", alignment, allocSite->getName().str().c_str(), forcedAlignment); alignment = forcedAlignment; } assert(bits64::isPowerOfTwo(alignment) && "Returned alignment must be a power of two"); return alignment; } void Executor::prepareForEarlyExit() { if (statsTracker) { // Make sure stats get flushed out statsTracker->done(); } } /// Returns the errno location in memory int *Executor::getErrnoLocation(const ExecutionState &state) const { #ifndef __APPLE__ /* From /usr/include/errno.h: it [errno] is a per-thread variable. */ return __errno_location(); #else return __error(); #endif } /// Interpreter *Interpreter::create(LLVMContext &ctx, const InterpreterOptions &opts, InterpreterHandler *ih) { return new Executor(ctx, opts, ih); }