Skip to content

Commit

Permalink
[feat] Cooddy NPE location handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Columpio authored and ladisgin committed Aug 30, 2023
1 parent a1aa217 commit a84c6ce
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 22 deletions.
35 changes: 33 additions & 2 deletions include/klee/Module/SarifReport.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <vector>

#include "klee/ADT/Ref.h"
#include "klee/Module/KInstruction.h"
#include <nlohmann/json.hpp>
#include <nonstd/optional.hpp>

Expand Down Expand Up @@ -165,6 +166,29 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(RunJson, results, tool)

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(SarifReportJson, runs)

enum class Precision {
NotFound = 0,
LineLevel = 1,
ColumnLevel = 2
};

template <class T>
struct WithPrecision {
T *ptr;
Precision precision;

explicit WithPrecision(T *p, Precision pr) : ptr(p), precision(pr) {}
explicit WithPrecision(T *p) : WithPrecision(p, Precision::NotFound) {}
explicit WithPrecision() : WithPrecision(nullptr) {}

void setNotFound() {
ptr = nullptr;
precision = Precision::NotFound;
}
};
using BlockWithPrecision = WithPrecision<KBlock>;
using InstrWithPrecision = WithPrecision<KInstruction>;

struct Location {
struct LocationHash {
std::size_t operator()(const Location *l) const { return l->hash(); }
Expand Down Expand Up @@ -194,7 +218,7 @@ struct Location {
optional<unsigned int> startColumn_,
optional<unsigned int> endColumn_);

~Location();
virtual ~Location();
std::size_t hash() const { return hashValue; }

/// @brief Required by klee::ref-managed objects
Expand All @@ -212,7 +236,9 @@ struct Location {
unsigned int,
std::unordered_map<unsigned int, std::unordered_set<unsigned int>>>;

bool isInside(KBlock *block, const Instructions &origInsts) const;
void isInside(InstrWithPrecision &kp, const Instructions &origInsts) const;

virtual void isInside(BlockWithPrecision &bp, const Instructions &origInsts);

std::string toString() const;

Expand Down Expand Up @@ -250,6 +276,11 @@ struct Location {
}
};

struct CoodyNPELocation : public Location {
CoodyNPELocation(const Location &loc) : Location(loc) {}
void isInside(BlockWithPrecision &bp, const Instructions &origInsts) override;
};

struct RefLocationHash {
unsigned operator()(const ref<Location> &t) const { return t->hash(); }
};
Expand Down
16 changes: 13 additions & 3 deletions lib/Core/TargetedExecutionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ TargetedExecutionManager::prepareAllLocations(KModule *kmodule,
const auto &infos = kmodule->infos;
for (auto it = locations.begin(); it != locations.end(); ++it) {
auto loc = *it;
auto precision = Precision::LineLevel;
Blocks blocks;
for (const auto &fileName : infos->getFilesNames()) {
if (kmodule->origInfos.count(fileName) == 0) {
continue;
Expand All @@ -338,14 +340,22 @@ TargetedExecutionManager::prepareAllLocations(KModule *kmodule,
const auto &origInstsInFile = kmodule->origInfos.at(fi.file);

for (const auto &kblock : kfunc->blocks) {
auto b = kblock.get();
if (!loc->isInside(b, origInstsInFile)) {
BlockWithPrecision bp(kblock.get(), precision);
loc->isInside(bp, origInstsInFile);
if (bp.precision < precision) {
continue;
} else if (bp.precision == precision) {
blocks.insert(bp.ptr);
} else {
blocks.clear();
blocks.insert(bp.ptr);
precision = bp.precision;
}
locToBlocks[loc].insert(b);
}
}
}
if (!blocks.empty())
locToBlocks.emplace(loc, std::move(blocks));
}

return locToBlocks;
Expand Down
110 changes: 93 additions & 17 deletions lib/Module/SarifReport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,21 @@ tryConvertRuleJson(const std::string &ruleId, const std::string &toolName,
}
}

void
tryConvertMessage(const std::string &toolName, const optional<Message> &errorMessage, ref<Location> &loc) {
if (toolName != "Cooddy" || !errorMessage.has_value())
return;
std::string start = "Dereferencing of \"";
std::string end = "\" which can be null";
auto &text = errorMessage->text;
if (text.substr(0, start.size()) == start &&
text.substr(text.size() - end.size(), end.size()) == end) {
auto size = text.size() - end.size() - start.size();
auto derefedExpr = text.substr(start.size(), size);
loc = new CoodyNPELocation(*loc);
}
}

optional<Result> tryConvertResultJson(const ResultJson &resultJson,
const std::string &toolName,
const std::string &id) {
Expand Down Expand Up @@ -166,6 +181,7 @@ optional<Result> tryConvertResultJson(const ResultJson &resultJson,
if (locations.empty()) {
return nonstd::nullopt;
}
tryConvertMessage(toolName, resultJson.message, locations.back());

return Result{std::move(locations), std::move(metadatas), id,
std::move(errors)};
Expand Down Expand Up @@ -325,27 +341,87 @@ bool Location::isInside(const std::string &name) const {
: (m == -1 && isOSSeparator(filename[n])));
}

bool Location::isInside(KBlock *block, const Instructions &origInsts) const {
auto first = block->getFirstInstruction()->info;
auto last = block->getLastInstruction()->info;
void Location::isInside(InstrWithPrecision &kp, const Instructions &origInsts) const {
auto ki = kp.ptr;
auto inst = ki->info;
if (!isa<DbgInfoIntrinsic>(ki->inst) && startLine <= inst->line && inst->line <= endLine) {
auto opCode = ki->inst->getOpcode();
if (*startColumn <= inst->column && inst->column <= *endColumn &&
origInsts.at(inst->line).at(inst->column).count(opCode) != 0)
kp.precision = Precision::ColumnLevel;
else
kp.precision = Precision::LineLevel;
return;
}
}

void Location::isInside(BlockWithPrecision &bp, const Instructions &origInsts) {
if (!startColumn.has_value()) {
if (first->line > endLine)
return false;
return startLine <= last->line; // and `first <= line` from above
} else {
for (size_t i = 0; i < block->numInstructions; ++i) {
auto inst = block->instructions[i]->info;
auto opCode = block->instructions[i]->inst->getOpcode();
if (!isa<DbgInfoIntrinsic>(block->instructions[i]->inst) &&
inst->line <= endLine && inst->line >= startLine &&
inst->column <= *endColumn && inst->column >= *startColumn &&
origInsts.at(inst->line).at(inst->column).count(opCode) != 0) {
return true;
}
auto first = bp.ptr->getFirstInstruction()->info;
auto last = bp.ptr->getLastInstruction()->info;
if (first->line <= endLine && startLine <= last->line)
bp.precision = Precision::LineLevel;
else
bp.setNotFound();
return;
}
auto tmpBP = bp;
bp.setNotFound();
for (size_t i = 0; i < tmpBP.ptr->numInstructions; ++i) {
InstrWithPrecision kp(tmpBP.ptr->instructions[i]);
isInside(kp, origInsts);
if (kp.precision >= tmpBP.precision) {
tmpBP.precision = kp.precision;
bp = tmpBP;
}
}
}

return false;
void CoodyNPELocation::isInside(BlockWithPrecision &bp, const Instructions &origInsts) {
// if (x + y > z && aaa->bbb->ccc->ddd)
// ^^^^^^^^^^^^^^^^^ first, skip all this
// second skip this ^^^^^^^^ (where Cooddy event points)
// finally, get this ^ (real location of `Load` instruction)
auto block = bp.ptr;
size_t start = 0;
auto inside = false;
auto precision = bp.precision;
KInstruction *ki = nullptr;
for (; start < block->numInstructions; ++start) {
ki = block->instructions[start];
InstrWithPrecision kp(ki);
Location::isInside(kp, origInsts);
if (kp.precision >= precision) { // first: go until Cooddy event
precision = kp.precision;
if (!inside) // first: reached Cooddy event
inside = true;
} else if (inside) // second: skip until left Coody event
break;
}
if (!inside) { // no Cooddy event in this Block
bp.setNotFound();
return;
}
if (precision == Precision::LineLevel) {
bp.precision = precision;
return;
}
// finally: Load instruction
if (ki->inst->getOpcode() == Instruction::Load) {
// we got precise instruction, so redefine the location
startLine = (endLine = ki->info->line);
startColumn = (endColumn = ki->info->column);
bp.precision = Precision::ColumnLevel;
return;
}
// most probably Cooddy points to a macro call
for (size_t i = 0; i < start; i++) {
if (block->instructions[i]->inst->getOpcode() == Instruction::Load) {
bp.precision = Precision::LineLevel;
return;
}
}
bp.setNotFound();
}

std::string Location::toString() const {
Expand Down

0 comments on commit a84c6ce

Please sign in to comment.