Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider function coverage for blocks with calls #121

Merged
merged 4 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/klee/ADT/Ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,18 @@ inline std::stringstream &operator<<(std::stringstream &os, const ref<T> &e) {
return os;
}

template <class T> class box {
friend class ref<box<T>>;

private:
/// @brief Required by klee::ref-managed objects
class ReferenceCounter _refCount;

public:
box(T value_) : value(value_) {}
ReferenceCounter count() { return _refCount; }
T value;
};
} // end namespace klee

namespace llvm {
Expand Down
3 changes: 2 additions & 1 deletion include/klee/Core/TerminationTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ enum class StateTerminationClass : std::uint8_t {
TTYPE(OutOfMemory, 12U, "early") \
TTYPE(OutOfStackMemory, 13U, "early") \
TTYPE(MaxCycles, 14U, "early") \
TTMARK(EARLY, 14U) \
TTYPE(CoverOnTheFly, 15U, "early") \
TTMARK(EARLY, 15U) \
TTYPE(Solver, 20U, "solver.err") \
TTMARK(SOLVERERR, 20U) \
TTYPE(Abort, 30U, "abort.err") \
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- CodeGraphDistance.h -------------------------------------*- C++ -*-===//
//===-- CodeGraphInfo.h -----------------------------------------*- C++ -*-===//
//
// The KLEE Symbolic Virtual Machine
//
Expand All @@ -16,7 +16,7 @@

namespace klee {

class CodeGraphDistance {
class CodeGraphInfo {

using blockDistanceMap =
std::unordered_map<KBlock *, std::unordered_map<KBlock *, unsigned>>;
Expand All @@ -30,6 +30,9 @@ class CodeGraphDistance {
std::unordered_map<KFunction *,
std::vector<std::pair<KFunction *, unsigned>>>;

using functionBranchesSet =
std::unordered_map<KFunction *, std::map<KBlock *, std::set<unsigned>>>;

private:
blockDistanceMap blockDistance;
blockDistanceMap blockBackwardDistance;
Expand All @@ -41,13 +44,17 @@ class CodeGraphDistance {
functionDistanceList functionSortedDistance;
functionDistanceList functionSortedBackwardDistance;

functionBranchesSet functionBranches;

private:
void calculateDistance(KBlock *bb);
void calculateBackwardDistance(KBlock *bb);

void calculateDistance(KFunction *kf);
void calculateBackwardDistance(KFunction *kf);

void calculateFunctionBranches(KFunction *kf);

public:
const std::unordered_map<KBlock *, unsigned int> &getDistance(KBlock *kb);
const std::unordered_map<KBlock *, unsigned int> &
Expand All @@ -68,6 +75,9 @@ class CodeGraphDistance {

void getNearestPredicateSatisfying(KBlock *from, KBlockPredicate predicate,
std::set<KBlock *> &result);

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

} // namespace klee
Expand Down
7 changes: 7 additions & 0 deletions include/klee/Module/KModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ struct KFunction : public KCallable {
}
};

struct KBlockCompare {
bool operator()(const KBlock *a, const KBlock *b) const {
return a->parent->id < b->parent->id ||
(a->parent->id == b->parent->id && a->id < b->id);
}
};

class KConstant {
public:
/// Actual LLVM constant this represents.
Expand Down
12 changes: 6 additions & 6 deletions lib/Core/DistanceCalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include "DistanceCalculator.h"
#include "ExecutionState.h"
#include "klee/Module/CodeGraphDistance.h"
#include "klee/Module/CodeGraphInfo.h"
#include "klee/Module/KInstruction.h"
#include "klee/Module/Target.h"

Expand Down Expand Up @@ -67,7 +67,7 @@ DistanceResult DistanceCalculator::getDistance(KBlock *kb, TargetKind kind,
DistanceResult DistanceCalculator::computeDistance(KBlock *kb, TargetKind kind,
KBlock *target) const {
const auto &distanceToTargetFunction =
codeGraphDistance.getBackwardDistance(target->parent);
codeGraphInfo.getBackwardDistance(target->parent);
weight_type weight = 0;
WeightResult res = Miss;
bool isInsideFunction = true;
Expand Down Expand Up @@ -99,7 +99,7 @@ DistanceResult DistanceCalculator::getDistance(

KBlock *kb = pc->parent;
const auto &distanceToTargetFunction =
codeGraphDistance.getBackwardDistance(target->parent);
codeGraphInfo.getBackwardDistance(target->parent);
unsigned int minCallWeight = UINT_MAX, minSfNum = UINT_MAX, sfNum = 0;
auto sfi = frames.rbegin(), sfe = frames.rend();
bool strictlyAfterKB =
Expand Down Expand Up @@ -145,7 +145,7 @@ bool DistanceCalculator::distanceInCallGraph(
KBlock *target, bool strictlyAfterKB) const {
distance = UINT_MAX;
const std::unordered_map<KBlock *, unsigned> &dist =
codeGraphDistance.getDistance(origKB);
codeGraphInfo.getDistance(origKB);
KBlock *targetBB = target;
KFunction *targetF = targetBB->parent;

Expand Down Expand Up @@ -176,7 +176,7 @@ bool DistanceCalculator::distanceInCallGraph(
KBlock *target) const {
distance = UINT_MAX;
const std::unordered_map<KBlock *, unsigned> &dist =
codeGraphDistance.getDistance(kb);
codeGraphInfo.getDistance(kb);

for (auto &kCallBlock : kf->kCallBlocks) {
if (dist.count(kCallBlock) == 0)
Expand All @@ -199,7 +199,7 @@ DistanceCalculator::tryGetLocalWeight(KBlock *kb, weight_type &weight,
KFunction *currentKF = kb->parent;
KBlock *currentKB = kb;
const std::unordered_map<KBlock *, unsigned> &dist =
codeGraphDistance.getDistance(currentKB);
codeGraphInfo.getDistance(currentKB);
weight = UINT_MAX;
for (auto &end : localTargets) {
if (dist.count(end) > 0) {
Expand Down
8 changes: 4 additions & 4 deletions lib/Core/DistanceCalculator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class BasicBlock;
} // namespace llvm

namespace klee {
class CodeGraphDistance;
class CodeGraphInfo;
class Target;

enum WeightResult : std::uint8_t {
Expand Down Expand Up @@ -45,8 +45,8 @@ struct DistanceResult {

class DistanceCalculator {
public:
explicit DistanceCalculator(CodeGraphDistance &codeGraphDistance_)
: codeGraphDistance(codeGraphDistance_) {}
explicit DistanceCalculator(CodeGraphInfo &codeGraphInfo_)
: codeGraphInfo(codeGraphInfo_) {}

DistanceResult getDistance(const ExecutionState &es, KBlock *target);

Expand Down Expand Up @@ -97,7 +97,7 @@ class DistanceCalculator {

using StatesSet = std::unordered_set<ExecutionState *>;

CodeGraphDistance &codeGraphDistance;
CodeGraphInfo &codeGraphInfo;
TargetToSpeculativeStateToDistanceResultMap distanceResultCache;
StatesSet localStates;

Expand Down
20 changes: 11 additions & 9 deletions lib/Core/ExecutionState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ ExecutionState::ExecutionState()
: initPC(nullptr), pc(nullptr), prevPC(nullptr), incomingBBIndex(-1),
depth(0), ptreeNode(nullptr), steppedInstructions(0),
steppedMemoryInstructions(0), instsSinceCovNew(0),
roundingMode(llvm::APFloat::rmNearestTiesToEven), coveredNew(false),
forkDisabled(false), prevHistory_(TargetsHistory::create()),
roundingMode(llvm::APFloat::rmNearestTiesToEven),
coveredNew(new box<bool>(false)), forkDisabled(false),
prevHistory_(TargetsHistory::create()),
history_(TargetsHistory::create()) {
setID();
}
Expand All @@ -138,8 +139,9 @@ ExecutionState::ExecutionState(KFunction *kf)
: initPC(kf->instructions), pc(initPC), prevPC(pc), incomingBBIndex(-1),
depth(0), ptreeNode(nullptr), steppedInstructions(0),
steppedMemoryInstructions(0), instsSinceCovNew(0),
roundingMode(llvm::APFloat::rmNearestTiesToEven), coveredNew(false),
forkDisabled(false), prevHistory_(TargetsHistory::create()),
roundingMode(llvm::APFloat::rmNearestTiesToEven),
coveredNew(new box<bool>(false)), forkDisabled(false),
prevHistory_(TargetsHistory::create()),
history_(TargetsHistory::create()) {
pushFrame(nullptr, kf);
setID();
Expand All @@ -149,8 +151,9 @@ ExecutionState::ExecutionState(KFunction *kf, KBlock *kb)
: initPC(kb->instructions), pc(initPC), prevPC(pc), incomingBBIndex(-1),
depth(0), ptreeNode(nullptr), steppedInstructions(0),
steppedMemoryInstructions(0), instsSinceCovNew(0),
roundingMode(llvm::APFloat::rmNearestTiesToEven), coveredNew(false),
forkDisabled(false), prevHistory_(TargetsHistory::create()),
roundingMode(llvm::APFloat::rmNearestTiesToEven),
coveredNew(new box<bool>(false)), forkDisabled(false),
prevHistory_(TargetsHistory::create()),
history_(TargetsHistory::create()) {
pushFrame(nullptr, kf);
setID();
Expand Down Expand Up @@ -189,7 +192,6 @@ ExecutionState *ExecutionState::branch() {

auto *falseState = new ExecutionState(*this);
falseState->setID();
falseState->coveredNew = false;
falseState->coveredLines.clear();

return falseState;
Expand Down Expand Up @@ -471,7 +473,7 @@ void ExecutionState::increaseLevel() {
if (prevPC->inst->isTerminator() && kmodule->inMainModule(*kf->function)) {
auto srcLevel = stack.infoStack().back().multilevel[srcbb].second;
stack.infoStack().back().multilevel.replace({srcbb, srcLevel + 1});
level.insert(srcbb);
level.insert(prevPC->parent);
}
if (srcbb != dstbb) {
transitionLevel.insert(std::make_pair(srcbb, dstbb));
Expand All @@ -483,7 +485,7 @@ bool ExecutionState::isGEPExpr(ref<Expr> expr) const {
}

bool ExecutionState::visited(KBlock *block) const {
return level.count(block->basicBlock) != 0;
return level.count(block) != 0;
}

bool ExecutionState::reachedTarget(ref<ReachBlockTarget> target) const {
Expand Down
4 changes: 2 additions & 2 deletions lib/Core/ExecutionState.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ class ExecutionState {
std::uint32_t depth = 0;

/// @brief Exploration level, i.e., number of times KLEE cycled for this state
std::unordered_set<llvm::BasicBlock *> level;
std::set<KBlock *, KBlockCompare> level;
std::unordered_set<Transition, TransitionHash> transitionLevel;

/// @brief Address space used by this state (e.g. Global and Heap)
Expand Down Expand Up @@ -369,7 +369,7 @@ class ExecutionState {
std::uint32_t id = 0;

/// @brief Whether a new instruction was covered in this state
bool coveredNew = false;
mutable ref<box<bool>> coveredNew;

/// @brief Disables forking for this state. Set by user code
bool forkDisabled = false;
Expand Down
71 changes: 47 additions & 24 deletions lib/Core/Executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
#include "klee/Expr/IndependentSet.h"
#include "klee/Expr/Symcrete.h"
#include "klee/Module/Cell.h"
#include "klee/Module/CodeGraphDistance.h"
#include "klee/Module/CodeGraphInfo.h"
#include "klee/Module/InstructionInfoTable.h"
#include "klee/Module/KCallable.h"
#include "klee/Module/KInstruction.h"
Expand Down Expand Up @@ -239,6 +239,18 @@ cl::opt<bool> EmitAllErrors(
"(default=false, i.e. one per (error,instruction) pair)"),
cl::cat(TestGenCat));

cl::opt<bool> CoverOnTheFly(
"cover-on-the-fly", cl::init(false),
cl::desc("Generate tests cases for each new covered block or branch "
"(default=false, i.e. one per (error,instruction) pair)"),
cl::cat(TestGenCat));

cl::opt<unsigned> DelayCoverOnTheFly(
"delay-cover-on-the-fly", cl::init(10000),
cl::desc("Start on the fly tests generation after this many instructions "
"(default=10000)"),
cl::cat(TestGenCat));

/* Constraint solving options */

cl::opt<unsigned> MaxSymArraySize(
Expand Down Expand Up @@ -455,13 +467,13 @@ Executor::Executor(LLVMContext &ctx, const InterpreterOptions &opts,
externalDispatcher(new ExternalDispatcher(ctx)), statsTracker(0),
pathWriter(0), symPathWriter(0),
specialFunctionHandler(0), timers{time::Span(TimerInterval)},
guidanceKind(opts.Guidance), codeGraphDistance(new CodeGraphDistance()),
distanceCalculator(new DistanceCalculator(*codeGraphDistance)),
targetCalculator(new TargetCalculator(*codeGraphDistance)),
guidanceKind(opts.Guidance), codeGraphInfo(new CodeGraphInfo()),
distanceCalculator(new DistanceCalculator(*codeGraphInfo)),
targetCalculator(new TargetCalculator(*codeGraphInfo)),
targetManager(new TargetManager(guidanceKind, *distanceCalculator,
*targetCalculator)),
targetedExecutionManager(
new TargetedExecutionManager(*codeGraphDistance, *targetManager)),
new TargetedExecutionManager(*codeGraphInfo, *targetManager)),
replayKTest(0), replayPath(0), usingSeeds(0), atMemoryLimit(false),
inhibitForking(false), haltExecution(HaltExecution::NotHalt),
ivcEnabled(false), debugLogBuffer(debugBufferString) {
Expand Down Expand Up @@ -4053,7 +4065,7 @@ bool Executor::checkMemoryUsage() {
unsigned idx = theRNG.getInt32() % N;
// Make two pulls to try and not hit a state that
// covered new code.
if (arr[idx]->coveredNew)
if (arr[idx]->coveredNew->value)
idx = theRNG.getInt32() % N;

std::swap(arr[idx], arr[N - 1]);
Expand Down Expand Up @@ -4325,8 +4337,36 @@ void Executor::initializeTypeManager() {
typeSystemManager->initModule();
}

static bool shouldWriteTest(const ExecutionState &state) {
bool coveredNew = state.coveredNew->value;
state.coveredNew->value = false;
return !OnlyOutputStatesCoveringNew || coveredNew;
}

static std::string terminationTypeFileExtension(StateTerminationType type) {
std::string ret;
#undef TTYPE
#undef TTMARK
#define TTYPE(N, I, S) \
case StateTerminationType::N: \
ret = (S); \
break;
#define TTMARK(N, I)
switch (type) { TERMINATION_TYPES }
return ret;
};

void Executor::executeStep(ExecutionState &state) {
KInstruction *prevKI = state.prevPC;

if (CoverOnTheFly && guidanceKind != GuidanceKind::ErrorGuidance &&
stats::instructions > DelayCoverOnTheFly && shouldWriteTest(state)) {
interpreterHandler->processTestCase(
state, nullptr,
terminationTypeFileExtension(StateTerminationType::CoverOnTheFly)
.c_str());
}

if (targetManager->isTargeted(state) && state.targets().empty()) {
terminateStateEarlyAlgorithm(state, "State missed all it's targets.",
StateTerminationType::MissedAllTargets);
Expand Down Expand Up @@ -4511,23 +4551,6 @@ void Executor::terminateState(ExecutionState &state,
removedStates.push_back(&state);
}

static bool shouldWriteTest(const ExecutionState &state) {
return !OnlyOutputStatesCoveringNew || state.coveredNew;
}

static std::string terminationTypeFileExtension(StateTerminationType type) {
std::string ret;
#undef TTYPE
#undef TTMARK
#define TTYPE(N, I, S) \
case StateTerminationType::N: \
ret = (S); \
break;
#define TTMARK(N, I)
switch (type) { TERMINATION_TYPES }
return ret;
};

void Executor::terminateStateOnExit(ExecutionState &state) {
auto terminationType = StateTerminationType::Exit;
++stats::terminationExit;
Expand Down Expand Up @@ -7273,7 +7296,7 @@ void Executor::dumpStates() {
*os << "{";
*os << "'depth' : " << es->depth << ", ";
*os << "'queryCost' : " << es->queryMetaData.queryCost << ", ";
*os << "'coveredNew' : " << es->coveredNew << ", ";
*os << "'coveredNew' : " << es->coveredNew->value << ", ";
*os << "'instsSinceCovNew' : " << es->instsSinceCovNew << ", ";
*os << "'md2u' : " << md2u << ", ";
*os << "'icnt' : " << icnt << ", ";
Expand Down
Loading
Loading