diff options
author | Nguyễn Gia Phong <cnx@loang.net> | 2023-10-29 18:23:14 +0900 |
---|---|---|
committer | Nguyễn Gia Phong <cnx@loang.net> | 2024-03-05 17:46:16 +0900 |
commit | ae1f642b1f04bce817fa66b92515da9459f1a4d0 (patch) | |
tree | c2c87047607579dbc0a741db5267327192e4acbd | |
parent | be10b1d4179db60fc1295be58626c3467c744efd (diff) | |
download | klee-ae1f642b1f04bce817fa66b92515da9459f1a4d0.tar.gz |
Implement return value detection
Values returned after reaching patch location from functions in the specified source file are now automatically accounted for differential test generation.
-rw-r--r-- | lib/Core/Executor.cpp | 32 | ||||
-rw-r--r-- | lib/Core/Executor.h | 3 |
2 files changed, 35 insertions, 0 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 73dc21fa..4763fdb5 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -62,6 +62,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" @@ -135,6 +136,10 @@ cl::opt<bool> SingleObjectResolution( cl::desc("Try to resolve memory reads/writes to single objects " "when offsets are symbolic (default=false)"), cl::init(false), cl::cat(MiscCat)); + +cl::opt<std::string> PatchedFile( + "patched-file", + cl::desc("Relative path to patched file")); } // namespace klee namespace { @@ -2120,6 +2125,30 @@ Function *Executor::getTargetFunction(Value *calledVal) { } } +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)) + return; + size_t bytes = bits == Expr::Bool ? 1u : bits >> 3; + auto const inst = state.prevPC->inst; + auto const mo = this->memory->allocate(bytes, true, false, + &state, inst, bytes); + std::string baseName = "out!" + fn->getName().str() + "!" + var + "!"; + std::string name; + unsigned id = 0; + do + name = baseName + llvm::utostr(id++); + while (!state.arrayNames.insert(name).second); + this->executeMakeSymbolic(state, mo, name); + // Cached symbolic array + auto const outArray = this->arrayCache.CreateArray(name, bytes); + auto const outVal = Expr::createTempRead(outArray, bits); + auto const eq = EqExpr::create(outVal, val); + this->addConstraint(state, eq); +} + void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { Instruction *i = ki->inst; switch (i->getOpcode()) { @@ -2206,6 +2235,9 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { } } + auto const fp = cast<CallBase>(*caller).getCalledOperand(); + if (auto const fn = this->getTargetFunction(fp)) + registerOutput(state, fn, "ret", to, result); bindLocal(kcaller, state, result); } } else { diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index 8b2a609c..a179c66d 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -250,6 +250,9 @@ private: ref<ConstantExpr> getEhTypeidFor(ref<Expr> type_info); llvm::Function* getTargetFunction(llvm::Value *calledVal); + + void registerOutput(ExecutionState &state, llvm::Function *fn, + std::string var, Expr::Width size, ref<Expr> val); void executeInstruction(ExecutionState &state, KInstruction *ki); |