Skip to content

Commit 94e3d70

Browse files
committed
[feat] Cooddy NPE location handling
1 parent a428b7c commit 94e3d70

File tree

3 files changed

+139
-22
lines changed

3 files changed

+139
-22
lines changed

include/klee/Module/SarifReport.h

+33-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <vector>
1717

1818
#include "klee/ADT/Ref.h"
19+
#include "klee/Module/KInstruction.h"
1920
#include <nlohmann/json.hpp>
2021
#include <nonstd/optional.hpp>
2122

@@ -165,6 +166,29 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(RunJson, results, tool)
165166

166167
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(SarifReportJson, runs)
167168

169+
enum class Precision {
170+
NotFound = 0,
171+
LineLevel = 1,
172+
ColumnLevel = 2
173+
};
174+
175+
template <class T>
176+
struct WithPrecision {
177+
T *ptr;
178+
Precision precision;
179+
180+
explicit WithPrecision(T *p, Precision pr) : ptr(p), precision(pr) {}
181+
explicit WithPrecision(T *p) : WithPrecision(p, Precision::NotFound) {}
182+
explicit WithPrecision() : WithPrecision(nullptr) {}
183+
184+
void setNotFound() {
185+
ptr = nullptr;
186+
precision = Precision::NotFound;
187+
}
188+
};
189+
using BlockWithPrecision = WithPrecision<KBlock>;
190+
using InstrWithPrecision = WithPrecision<KInstruction>;
191+
168192
struct Location {
169193
struct LocationHash {
170194
std::size_t operator()(const Location *l) const { return l->hash(); }
@@ -194,7 +218,7 @@ struct Location {
194218
optional<unsigned int> startColumn_,
195219
optional<unsigned int> endColumn_);
196220

197-
~Location();
221+
virtual ~Location();
198222
std::size_t hash() const { return hashValue; }
199223

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

215-
bool isInside(KBlock *block, const Instructions &origInsts) const;
239+
void isInside(InstrWithPrecision &kp, const Instructions &origInsts) const;
240+
241+
virtual void isInside(BlockWithPrecision &bp, const Instructions &origInsts);
216242

217243
std::string toString() const;
218244

@@ -250,6 +276,11 @@ struct Location {
250276
}
251277
};
252278

279+
struct CoodyNPELocation : public Location {
280+
CoodyNPELocation(const Location &loc) : Location(loc) {}
281+
void isInside(BlockWithPrecision &bp, const Instructions &origInsts) override;
282+
};
283+
253284
struct RefLocationHash {
254285
unsigned operator()(const ref<Location> &t) const { return t->hash(); }
255286
};

lib/Core/TargetedExecutionManager.cpp

+13-3
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ TargetedExecutionManager::prepareAllLocations(KModule *kmodule,
321321
const auto &infos = kmodule->infos;
322322
for (auto it = locations.begin(); it != locations.end(); ++it) {
323323
auto loc = *it;
324+
auto precision = Precision::LineLevel;
325+
Blocks blocks;
324326
for (const auto &fileName : infos->getFilesNames()) {
325327
if (kmodule->origInfos.count(fileName) == 0) {
326328
continue;
@@ -338,14 +340,22 @@ TargetedExecutionManager::prepareAllLocations(KModule *kmodule,
338340
const auto &origInstsInFile = kmodule->origInfos.at(fi.file);
339341

340342
for (const auto &kblock : kfunc->blocks) {
341-
auto b = kblock.get();
342-
if (!loc->isInside(b, origInstsInFile)) {
343+
BlockWithPrecision bp(kblock.get(), precision);
344+
loc->isInside(bp, origInstsInFile);
345+
if (bp.precision < precision) {
343346
continue;
347+
} else if (bp.precision == precision) {
348+
blocks.insert(bp.ptr);
349+
} else {
350+
blocks.clear();
351+
blocks.insert(bp.ptr);
352+
precision = bp.precision;
344353
}
345-
locToBlocks[loc].insert(b);
346354
}
347355
}
348356
}
357+
if (!blocks.empty())
358+
locToBlocks.emplace(loc, std::move(blocks));
349359
}
350360

351361
return locToBlocks;

lib/Module/SarifReport.cpp

+93-17
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,21 @@ tryConvertRuleJson(const std::string &ruleId, const std::string &toolName,
121121
}
122122
}
123123

124+
void
125+
tryConvertMessage(const std::string &toolName, const optional<Message> &errorMessage, ref<Location> &loc) {
126+
if (toolName != "Cooddy" || !errorMessage.has_value())
127+
return;
128+
std::string start = "Dereferencing of \"";
129+
std::string end = "\" which can be null";
130+
auto &text = errorMessage->text;
131+
if (text.substr(0, start.size()) == start &&
132+
text.substr(text.size() - end.size(), end.size()) == end) {
133+
auto size = text.size() - end.size() - start.size();
134+
auto derefedExpr = text.substr(start.size(), size);
135+
loc = new CoodyNPELocation(*loc);
136+
}
137+
}
138+
124139
optional<Result> tryConvertResultJson(const ResultJson &resultJson,
125140
const std::string &toolName,
126141
const std::string &id) {
@@ -166,6 +181,7 @@ optional<Result> tryConvertResultJson(const ResultJson &resultJson,
166181
if (locations.empty()) {
167182
return nonstd::nullopt;
168183
}
184+
tryConvertMessage(toolName, resultJson.message, locations.back());
169185

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

328-
bool Location::isInside(KBlock *block, const Instructions &origInsts) const {
329-
auto first = block->getFirstInstruction()->info;
330-
auto last = block->getLastInstruction()->info;
344+
void Location::isInside(InstrWithPrecision &kp, const Instructions &origInsts) const {
345+
auto ki = kp.ptr;
346+
auto inst = ki->info;
347+
if (!isa<DbgInfoIntrinsic>(ki->inst) && startLine <= inst->line && inst->line <= endLine) {
348+
auto opCode = ki->inst->getOpcode();
349+
if (*startColumn <= inst->column && inst->column <= *endColumn &&
350+
origInsts.at(inst->line).at(inst->column).count(opCode) != 0)
351+
kp.precision = Precision::ColumnLevel;
352+
else
353+
kp.precision = Precision::LineLevel;
354+
return;
355+
}
356+
}
357+
358+
void Location::isInside(BlockWithPrecision &bp, const Instructions &origInsts) {
331359
if (!startColumn.has_value()) {
332-
if (first->line > endLine)
333-
return false;
334-
return startLine <= last->line; // and `first <= line` from above
335-
} else {
336-
for (size_t i = 0; i < block->numInstructions; ++i) {
337-
auto inst = block->instructions[i]->info;
338-
auto opCode = block->instructions[i]->inst->getOpcode();
339-
if (!isa<DbgInfoIntrinsic>(block->instructions[i]->inst) &&
340-
inst->line <= endLine && inst->line >= startLine &&
341-
inst->column <= *endColumn && inst->column >= *startColumn &&
342-
origInsts.at(inst->line).at(inst->column).count(opCode) != 0) {
343-
return true;
344-
}
360+
auto first = bp.ptr->getFirstInstruction()->info;
361+
auto last = bp.ptr->getLastInstruction()->info;
362+
if (first->line <= endLine && startLine <= last->line)
363+
bp.precision = Precision::LineLevel;
364+
else
365+
bp.setNotFound();
366+
return;
367+
}
368+
auto tmpBP = bp;
369+
bp.setNotFound();
370+
for (size_t i = 0; i < tmpBP.ptr->numInstructions; ++i) {
371+
InstrWithPrecision kp(tmpBP.ptr->instructions[i]);
372+
isInside(kp, origInsts);
373+
if (kp.precision >= tmpBP.precision) {
374+
tmpBP.precision = kp.precision;
375+
bp = tmpBP;
345376
}
377+
}
378+
}
346379

347-
return false;
380+
void CoodyNPELocation::isInside(BlockWithPrecision &bp, const Instructions &origInsts) {
381+
// if (x + y > z && aaa->bbb->ccc->ddd)
382+
// ^^^^^^^^^^^^^^^^^ first, skip all this
383+
// second skip this ^^^^^^^^ (where Cooddy event points)
384+
// finally, get this ^ (real location of `Load` instruction)
385+
auto block = bp.ptr;
386+
size_t start = 0;
387+
auto inside = false;
388+
auto precision = bp.precision;
389+
KInstruction *ki = nullptr;
390+
for (; start < block->numInstructions; ++start) {
391+
ki = block->instructions[start];
392+
InstrWithPrecision kp(ki);
393+
Location::isInside(kp, origInsts);
394+
if (kp.precision >= precision) { // first: go until Cooddy event
395+
precision = kp.precision;
396+
if (!inside) // first: reached Cooddy event
397+
inside = true;
398+
} else if (inside) // second: skip until left Coody event
399+
break;
400+
}
401+
if (!inside) { // no Cooddy event in this Block
402+
bp.setNotFound();
403+
return;
404+
}
405+
if (precision == Precision::LineLevel) {
406+
bp.precision = precision;
407+
return;
408+
}
409+
// finally: Load instruction
410+
if (ki->inst->getOpcode() == Instruction::Load) {
411+
// we got precise instruction, so redefine the location
412+
startLine = (endLine = ki->info->line);
413+
startColumn = (endColumn = ki->info->column);
414+
bp.precision = Precision::ColumnLevel;
415+
return;
416+
}
417+
// most probably Cooddy points to a macro call
418+
for (size_t i = 0; i < start; i++) {
419+
if (block->instructions[i]->inst->getOpcode() == Instruction::Load) {
420+
bp.precision = Precision::LineLevel;
421+
return;
422+
}
348423
}
424+
bp.setNotFound();
349425
}
350426

351427
std::string Location::toString() const {

0 commit comments

Comments
 (0)