Skip to content

Commit

Permalink
Merge 54f6c5a into ca88a99
Browse files Browse the repository at this point in the history
  • Loading branch information
misonijnik authored Oct 16, 2023
2 parents ca88a99 + 54f6c5a commit 660481f
Show file tree
Hide file tree
Showing 8 changed files with 1,910 additions and 58 deletions.
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ SQLITE_VERSION="3400100"
## LLVM Required options
LLVM_VERSION=14
ENABLE_OPTIMIZED=1
ENABLE_DEBUG=1
ENABLE_DEBUG=0
DISABLE_ASSERTIONS=1
REQUIRES_RTTI=1
REQUIRES_RTTI=0

## Solvers Required options
# SOLVERS=STP
Expand Down
8 changes: 8 additions & 0 deletions include/klee/Module/CodeGraphInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class CodeGraphInfo {
functionDistanceList functionSortedBackwardDistance;

functionBranchesSet functionBranches;
functionBranchesSet functionConditionalBranches;
functionBranchesSet functionBlocks;

private:
void calculateDistance(KBlock *bb);
Expand All @@ -54,6 +56,8 @@ class CodeGraphInfo {
void calculateBackwardDistance(KFunction *kf);

void calculateFunctionBranches(KFunction *kf);
void calculateFunctionConditionalBranches(KFunction *kf);
void calculateFunctionBlocks(KFunction *kf);

public:
const std::unordered_map<KBlock *, unsigned int> &getDistance(KBlock *kb);
Expand All @@ -78,6 +82,10 @@ class CodeGraphInfo {

const std::map<KBlock *, std::set<unsigned>> &
getFunctionBranches(KFunction *kf);
const std::map<KBlock *, std::set<unsigned>> &
getFunctionConditionalBranches(KFunction *kf);
const std::map<KBlock *, std::set<unsigned>> &
getFunctionBlocks(KFunction *kf);
};

} // namespace klee
Expand Down
7 changes: 7 additions & 0 deletions lib/Core/Executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ bool allLeafsAreConstant(const ref<Expr> &expr) {
extern llvm::cl::opt<uint64_t> MaxConstantAllocationSize;
extern llvm::cl::opt<uint64_t> MaxSymbolicAllocationSize;
extern llvm::cl::opt<bool> UseSymbolicSizeAllocation;
extern llvm::cl::opt<TrackCoverageBy> TrackCoverage;

// XXX hack
extern "C" unsigned dumpStates, dumpPForest;
Expand Down Expand Up @@ -4373,6 +4374,7 @@ static std::string terminationTypeFileExtension(StateTerminationType type) {
};

void Executor::executeStep(ExecutionState &state) {
KFunction *initKF = state.initPC->parent->parent;
if (CoverOnTheFly && guidanceKind != GuidanceKind::ErrorGuidance &&
stats::instructions > DelayCoverOnTheFly && shouldWriteTest(state)) {
state.clearCoveredNew();
Expand Down Expand Up @@ -4407,6 +4409,11 @@ void Executor::executeStep(ExecutionState &state) {
// pressure
updateStates(nullptr);
}

if (targetCalculator && TrackCoverage != TrackCoverageBy::None &&
targetCalculator->isCovered(initKF)) {
haltExecution = HaltExecution::CovCheck;
}
}

void Executor::targetedRun(ExecutionState &initialState, KBlock *target,
Expand Down
163 changes: 109 additions & 54 deletions lib/Core/TargetCalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,19 @@ llvm::cl::opt<TargetCalculateBy> TargetCalculatorMode(
"Looks for the closest uncovered block by state transitions "
"history.")),
cl::init(TargetCalculateBy::Default), cl::cat(ExecCat));

} // namespace klee

llvm::cl::opt<TrackCoverageBy> TrackCoverage(
"track-coverage", cl::desc("Specifiy the track coverage mode."),
cl::values(clEnumValN(TrackCoverageBy::None, "none", "Not track coverage."),
clEnumValN(TrackCoverageBy::Blocks, "blocks",
"Track only covered block."),
clEnumValN(TrackCoverageBy::Branches, "branches",
"Track only covered conditional branches."),
clEnumValN(TrackCoverageBy::All, "all", "Track all.")),
cl::init(TrackCoverageBy::None), cl::cat(ExecCat));

void TargetCalculator::update(const ExecutionState &state) {
Function *initialFunction = state.getInitPCBlock()->getParent();

Expand All @@ -46,28 +57,34 @@ void TargetCalculator::update(const ExecutionState &state) {
}
if (state.prevPC == state.prevPC->parent->getLastInstruction() &&
!fullyCoveredFunctions.count(state.prevPC->parent->parent)) {
auto &fBranches = getCoverageTargets(state.prevPC->parent->parent);

if (!coveredFunctionsInBranches.count(state.prevPC->parent->parent)) {
unsigned index = 0;
if (!coveredBranches[state.prevPC->parent->parent].count(
state.prevPC->parent)) {
state.coverNew();
coveredBranches[state.prevPC->parent->parent][state.prevPC->parent];
}
for (auto succ : successors(state.getPrevPCBlock())) {
if (succ == state.getPCBlock()) {
if (!coveredBranches[state.prevPC->parent->parent]
[state.prevPC->parent]
.count(index)) {
state.coverNew();
coveredBranches[state.prevPC->parent->parent][state.prevPC->parent]
.insert(index);
if (fBranches.count(state.prevPC->parent) != 0) {
if (!coveredBranches[state.prevPC->parent->parent].count(
state.prevPC->parent)) {
state.coverNew();
coveredBranches[state.prevPC->parent->parent][state.prevPC->parent];
}
if (!fBranches.at(state.prevPC->parent).empty()) {
unsigned index = 0;
for (auto succ : successors(state.getPrevPCBlock())) {
if (succ == state.getPCBlock()) {
if (!coveredBranches[state.prevPC->parent->parent]
[state.prevPC->parent]
.count(index)) {
state.coverNew();
coveredBranches[state.prevPC->parent->parent]
[state.prevPC->parent]
.insert(index);
}
break;
}
++index;
}
break;
}
++index;
}
if (codeGraphInfo.getFunctionBranches(state.prevPC->parent->parent) ==
if (getCoverageTargets(state.prevPC->parent->parent) ==
coveredBranches[state.prevPC->parent->parent]) {
coveredFunctionsInBranches.insert(state.prevPC->parent->parent);
}
Expand All @@ -88,12 +105,15 @@ void TargetCalculator::update(const ExecutionState &state) {
KFunction *calledKFunction = state.prevPC->parent->parent->parent
->functionMap[calledFunction];
if (calledKFunction->numInstructions != 0 &&
coveredFunctionsInBranches.count(calledKFunction) == 0) {
coveredFunctionsInBranches.count(calledKFunction) == 0 &&
!getCoverageTargets(calledKFunction).empty()) {
covered = false;
break;
}
if (!fnsTaken.count(calledKFunction) &&
fullyCoveredFunctions.count(calledKFunction) == 0) {
fullyCoveredFunctions.count(calledKFunction) == 0 &&
calledKFunction->numInstructions != 0 &&
!getCoverageTargets(calledKFunction).empty()) {
fns.push_back(calledKFunction);
}
}
Expand Down Expand Up @@ -178,6 +198,22 @@ bool TargetCalculator::differenceIsEmpty(
return diff.empty();
}

const std::map<KBlock *, std::set<unsigned>> &
TargetCalculator::getCoverageTargets(KFunction *kf) {
switch (TrackCoverage) {
case TrackCoverageBy::Blocks:
return codeGraphInfo.getFunctionBlocks(kf);
case TrackCoverageBy::Branches:
return codeGraphInfo.getFunctionConditionalBranches(kf);
case TrackCoverageBy::None:
case TrackCoverageBy::All:
return codeGraphInfo.getFunctionBranches(kf);

default:
assert(0 && "not implemented");
}
}

bool TargetCalculator::uncoveredBlockPredicate(ExecutionState *state,
KBlock *kblock) {
Function *initialFunction = state->getInitPCBlock()->getParent();
Expand All @@ -186,20 +222,28 @@ bool TargetCalculator::uncoveredBlockPredicate(ExecutionState *state,
std::unordered_map<llvm::BasicBlock *, VisitedTransitions>
&transitionHistory = transitionsHistory[initialFunction];
bool result = false;
if (coveredBranches[kblock->parent].count(kblock) == 0) {
result = true;
} else {
auto &cb = coveredBranches[kblock->parent][kblock];
if (isa<KCallBlock>(kblock) &&
cast<KCallBlock>(kblock)->calledFunctions.size() == 1) {
auto calledFunction = *cast<KCallBlock>(kblock)->calledFunctions.begin();
KFunction *calledKFunction =
kblock->parent->parent->functionMap[calledFunction];
result = fullyCoveredFunctions.count(calledKFunction) == 0 &&
calledKFunction->numInstructions;

auto &fBranches = getCoverageTargets(kblock->parent);

if (fBranches.count(kblock) != 0 || isa<KCallBlock>(kblock)) {
if (coveredBranches[kblock->parent].count(kblock) == 0) {
result = true;
} else {
auto &cb = coveredBranches[kblock->parent][kblock];
if (isa<KCallBlock>(kblock) &&
cast<KCallBlock>(kblock)->calledFunctions.size() == 1) {
auto calledFunction =
*cast<KCallBlock>(kblock)->calledFunctions.begin();
KFunction *calledKFunction =
kblock->parent->parent->functionMap[calledFunction];
result = fullyCoveredFunctions.count(calledKFunction) == 0 &&
calledKFunction->numInstructions;
}
if (fBranches.at(kblock) != cb) {
result |=
kblock->basicBlock->getTerminator()->getNumSuccessors() > cb.size();
}
}
result |=
kblock->basicBlock->getTerminator()->getNumSuccessors() > cb.size();
}

switch (TargetCalculatorMode) {
Expand Down Expand Up @@ -246,29 +290,36 @@ TargetHashSet TargetCalculator::calculate(ExecutionState &state) {
if (!blocks.empty()) {
TargetHashSet targets;
for (auto block : blocks) {
if (coveredBranches[block->parent].count(block) == 0) {
targets.insert(ReachBlockTarget::create(block, false));
} else {
auto &cb = coveredBranches[block->parent][block];
bool notCoveredFunction = false;
if (isa<KCallBlock>(block) &&
cast<KCallBlock>(block)->calledFunctions.size() == 1) {
auto calledFunction =
*cast<KCallBlock>(block)->calledFunctions.begin();
KFunction *calledKFunction =
block->parent->parent->functionMap[calledFunction];
notCoveredFunction =
fullyCoveredFunctions.count(calledKFunction) == 0 &&
calledKFunction->numInstructions;
}
if (notCoveredFunction) {
targets.insert(ReachBlockTarget::create(block, true));
auto &fBranches = getCoverageTargets(block->parent);

if (fBranches.count(block) != 0 || isa<KCallBlock>(block)) {
if (coveredBranches[block->parent].count(block) == 0) {
targets.insert(ReachBlockTarget::create(block, false));
} else {
for (unsigned index = 0;
index < block->basicBlock->getTerminator()->getNumSuccessors();
++index) {
if (!cb.count(index))
targets.insert(CoverBranchTarget::create(block, index));
auto &cb = coveredBranches[block->parent][block];
bool notCoveredFunction = false;
if (isa<KCallBlock>(block) &&
cast<KCallBlock>(block)->calledFunctions.size() == 1) {
auto calledFunction =
*cast<KCallBlock>(block)->calledFunctions.begin();
KFunction *calledKFunction =
block->parent->parent->functionMap[calledFunction];
notCoveredFunction =
fullyCoveredFunctions.count(calledKFunction) == 0 &&
calledKFunction->numInstructions;
}
if (notCoveredFunction) {
targets.insert(ReachBlockTarget::create(block, true));
} else {
if (fBranches.at(block) != cb) {
for (unsigned index = 0;
index <
block->basicBlock->getTerminator()->getNumSuccessors();
++index) {
if (!cb.count(index))
targets.insert(CoverBranchTarget::create(block, index));
}
}
}
}
}
Expand All @@ -289,3 +340,7 @@ TargetHashSet TargetCalculator::calculate(ExecutionState &state) {

return {};
}

bool TargetCalculator::isCovered(KFunction *kf) const {
return fullyCoveredFunctions.count(kf) != 0;
}
9 changes: 8 additions & 1 deletion lib/Core/TargetCalculator.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class CodeGraphInfo;
class ExecutionState;
struct TransitionHash;

enum TargetCalculateBy { Default, Blocks, Transitions };
enum class TargetCalculateBy { Default, Blocks, Transitions };

enum class TrackCoverageBy { None, Blocks, Branches, All };

typedef std::pair<llvm::BasicBlock *, llvm::BasicBlock *> Transition;
typedef std::pair<llvm::BasicBlock *, unsigned> Branch;
Expand Down Expand Up @@ -77,6 +79,8 @@ class TargetCalculator {

TargetHashSet calculate(ExecutionState &state);

bool isCovered(KFunction *kf) const;

private:
CodeGraphInfo &codeGraphInfo;
BlocksHistory blocksHistory;
Expand All @@ -96,6 +100,9 @@ class TargetCalculator {
const std::unordered_map<llvm::BasicBlock *, VisitedTransitions> &history,
KBlock *target);

const std::map<KBlock *, std::set<unsigned>> &
getCoverageTargets(KFunction *kf);

bool uncoveredBlockPredicate(ExecutionState *state, KBlock *kblock);
};
} // namespace klee
Expand Down
34 changes: 34 additions & 0 deletions lib/Module/CodeGraphInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,26 @@ void CodeGraphInfo::calculateFunctionBranches(KFunction *kf) {
}
}
}
void CodeGraphInfo::calculateFunctionConditionalBranches(KFunction *kf) {
std::map<KBlock *, std::set<unsigned>> &fbranches =
functionConditionalBranches[kf];
for (auto &kb : kf->blocks) {
if (kb->basicBlock->getTerminator()->getNumSuccessors() > 1) {
fbranches[kb.get()];
for (unsigned branch = 0;
branch < kb->basicBlock->getTerminator()->getNumSuccessors();
++branch) {
fbranches[kb.get()].insert(branch);
}
}
}
}
void CodeGraphInfo::calculateFunctionBlocks(KFunction *kf) {
std::map<KBlock *, std::set<unsigned>> &fbranches = functionBlocks[kf];
for (auto &kb : kf->blocks) {
fbranches[kb.get()];
}
}

const std::unordered_map<KBlock *, unsigned> &
CodeGraphInfo::getDistance(KBlock *kb) {
Expand Down Expand Up @@ -219,3 +239,17 @@ CodeGraphInfo::getFunctionBranches(KFunction *kf) {
calculateFunctionBranches(kf);
return functionBranches.at(kf);
}

const std::map<KBlock *, std::set<unsigned>> &
CodeGraphInfo::getFunctionConditionalBranches(KFunction *kf) {
if (functionConditionalBranches.count(kf) == 0)
calculateFunctionConditionalBranches(kf);
return functionConditionalBranches.at(kf);
}

const std::map<KBlock *, std::set<unsigned>> &
CodeGraphInfo::getFunctionBlocks(KFunction *kf) {
if (functionBlocks.count(kf) == 0)
calculateFunctionBlocks(kf);
return functionBlocks.at(kf);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// REQUIRES: geq-llvm-14.0
// RUN: %clang %s -emit-llvm %O0opt -g -c -o %t1.bc
// RUN: rm -rf %t.klee-out
// RUN: %klee --output-dir=%t.klee-out --delete-dead-loops=false --emit-all-errors --mock-all-externals --use-forked-solver=false --optimize --skip-not-lazy-initialized --output-source=false --output-stats=true --output-istats=true -istats-write-interval=3s --use-sym-size-alloc=true --cex-cache-validity-cores --symbolic-allocation-threshold=8192 --cover-on-the-fly=false --delay-cover-on-the-fly=400000 --only-output-states-covering-new --dump-states-on-halt=true --search=dfs --search=random-state --use-iterative-deepening-search=max-cycles --max-cycles=4 %t1.bc
// RUN: %klee --output-dir=%t.klee-out --track-coverage=branches --delete-dead-loops=false --emit-all-errors --mock-all-externals --use-forked-solver=false --optimize --skip-not-lazy-initialized --output-source=false --output-stats=true --output-istats=true -istats-write-interval=3s --use-sym-size-alloc=true --cex-cache-validity-cores --symbolic-allocation-threshold=8192 --cover-on-the-fly=false --delay-cover-on-the-fly=400000 --only-output-states-covering-new --dump-states-on-halt=true --search=dfs --search=random-state --use-iterative-deepening-search=max-cycles --max-cycles=4 %t1.bc
// RUN: %klee-stats --print-columns 'BCov(%)' --table-format=csv %t.klee-out > %t.stats
// RUN: FileCheck -input-file=%t.stats %s

Expand Down
Loading

0 comments on commit 660481f

Please sign in to comment.