//===-- 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 "Common.h" #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 "../Solver/SolverStats.h" #include "klee/ExecutionState.h" #include "klee/Expr.h" #include "klee/Interpreter.h" #include "klee/TimerStatIncrementer.h" #include "klee/util/Assignment.h" #include "klee/util/ExprPPrinter.h" #include "klee/util/ExprUtil.h" #include "klee/Config/config.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/FloatEvaluation.h" #include "klee/Internal/System/Time.h" #include "llvm/Attributes.h" #include "llvm/BasicBlock.h" #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" #include "llvm/Module.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Process.h" #include "llvm/Target/TargetData.h" #include #include #include #include #include #include #include #include #include #include #include using namespace llvm; using namespace klee; // omg really hard to share cl opts across files ... bool WriteTraces = false; namespace { cl::opt DumpStatesOnHalt("dump-states-on-halt", cl::init(true)); cl::opt NoPreferCex("no-prefer-cex", cl::init(false)); cl::opt UseAsmAddresses("use-asm-addresses", cl::init(false)); cl::opt RandomizeFork("randomize-fork", cl::init(false)); cl::opt AllowExternalSymCalls("allow-external-sym-calls", cl::init(false)); cl::opt DebugPrintInstructions("debug-print-instructions", cl::desc("Print instructions during execution.")); cl::opt DebugCheckForImpliedValues("debug-check-for-implied-values"); cl::opt SimplifySymIndices("simplify-sym-indices", cl::init(false)); cl::opt MaxSymArraySize("max-sym-array-size", cl::init(0)); cl::opt DebugValidateSolver("debug-validate-solver", cl::init(false)); cl::opt SuppressExternalWarnings("suppress-external-warnings"); cl::opt AllExternalWarnings("all-external-warnings"); cl::opt OnlyOutputStatesCoveringNew("only-output-states-covering-new", cl::init(false)); cl::opt AlwaysOutputSeeds("always-output-seeds", cl::init(true)); cl::opt UseFastCexSolver("use-fast-cex-solver", cl::init(false)); cl::opt UseIndependentSolver("use-independent-solver", cl::init(true), cl::desc("Use constraint independence")); cl::opt EmitAllErrors("emit-all-errors", cl::init(false), cl::desc("Generate tests cases for all errors " "(default=one per (error,instruction) pair)")); cl::opt UseCexCache("use-cex-cache", cl::init(true), cl::desc("Use counterexample caching")); cl::opt UseQueryLog("use-query-log", cl::init(false)); cl::opt UseQueryPCLog("use-query-pc-log", cl::init(false)); cl::opt UseSTPQueryPCLog("use-stp-query-pc-log", cl::init(false)); cl::opt NoExternals("no-externals", cl::desc("Do not allow external functin calls")); cl::opt UseCache("use-cache", cl::init(true), cl::desc("Use validity caching")); cl::opt OnlyReplaySeeds("only-replay-seeds", cl::desc("Discard states that do not have a seed.")); cl::opt OnlySeed("only-seed", cl::desc("Stop execution after seeding is done without doing regular search.")); cl::opt AllowSeedExtension("allow-seed-extension", cl::desc("Allow extra (unbound) values to become symbolic during seeding.")); cl::opt ZeroSeedExtension("zero-seed-extension"); cl::opt AllowSeedTruncation("allow-seed-truncation", cl::desc("Allow smaller buffers than in seeds.")); cl::opt NamedSeedMatching("named-seed-matching", cl::desc("Use names to match symbolic objects to inputs.")); cl::opt MaxStaticForkPct("max-static-fork-pct", cl::init(1.)); cl::opt MaxStaticSolvePct("max-static-solve-pct", cl::init(1.)); cl::opt MaxStaticCPForkPct("max-static-cpfork-pct", cl::init(1.)); cl::opt MaxStaticCPSolvePct("max-static-cpsolve-pct", cl::init(1.)); cl::opt MaxInstructionTime("max-instruction-time", cl::desc("Only allow a single instruction to take this much time (default=0 (off))"), 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::opt MaxSTPTime("max-stp-time", cl::desc("Maximum amount of time for a single query (default=120s)"), cl::init(120.0)); cl::opt StopAfterNInstructions("stop-after-n-instructions", cl::desc("Stop execution after specified number of instructions (0=off)"), cl::init(0)); cl::opt MaxForks("max-forks", cl::desc("Only fork this many times (-1=off)"), cl::init(~0u)); cl::opt MaxDepth("max-depth", cl::desc("Only allow this many symbolic branches (0=off)"), cl::init(0)); cl::opt MaxMemory("max-memory", cl::desc("Refuse to fork when more above this about of memory (in MB, 0=off)"), cl::init(0)); cl::opt MaxMemoryInhibit("max-memory-inhibit", cl::desc("Inhibit forking at memory cap (vs. random terminate)"), cl::init(true)); // use 'external storage' because also needed by tools/klee/main.cpp cl::opt WriteTracesProxy("write-traces", cl::desc("Write .trace file for each terminated state"), cl::location(WriteTraces), cl::init(false)); cl::opt UseForkedSTP("use-forked-stp", cl::desc("Run STP in forked process")); } static void *theMMap = 0; static unsigned theMMapSize = 0; namespace klee { RNG theRNG; } Solver *constructSolverChain(STPSolver *stpSolver, std::string queryLogPath, std::string stpQueryLogPath, std::string queryPCLogPath, std::string stpQueryPCLogPath) { Solver *solver = stpSolver; if (UseSTPQueryPCLog) solver = createPCLoggingSolver(solver, stpQueryLogPath); if (UseFastCexSolver) solver = createFastCexSolver(solver); if (UseCexCache) solver = createCexCachingSolver(solver); if (UseCache) solver = createCachingSolver(solver); if (UseIndependentSolver) solver = createIndependentSolver(solver); if (DebugValidateSolver) solver = createValidatingSolver(solver, stpSolver); if (UseQueryPCLog) solver = createPCLoggingSolver(solver, queryPCLogPath); return solver; } Executor::Executor(const InterpreterOptions &opts, InterpreterHandler *ih) : Interpreter(opts), kmodule(0), interpreterHandler(ih), searcher(0), externalDispatcher(new ExternalDispatcher()), statsTracker(0), pathWriter(0), symPathWriter(0), specialFunctionHandler(0), processTree(0), replayOut(0), replayPath(0), usingSeeds(0), atMemoryLimit(false), inhibitForking(false), haltExecution(false), ivcEnabled(false), stpTimeout(std::min(MaxSTPTime,MaxInstructionTime)) { STPSolver *stpSolver = new STPSolver(UseForkedSTP); Solver *solver = constructSolverChain(stpSolver, interpreterHandler->getOutputFilename("queries.qlog"), interpreterHandler->getOutputFilename("stp-queries.qlog"), interpreterHandler->getOutputFilename("queries.pc"), interpreterHandler->getOutputFilename("stp-queries.pc")); this->solver = new TimingSolver(solver, stpSolver); memory = new MemoryManager(); } 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. TargetData *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()) { statsTracker = new StatsTracker(*this, interpreterHandler->getOutputFilename("assembly.ll"), userSearcherRequiresMD2U()); } return module; } Executor::~Executor() { delete memory; delete externalDispatcher; if (processTree) delete processTree; if (specialFunctionHandler) delete specialFunctionHandler; if (statsTracker) delete statsTracker; delete solver; delete kmodule; } /***/ void Executor::initializeGlobalObject(ExecutionState &state, ObjectState *os, Constant *c, unsigned offset) { TargetData *targetData = kmodule->targetData; if (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 (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 (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 { 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; } void Executor::initializeGlobals(ExecutionState &state) { Module *m = kmodule->module; if (m->getModuleInlineAsm() != "") klee_warning("executable has module level assembly (ignoring)"); assert(m->lib_begin() == m->lib_end() && "XXX do not support dependent libraries"); // 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->getNameStr())) { 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)); } // Disabled, we don't want to promote use of live externals. #ifdef HAVE_CTYPE_EXTERNALS #ifndef WINDOWS #ifndef DARWIN /* From /usr/include/errno.h: it [errno] is a per-thread variable. */ int *errno_addr = __errno_location(); addExternalObject(state, (void *)errno_addr, sizeof *errno_addr, false); /* 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, (void *)(*addr-128), 384 * sizeof **addr, true); addExternalObject(state, addr, 4, true); const int32_t **lower_addr = __ctype_tolower_loc(); addExternalObject(state, (void *)(*lower_addr-128), 384 * sizeof **lower_addr, true); addExternalObject(state, lower_addr, 4, true); const int32_t **upper_addr = __ctype_toupper_loc(); addExternalObject(state, (void *)(*upper_addr-128), 384 * sizeof **upper_addr, true); addExternalObject(state, upper_addr, 4, 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) { 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. const Type *ty = i->getType()->getElementType(); uint64_t size = kmodule->targetData->getTypeStoreSize(ty); // 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) { llvm::errs() << "Unable to find size for global variable: " << i->getName() << " (use will result in out of bounds access)\n"; } MemoryObject *mo = memory->allocate(size, false, true, i); ObjectState *os = bindObjectInState(state, mo, false); globalObjects.insert(std::make_pair(i, mo)); globalAddresses.insert(std::make_pair(i, 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") { extern void *__dso_handle __attribute__ ((__weak__)); addr = &__dso_handle; // wtf ? } else { addr = externalDispatcher->resolveSymbol(i->getNameStr()); } 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 { const Type *ty = i->getType()->getElementType(); uint64_t size = kmodule->targetData->getTypeStoreSize(ty); MemoryObject *mo = 0; if (UseAsmAddresses && i->getName()[0]=='\01') { char *end; uint64_t address = ::strtoll(i->getNameStr().c_str()+1, &end, 0); if (end && *end == '\0') { klee_message("NOTE: allocated global at asm specified address: %#08llx" " (%llu bytes)", address, size); mo = memory->allocateFixed(address, size, &*i); mo->isUserSpecified = true; // XXX hack; } } if (!mo) mo = memory->allocate(size, false, true, &*i); assert(mo && "out of memory"); ObjectState *os = bindObjectInState(state, mo, false); globalObjects.insert(std::make_pair(i, mo)); globalAddresses.insert(std::make_pair(i, 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()) { MemoryObject *mo = globalObjects.find(i)->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); stats::forks += N-1; // XXX do proper balance or keep random? result.push_back(&state); for (unsigned i=1; ibranch(); addedStates.insert(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; 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 = stpTimeout; 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"); 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(!replayOut && "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.insert(falseState); if (RandomizeFork && theRNG.getBool()) std::swap(trueState, 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 (!isInternal) { if (pathWriter) { falseState->pathOS = pathWriter->open(current.pathOS); trueState->pathOS << "1"; falseState->pathOS << "0"; } if (symPathWriter) { falseState->symPathOS = symPathWriter->open(current.symPathOS); 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)) { assert(CE->isTrue() && "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)); } ref Executor::evalConstant(Constant *c) { if (llvm::ConstantExpr *ce = dyn_cast(c)) { return evalConstantExpr(ce); } else { if (const ConstantInt *ci = dyn_cast(c)) { return ConstantExpr::alloc(ci->getValue()); } else if (const ConstantFP *cf = dyn_cast(c)) { return ConstantExpr::alloc(cf->getValueAPF().bitcastToAPInt()); } else if (const GlobalValue *gv = dyn_cast(c)) { return globalAddresses.find(gv)->second; } else if (isa(c)) { return Expr::createPointer(0); } else if (isa(c)) { return ConstantExpr::create(0, Expr::getWidthForLLVMType(c->getType())); } else { // Constant{AggregateZero,Array,Struct,Vector} assert(0 && "invalid argument to evalConstant()"); } } } const Cell& Executor::eval(KInstruction *ki, unsigned index, ExecutionState &state) const { assert(index < ki->inst->getNumOperands()); int vnumber = ki->operands[index]; // 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(stpTimeout); 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::ostringstream os; 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::stepInstruction(ExecutionState &state) { if (DebugPrintInstructions) { printFileLine(state, state.pc); llvm::cerr << std::setw(10) << stats::instructions << " " << *state.pc->inst; } if (statsTracker) statsTracker->stepInstruction(state); ++stats::instructions; 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) { if (WriteTraces) { // don't print out special debug stop point 'function' calls if (f->getIntrinsicID() != Intrinsic::dbg_stoppoint) state.exeTraceMgr.addEvent(new FunctionCallTraceEvent(state, ki, f->getName())); } Instruction *i = ki->inst; if (f && f->isDeclaration()) { if (f!=kmodule->dbgStopPointFn) { // special case speed hack switch(f->getIntrinsicID()) { case Intrinsic::dbg_stoppoint: case Intrinsic::dbg_region_start: case Intrinsic::dbg_region_end: case Intrinsic::dbg_func_start: case Intrinsic::dbg_declare: case Intrinsic::not_intrinsic: // state may be destroyed by this call, cannot touch callExternalFunction(state, ki, f, arguments); break; // vararg is handled by caller and intrinsic lowering, // see comment for ExecutionState::varargs case Intrinsic::vastart: { StackFrame &sf = state.stack.back(); assert(sf.varargs && "vastart called in function with no vararg object"); executeMemoryOperation(state, true, arguments[0], sf.varargs->getBaseExpr(), 0); break; } case Intrinsic::vaend: // va_end is a noop for the interpreter break; case Intrinsic::vacopy: // should be lowered default: klee_error("unknown intrinsic: %s", f->getName().data()); } } if (InvokeInst *ii = dyn_cast(i)) { transferToBasicBlock(ii->getNormalDest(), i->getParent(), state); } } else { // XXX not really happy about this reliance on prevPC but 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]); 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.err"); return; } } else { if (callingArgs < funcArgs) { terminateStateOnError(state, "calling function with too few arguments", "user.err"); return; } StackFrame &sf = state.stack.back(); unsigned size = 0; for (unsigned i = funcArgs; i < callingArgs; i++) size += Expr::getMinBytesForWidth(arguments[i]->getWidth()); MemoryObject *mo = sf.varargs = memory->allocate(size, true, false, state.prevPC->inst); if (!mo) { terminateStateOnExecError(state, "out of memory (varargs)"); return; } ObjectState *os = bindObjectInState(state, mo, true); unsigned offset = 0; for (unsigned i = funcArgs; i < callingArgs; i++) { // XXX: DRE: i think we bind memory objects here? os->write(offset, arguments[i]); offset += Expr::getMinBytesForWidth(arguments[i]->getWidth()); } } 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); } } void Executor::printFileLine(ExecutionState &state, KInstruction *ki) { const InstructionInfo &ii = *ki->info; if (ii.file != "") llvm::cerr << " " << ii.file << ":" << ii.line << ":"; else llvm::cerr << " [no debug info]:"; } Function* Executor::getCalledFunction(CallSite &cs, ExecutionState &state) { Function *f = cs.getCalledFunction(); if (f) { std::string alias = state.getFnAlias(f->getName()); if (alias != "") { llvm::Module* currModule = kmodule->module; Function* old_f = f; f = currModule->getFunction(alias); if (!f) { llvm::errs() << "Function " << alias << "(), alias for " << old_f->getName() << " not found!\n"; assert(f && "function alias not found"); } } } return f; } 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 (WriteTraces) { state.exeTraceMgr.addEvent(new FunctionReturnTraceEvent(state, ki)); } 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) { const Type *t = caller->getType(); if (t != Type::VoidTy) { // may need to do coercion due to bitcasts Expr::Width from = result->getWidth(); Expr::Width to = Expr::getWidthForLLVMType(t); if (from != to) { CallSite cs = (isa(caller) ? CallSite(cast(caller)) : CallSite(cast(caller))); // XXX need to check other param attrs ? if (cs.paramHasAttr(0, llvm::Attribute::SExt)) { 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::Unwind: { for (;;) { KInstruction *kcaller = state.stack.back().caller; state.popFrame(); if (statsTracker) statsTracker->framePopped(state); if (state.stack.empty()) { terminateStateOnExecError(state, "unwind from initial stack frame"); break; } else { Instruction *caller = kcaller->inst; if (InvokeInst *ii = dyn_cast(caller)) { transferToBasicBlock(ii->getUnwindDest(), caller->getParent(), state); break; } } } 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); if (WriteTraces) { bool isTwoWay = (branches.first && branches.second); if (branches.first) { branches.first->exeTraceMgr.addEvent( new BranchTraceEvent(state, ki, true, isTwoWay)); } if (branches.second) { branches.second->exeTraceMgr.addEvent( new BranchTraceEvent(state, ki, false, isTwoWay)); } } // 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::Switch: { SwitchInst *si = cast(i); ref cond = eval(ki, 0, state).value; unsigned cases = si->getNumCases(); 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. const llvm::IntegerType *Ty = cast(si->getCondition()->getType()); ConstantInt *ci = ConstantInt::get(Ty, CE->getZExtValue()); unsigned index = si->findCaseValue(ci); transferToBasicBlock(si->getSuccessor(index), si->getParent(), state); } else { std::map > targets; ref isDefault = ConstantExpr::alloc(1, Expr::Bool); for (unsigned i=1; i value = evalConstant(si->getCaseValue(i)); ref match = EqExpr::create(cond, value); isDefault = AndExpr::create(isDefault, Expr::createIsZero(match)); bool result; bool success = solver->mayBeTrue(state, match, result); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (result) { std::map >::iterator it = targets.insert(std::make_pair(si->getSuccessor(i), ConstantExpr::alloc(0, Expr::Bool))).first; it->second = OrExpr::create(match, it->second); } } bool res; bool success = solver->mayBeTrue(state, isDefault, res); assert(success && "FIXME: Unhandled solver failure"); (void) success; if (res) targets.insert(std::make_pair(si->getSuccessor(0), isDefault)); std::vector< ref > conditions; for (std::map >::iterator it = targets.begin(), ie = targets.end(); it != ie; ++it) conditions.push_back(it->second); std::vector branches; branch(state, conditions, branches); std::vector::iterator bit = branches.begin(); for (std::map >::iterator it = targets.begin(), ie = targets.end(); it != ie; ++it) { ExecutionState *es = *bit; if (es) transferToBasicBlock(it->first, 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; unsigned argStart; if (i->getOpcode()==Instruction::Call) { cs = CallSite(cast(i)); argStart = 1; } else { cs = CallSite(cast(i)); argStart = 3; } unsigned numArgs = cs.arg_size(); Function *f = getCalledFunction(cs, state); // evaluate arguments std::vector< ref > arguments; arguments.reserve(numArgs); for (unsigned j=0; j(fp); if (ce && ce->getOpcode()==Instruction::BitCast) { f = dyn_cast(ce->getOperand(0)); assert(f && "XXX unrecognized constant expression in call"); const FunctionType *fType = dyn_cast(cast(f->getType())->getElementType()); const FunctionType *ceType = dyn_cast(cast(ce->getType())->getElementType()); assert(fType && ceType && "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 = Expr::getWidthForLLVMType(fType->getParamType(i)); if (from != to) { // XXX need to check other param attrs ? if (cs.paramHasAttr(i+1, llvm::Attribute::SExt)) { arguments[i] = SExtExpr::create(arguments[i], to); } else { arguments[i] = ZExtExpr::create(arguments[i], to); } } } i++; } } else if (isa(fp)) { terminateStateOnExecError(state, "inline assembly is unsupported"); break; } } if (f) { 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 * 2, state).value; bindLocal(ki, state, result); break; } // Special instructions case Instruction::Select: { SelectInst *SI = cast(ki->inst); assert(SI->getCondition() == SI->getOperand(0) && "Wrong operand index!"); 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: case Instruction::Malloc: { AllocationInst *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::createCoerceToPointerType(count); size = MulExpr::create(size, count); } bool isLocal = i->getOpcode()==Instruction::Alloca; executeAlloc(state, size, isLocal, ki); break; } case Instruction::Free: { executeFree(state, eval(ki, 0, state).value); 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) { unsigned elementSize = it->second; ref index = eval(ki, it->first, state).value; base = AddExpr::create(base, MulExpr::create(Expr::createCoerceToPointerType(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, Expr::getWidthForLLVMType(ci->getType())); bindLocal(ki, state, result); break; } case Instruction::ZExt: { CastInst *ci = cast(i); ref result = ZExtExpr::create(eval(ki, 0, state).value, Expr::getWidthForLLVMType(ci->getType())); bindLocal(ki, state, result); break; } case Instruction::SExt: { CastInst *ci = cast(i); ref result = SExtExpr::create(eval(ki, 0, state).value, Expr::getWidthForLLVMType(ci->getType())); bindLocal(ki, state, result); break; } case Instruction::IntToPtr: { CastInst *ci = cast(i); Expr::Width pType = Expr::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 = Expr::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"); llvm::APFloat Res(left->getAPValue()); Res.add(APFloat(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"); llvm::APFloat Res(left->getAPValue()); Res.subtract(APFloat(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"); llvm::APFloat Res(left->getAPValue()); Res.multiply(APFloat(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"); llvm::APFloat Res(left->getAPValue()); Res.divide(APFloat(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"); llvm::APFloat Res(left->getAPValue()); Res.mod(APFloat(right->getAPValue()), APFloat::rmNearestTiesToEven); bindLocal(ki, state, ConstantExpr::alloc(Res.bitcastToAPInt())); break; } case Instruction::FPTrunc: { FPTruncInst *fi = cast(i); Expr::Width resultType = Expr::getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (arg->getWidth() > 64) return terminateStateOnExecError(state, "Unsupported FPTrunc operation"); uint64_t value = floats::trunc(arg->getZExtValue(), resultType, arg->getWidth()); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); break; } case Instruction::FPExt: { FPExtInst *fi = cast(i); Expr::Width resultType = Expr::getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (arg->getWidth() > 64) return terminateStateOnExecError(state, "Unsupported FPExt operation"); uint64_t value = floats::ext(arg->getZExtValue(), resultType, arg->getWidth()); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); break; } case Instruction::FPToUI: { FPToUIInst *fi = cast(i); Expr::Width resultType = Expr::getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (arg->getWidth() > 64) return terminateStateOnExecError(state, "Unsupported FPToUI operation"); uint64_t value = floats::toUnsignedInt(arg->getZExtValue(), resultType, arg->getWidth()); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); break; } case Instruction::FPToSI: { FPToSIInst *fi = cast(i); Expr::Width resultType = Expr::getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (arg->getWidth() > 64) return terminateStateOnExecError(state, "Unsupported FPToSI operation"); uint64_t value = floats::toSignedInt(arg->getZExtValue(), resultType, arg->getWidth()); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); break; } case Instruction::UIToFP: { UIToFPInst *fi = cast(i); Expr::Width resultType = Expr::getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (arg->getWidth() > 64) return terminateStateOnExecError(state, "Unsupported UIToFP operation"); uint64_t value = floats::UnsignedIntToFP(arg->getZExtValue(), resultType); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); break; } case Instruction::SIToFP: { SIToFPInst *fi = cast(i); Expr::Width resultType = Expr::getWidthForLLVMType(fi->getType()); ref arg = toConstant(state, eval(ki, 0, state).value, "floating point"); if (arg->getWidth() > 64) return terminateStateOnExecError(state, "Unsupported SIToFP operation"); uint64_t value = floats::SignedIntToFP(arg->getZExtValue(), resultType, arg->getWidth()); bindLocal(ki, state, ConstantExpr::alloc(value, resultType)); 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"); APFloat LHS(left->getAPValue()); APFloat RHS(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; } // Other instructions... // Unhandled case Instruction::ExtractElement: case Instruction::InsertElement: case Instruction::ShuffleVector: terminateStateOnError(state, "XXX vector instructions unhandled", "xxx.err"); break; default: terminateStateOnExecError(state, "illegal instruction"); break; } } void Executor::updateStates(ExecutionState *current) { if (searcher) { searcher->update(current, addedStates, removedStates); } states.insert(addedStates.begin(), addedStates.end()); addedStates.clear(); for (std::set::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(); } void Executor::bindInstructionConstants(KInstruction *KI) { GetElementPtrInst *gepi = dyn_cast(KI->inst); if (!gepi) return; KGEPInstruction *kgepi = static_cast(KI); ref constantOffset = ConstantExpr::alloc(0, Context::get().getPointerWidth()); unsigned index = 1; for (gep_type_iterator ii = gep_type_begin(gepi), ie = gep_type_end(gepi); ii != ie; ++ii) { if (const 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 *st = cast(*ii); unsigned elementSize = kmodule->targetData->getTypeStoreSize(st->getElementType()); Value *operand = ii.getOperand(); if (Constant *c = dyn_cast(operand)) { ref index = evalConstant(c)->ZExt(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::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::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) goto dump; 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) goto dump; } searcher = constructUserSearcher(*this); searcher->update(0, states, std::set()); while (!states.empty() && !haltExecution) { ExecutionState &state = searcher->selectState(); KInstruction *ki = state.pc; stepInstruction(state); executeInstruction(state, ki); processTimers(&state, MaxInstructionTime); if (MaxMemory) { if ((stats::instructions & 0xFFFF) == 0) { // We need to avoid calling GetMallocUsage() often because it // is O(elts on freelist). This is really bad since we start // to pummel the freelist once we hit the memory cap. unsigned mbs = sys::Process::GetTotalMemoryUsage() >> 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); if (MaxMemoryInhibit) klee_warning("killing %d states (over memory cap)", toKill); std::vector arr(states.begin(), states.end()); for (unsigned i=0,N=arr.size(); N && icoveredNew) idx = rand() % N; std::swap(arr[idx], arr[N-1]); terminateStateEarly(*arr[N-1], "memory limit"); } } atMemoryLimit = true; } else { atMemoryLimit = false; } } } updateStates(&state); } delete searcher; searcher = 0; dump: if (DumpStatesOnHalt && !states.empty()) { llvm::cerr << "KLEE: halting execution, dumping remaining states\n"; for (std::set::iterator it = states.begin(), ie = states.end(); it != ie; ++it) { ExecutionState &state = **it; stepInstruction(state); // keep stats rolling terminateStateEarly(state, "execution halting"); } updateStates(0); } } std::string Executor::getAddressInfo(ExecutionState &state, ref address) const{ std::ostringstream info; 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; info << "object at " << mo->address << " of size " << mo->size << "\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; info << "object at " << mo->address << " of size " << mo->size << "\n"; } } return info.str(); } void Executor::terminateState(ExecutionState &state) { if (replayOut && replayPosition!=replayOut->numObjects) { klee_warning_once(replayOut, "replay did not consume all objects in test input."); } interpreterHandler->incPathsExplored(); std::set::iterator it = addedStates.find(&state); if (it==addedStates.end()) { state.pc = state.prevPC; removedStates.insert(&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); } void Executor::terminateStateOnError(ExecutionState &state, const llvm::Twine &messaget, const char *suffix, const llvm::Twine &info) { std::string message = messaget.str(); static std::set< std::pair > emittedErrors; const InstructionInfo &ii = *state.prevPC->info; if (EmitAllErrors || emittedErrors.insert(std::make_pair(state.prevPC->inst, message)).second) { if (ii.file != "") { klee_message("ERROR: %s:%d: %s", ii.file.c_str(), ii.line, message.c_str()); } else { klee_message("ERROR: %s", message.c_str()); } if (!EmitAllErrors) klee_message("NOTE: now ignoring this error at this location"); std::ostringstream msg; msg << "Error: " << message << "\n"; if (ii.file != "") { msg << "File: " << ii.file << "\n"; msg << "Line: " << ii.line << "\n"; } msg << "Stack: \n"; unsigned idx = 0; const KInstruction *target = state.prevPC; for (ExecutionState::stack_ty::reverse_iterator it = state.stack.rbegin(), ie = state.stack.rend(); it != ie; ++it) { StackFrame &sf = *it; Function *f = sf.kf->function; const InstructionInfo &ii = *target->info; msg << "\t#" << idx++ << " " << std::setw(8) << std::setfill('0') << ii.assemblyLine << " in " << f->getNameStr() << " ("; // Yawn, we could go up and print varargs if we wanted to. unsigned index = 0; for (Function::arg_iterator ai = f->arg_begin(), ae = f->arg_end(); ai != ae; ++ai) { if (ai!=f->arg_begin()) msg << ", "; msg << ai->getNameStr(); // XXX should go through function ref value = sf.locals[sf.kf->getArgRegister(index++)].value; if (isa(value)) msg << "=" << value; } msg << ")"; if (ii.file != "") msg << " at " << ii.file << ":" << ii.line; msg << "\n"; target = sf.caller; } std::string info_str = info.str(); if (info_str != "") msg << "Info: \n" << info_str; interpreterHandler->processTestCase(state, msg.str().c_str(), suffix); } terminateState(state); } // 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())) { llvm::cerr << "KLEE:ERROR: Calling not-OK external function : " << function->getNameStr() << "\n"; terminateStateOnError(state, "externals disallowed", "user.err"); return; } // normal external function handling path uint64_t *args = (uint64_t*) alloca(sizeof(*args) * (arguments.size() + 1)); memset(args, 0, sizeof(*args) * (arguments.size() + 1)); unsigned i = 1; for (std::vector >::iterator ai = arguments.begin(), ae = arguments.end(); ai!=ae; ++ai, ++i) { if (AllowExternalSymCalls) { // don't bother checking uniqueness ref ce; bool success = solver->getValue(state, *ai, ce); assert(success && "FIXME: Unhandled solver failure"); (void) success; static_cast(ce.get())->toMemory((void*) &args[i]); } else { ref arg = toUnique(state, *ai); if (ConstantExpr *CE = dyn_cast(arg)) { // XXX kick toMemory functions from here CE->toMemory((void*) &args[i]); } else { terminateStateOnExecError(state, "external call with symbolic argument: " + function->getName()); return; } } } state.addressSpace.copyOutConcretes(); if (!SuppressExternalWarnings) { std::ostringstream os; os << "calling external: " << function->getNameStr() << "("; for (unsigned i=0; iexecuteCall(function, target->inst, args); if (!success) { terminateStateOnError(state, "failed external call: " + function->getName(), "external.err"); return; } if (!state.addressSpace.copyInConcretes()) { terminateStateOnError(state, "external modified read-only object", "external.err"); return; } const Type *resultType = target->inst->getType(); if (resultType != Type::VoidTy) { ref e = ConstantExpr::fromMemory((void*) args, Expr::getWidthForLLVMType(resultType)); bindLocal(target, state, e); } } /***/ ref Executor::replaceReadWithSymbolic(ExecutionState &state, ref e) { unsigned n = interpreterOpts.MakeConcreteSymbolic; if (!n || replayOut || replayPath) return e; // right now, we don't replace symbolics (is there any reason too?) 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 = new Array("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::cerr << "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)) { MemoryObject *mo = memory->allocate(CE->getZExtValue(), isLocal, false, state.prevPC->inst); 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(1<<31, Expr::Int32), size), true); if (hugeSize.first) { klee_message("NOTE: found huge malloc, returing 0"); bindLocal(target, *hugeSize.first, ConstantExpr::alloc(0, Context::get().getPointerWidth())); } if (hugeSize.second) { std::ostringstream info; ExprPPrinter::printOne(info, " size expr", size); info << " concretization : " << example << "\n"; info << " unbound example: " << tmp << "\n"; terminateStateOnError(*hugeSize.second, "concretized symbolic size", "model.err", 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.err", getAddressInfo(*it->second, address)); } else if (mo->isGlobal) { terminateStateOnError(*it->second, "free of global", "free.err", 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.err", 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() : Expr::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(stpTimeout); 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(stpTimeout); bool success = solver->mustBeTrue(state, mo->getBoundsCheckOffset(offset, bytes), inBounds); solver->setTimeout(0); if (!success) { state.pc = state.prevPC; terminateStateEarly(state, "query timed out"); return; } if (inBounds) { const ObjectState *os = op.second; if (isWrite) { if (os->readOnly) { terminateStateOnError(state, "memory error: object read only", "readonly.err"); } 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(stpTimeout); bool incomplete = state.addressSpace.resolve(state, solver, address, rl, 0, stpTimeout); 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.err"); } 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.err", getAddressInfo(*unbound, address)); } } } void Executor::executeMakeSymbolic(ExecutionState &state, const MemoryObject *mo) { // Create a new object state for the memory object (instead of a copy). if (!replayOut) { static unsigned id = 0; const Array *array = new Array("arr" + llvm::utostr(++id), 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.err"); 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.err"); 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 >= replayOut->numObjects) { terminateStateOnError(state, "replay count mismatch", "user.err"); } else { KTestObject *obj = &replayOut->objects[replayPosition++]; if (obj->numBytes != mo->size) { terminateStateOnError(state, "replay size mismatch", "user.err"); } 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) { argvMO = memory->allocate((argc+1+envc+1+1) * NumPtrBytes, false, true, f->begin()->begin()); 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) { arg = 0; } else { char *s = iallocate(len+1, false, true, state->pc->inst); ObjectState *os = bindObjectInState(*state, arg, false); for (j=0; jwrite8(j, s[j]); } if (arg) { argvOS->write(i * NumPtrBytes, arg->getBaseExpr()); } else { argvOS->write(i * NumPtrBytes, Expr::createPointer(0)); } } } 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(); globalObjects.clear(); globalAddresses.clear(); if (statsTracker) statsTracker->done(); if (theMMap) { munmap(theMMap, theMMapSize); theMMap = 0; } } 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, bool asCVC) { if (asCVC) { Query query(state.constraints, ConstantExpr::alloc(0, Expr::Bool)); char *log = solver->stpSolver->getConstraintLog(query); res = std::string(log); free(log); } else { std::ostringstream info; ExprPPrinter::printConstraints(info, state.constraints); res = info.str(); } } bool Executor::getSymbolicSolution(const ExecutionState &state, std::vector< std::pair > > &res) { solver->setTimeout(stpTimeout); ExecutionState tmp(state); if (!NoPreferCex) { 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; bool success = solver->mustBeTrue(tmp, Expr::createIsZero(*pi), mustBeTrue); if (!success) break; 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(std::cerr, 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); } } } } /// Interpreter *Interpreter::create(const InterpreterOptions &opts, InterpreterHandler *ih) { return new Executor(opts, ih); }