diff options
author | Nguyễn Gia Phong <cnx@loang.net> | 2023-11-10 12:23:37 +0900 |
---|---|---|
committer | Nguyễn Gia Phong <cnx@loang.net> | 2024-03-05 17:53:27 +0900 |
commit | 25ea1e3bbb2ff2abf57dd348af62837425dba8a7 (patch) | |
tree | 97b02b37a91353c01fedd2c721619c1f78814725 | |
parent | ae1f642b1f04bce817fa66b92515da9459f1a4d0 (diff) | |
download | klee-25ea1e3bbb2ff2abf57dd348af62837425dba8a7.tar.gz |
Implement detection of implicit return via pointer
-rw-r--r-- | lib/Core/Executor.cpp | 78 | ||||
-rw-r--r-- | lib/Core/Executor.h | 11 |
2 files changed, 67 insertions, 22 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 4763fdb5..d26e5d04 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -2125,11 +2125,17 @@ Function *Executor::getTargetFunction(Value *calledVal) { } } +bool patchLocal(llvm::Function *fn) { + if (PatchedFile.empty() + || fn->getSubprogram()->getFilename() != PatchedFile) + return false; + auto const name = fn->getName(); + return name != "__choose" && name.substr(0, 7) != "__klee_"; +} + void Executor::registerOutput(ExecutionState &state, Function *fn, std::string var, Expr::Width bits, ref<Expr> val) { - if (state.patchLocs == 0 || fn->getName() == "__choose" - || (!PatchedFile.empty() - && fn->getSubprogram()->getFilename() != PatchedFile)) + if (state.patchLocs == 0 || !patchLocal(fn)) return; size_t bytes = bits == Expr::Bool ? 1u : bits >> 3; auto const inst = state.prevPC->inst; @@ -2168,6 +2174,33 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { assert(!caller && "caller set on initial stack frame"); terminateStateOnExit(state); } else { + std::vector<ref<Expr>> arguments; + auto const fp = cast<CallBase>(*caller).getCalledOperand(); + if (auto const fn = getTargetFunction(fp)) { + auto const kf = kmodule->functionMap[fn]; + auto const ft = fn->getFunctionType(); + auto k = fn->arg_size(); + while (k--) { + auto const t = ft->getParamType(k); + if (!t->isPointerTy()) + continue; + auto const addr = getArgumentCell(state, kf, k).value; + // FIXME: changed to getPointerElementType in LLVM 14 + // and removed (!!!) in favor of opaque pointers in LLVM 15 + auto const pt = cast<PointerType>(t)->getElementType(); + if (pt->isFunctionTy() || !patchLocal(fn)) + continue; + auto const size = getWidthForLLVMType(pt); + auto const& val = executeMemoryOperation(state, false, addr, + 0, nullptr, size); + if (val.isNull()) + klee_warning("failed to make argument %s:%s#%zu symbolic", + fn->getSubprogram()->getFilename().data(), + fn->getName().data(), k); + else + registerOutput(state, fn, "parg" + llvm::utostr(k), size, val); + } + } state.popFrame(); if (statsTracker) @@ -4635,13 +4668,18 @@ void Executor::resolveExact(ExecutionState &state, } } -void Executor::executeMemoryOperation(ExecutionState &state, - bool isWrite, - ref<Expr> address, - ref<Expr> value /* undef if read */, - KInstruction *target /* undef if write */) { - Expr::Width type = (isWrite ? value->getWidth() : - getWidthForLLVMType(target->inst->getType())); +ref<Expr> Executor::executeMemoryOperation(ExecutionState &state, + bool isWrite, + ref<Expr> address, + ref<Expr> value /* undef if read */, + KInstruction *target, + Expr::Width type) { + if (isWrite) + type = value->getWidth(); + else if (target) + type = getWidthForLLVMType(target->inst->getType()); + else + assert(type != Expr::InvalidWidth); unsigned bytes = Expr::getMinBytesForWidth(type); if (SimplifySymIndices) { @@ -4711,7 +4749,7 @@ void Executor::executeMemoryOperation(ExecutionState &state, if (!success) { state.pc = state.prevPC; terminateStateOnSolverError(state, "Query timed out (bounds check)."); - return; + return {}; } if (inBounds) { @@ -4729,11 +4767,13 @@ void Executor::executeMemoryOperation(ExecutionState &state, if (interpreterOpts.MakeConcreteSymbolic) result = replaceReadWithSymbolic(state, result); - - bindLocal(target, state, result); + if (target) + bindLocal(target, state, result); + else + return result; } - return; + return {}; } } } @@ -4776,7 +4816,10 @@ void Executor::executeMemoryOperation(ExecutionState &state, } } else { ref<Expr> result = os->read(mo->getOffsetExpr(address), type); - bindLocal(target, *bound, result); + if (target) + bindLocal(target, *bound, result); + else + return result; } } @@ -4789,6 +4832,8 @@ void Executor::executeMemoryOperation(ExecutionState &state, if (unbound) { if (incomplete) { terminateStateOnSolverError(*unbound, "Query timed out (resolve)."); + } else if (!isWrite && !target) { + return {}; } else { if (auto CE = dyn_cast<ConstantExpr>(address)) { std::uintptr_t ptrval = CE->getZExtValue(); @@ -4797,7 +4842,6 @@ void Executor::executeMemoryOperation(ExecutionState &state, terminateStateOnProgramError( *unbound, "memory error: null page access", StateTerminationType::Ptr, getAddressInfo(*unbound, address)); - return; } else if (MemoryManager::isDeterministic) { using kdalloc::LocationInfo; auto li = unbound->heapAllocator.locationInfo(ptr, bytes); @@ -4811,7 +4855,6 @@ void Executor::executeMemoryOperation(ExecutionState &state, terminateStateOnProgramError( *unbound, "memory error: use after free", StateTerminationType::Ptr, getAddressInfo(*unbound, address)); - return; } } } @@ -4821,6 +4864,7 @@ void Executor::executeMemoryOperation(ExecutionState &state, StateTerminationType::Ptr, getAddressInfo(*unbound, address)); } } + return {}; } void Executor::executeMakeSymbolic(ExecutionState &state, diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index a179c66d..870e5801 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -354,11 +354,12 @@ private: // do address resolution / object binding / out of bounds checking // and perform the operation - void executeMemoryOperation(ExecutionState &state, - bool isWrite, - ref<Expr> address, - ref<Expr> value /* undef if read */, - KInstruction *target /* undef if write */); + ref<Expr> executeMemoryOperation(ExecutionState &state, + bool isWrite, + ref<Expr> address, + ref<Expr> value /* undef if read */, + KInstruction *target, + Expr::Width type = Expr::InvalidWidth); void executeMakeSymbolic(ExecutionState &state, const MemoryObject *mo, const std::string &name); |