Skip to content

Commit 934dd5d

Browse files
committed
[feat] Cooddy NPE location handling
1 parent c8b06fd commit 934dd5d

16 files changed

+1146
-219
lines changed

include/klee/Core/TargetedExecutionReporter.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ ty min(ty left, ty right);
3030
}; // namespace confidence
3131

3232
void reportFalsePositive(confidence::ty confidence,
33-
const std::vector<ReachWithError> &errors,
34-
const std::string &id, std::string whatToIncrease);
33+
const ReachWithErrors &errors, const std::string &id,
34+
std::string whatToIncrease);
3535

3636
} // namespace klee
3737

include/klee/Module/KInstruction.h

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Instruction;
3030
namespace klee {
3131
class Executor;
3232
class KModule;
33+
struct KFunction;
3334
struct KBlock;
3435

3536
/// KInstruction - Intermediate instruction representation used

include/klee/Module/SarifReport.h

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

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

@@ -52,9 +53,10 @@ enum ReachWithError {
5253
Reachable,
5354
None,
5455
};
56+
using ReachWithErrors = std::vector<ReachWithError>;
5557

5658
const char *getErrorString(ReachWithError error);
57-
std::string getErrorsString(const std::vector<ReachWithError> &errors);
59+
std::string getErrorsString(const ReachWithErrors &errors);
5860

5961
struct FunctionInfo;
6062
struct KBlock;
@@ -63,11 +65,16 @@ struct ArtifactLocationJson {
6365
optional<std::string> uri;
6466
};
6567

68+
struct Message {
69+
std::string text;
70+
};
71+
6672
struct RegionJson {
6773
optional<unsigned int> startLine;
6874
optional<unsigned int> endLine;
6975
optional<unsigned int> startColumn;
7076
optional<unsigned int> endColumn;
77+
optional<Message> message;
7178
};
7279

7380
struct PhysicalLocationJson {
@@ -92,10 +99,6 @@ struct CodeFlowJson {
9299
std::vector<ThreadFlowJson> threadFlows;
93100
};
94101

95-
struct Message {
96-
std::string text;
97-
};
98-
99102
struct Fingerprints {
100103
std::string cooddy_uid;
101104
};
@@ -137,7 +140,7 @@ struct SarifReportJson {
137140
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ArtifactLocationJson, uri)
138141

139142
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(RegionJson, startLine, endLine,
140-
startColumn, endColumn)
143+
startColumn, endColumn, message)
141144

142145
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(PhysicalLocationJson,
143146
artifactLocation, region)
@@ -165,6 +168,148 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(RunJson, results, tool)
165168

166169
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(SarifReportJson, runs)
167170

171+
enum class Precision { NotFound = 0, Line = 1, Column = 2, Instruction = 3 };
172+
173+
template <class T> struct WithPrecision {
174+
T *ptr;
175+
Precision precision;
176+
177+
explicit WithPrecision(T *p, Precision pr) : ptr(p), precision(pr) {}
178+
explicit WithPrecision(T *p) : WithPrecision(p, Precision::NotFound) {}
179+
explicit WithPrecision() : WithPrecision(nullptr) {}
180+
181+
void setNotFound() { precision = Precision::NotFound; }
182+
bool isNotFound() const { return precision == Precision::NotFound; }
183+
};
184+
185+
struct KBlock;
186+
struct KInstruction;
187+
188+
using BlockWithPrecision = WithPrecision<KBlock>;
189+
using InstrWithPrecision = WithPrecision<KInstruction>;
190+
191+
inline size_t hash_combine2(std::size_t s, std::size_t v) {
192+
return s ^ (v + 0x9e3779b9 + (s << 6) + (s >> 2));
193+
}
194+
195+
template <class T> inline void hash_combine(std::size_t &s, const T &v) {
196+
std::hash<T> h;
197+
s = hash_combine2(s, h(v));
198+
}
199+
200+
enum class ReachWithoutError {
201+
Reach = 0,
202+
Return,
203+
NPESource,
204+
Free,
205+
BranchFalse,
206+
BranchTrue,
207+
Call,
208+
AfterCall
209+
};
210+
211+
struct EventKind final {
212+
const bool isError;
213+
const ReachWithErrors kinds;
214+
const ReachWithoutError kind;
215+
size_t hashValue = 0;
216+
void computeHash() {
217+
hash_combine(hashValue, isError);
218+
for (auto k : kinds)
219+
hash_combine(hashValue, k);
220+
hash_combine(hashValue, kind);
221+
}
222+
EventKind(ReachWithErrors &&kinds)
223+
: isError(true), kinds(kinds), kind(ReachWithoutError::Reach) {
224+
computeHash();
225+
}
226+
EventKind(ReachWithoutError kind) : isError(false), kind(kind) {
227+
computeHash();
228+
}
229+
};
230+
} // namespace klee
231+
232+
namespace std {
233+
template <> struct hash<klee::EventKind> {
234+
size_t operator()(const klee::EventKind &k) const { return k.hashValue; }
235+
};
236+
} // namespace std
237+
238+
namespace klee {
239+
enum class ToolName { Unknown = 0, SecB, clang, CppCheck, Infer, Cooddy };
240+
241+
class LineColumnRange;
242+
243+
struct LocRange {
244+
virtual LineColumnRange getRange() const = 0;
245+
virtual ~LocRange() = default;
246+
virtual Precision maxPrecision() const = 0;
247+
virtual size_t hash() const = 0;
248+
virtual std::string toString() const = 0;
249+
bool hasInside(KInstruction *ki) const;
250+
void hasInside(InstrWithPrecision &kp);
251+
virtual void setRange(const KInstruction *ki) = 0;
252+
253+
protected:
254+
virtual bool hasInsideInternal(InstrWithPrecision &kp) const = 0;
255+
};
256+
257+
class LineColumnRange final : public LocRange {
258+
size_t startLine;
259+
size_t startColumn;
260+
size_t endLine;
261+
size_t endColumn;
262+
static const size_t empty = std::numeric_limits<size_t>::max();
263+
264+
bool inline onlyLine() const { return startColumn == empty; }
265+
266+
public:
267+
explicit LineColumnRange(size_t startLine, size_t startColumn, size_t endLine,
268+
size_t endColumn)
269+
: startLine(startLine), startColumn(startColumn), endLine(endLine),
270+
endColumn(endColumn) {
271+
assert(startLine <= endLine);
272+
assert(startLine != endLine || startColumn <= endColumn);
273+
}
274+
explicit LineColumnRange(size_t startLine, size_t endLine)
275+
: LineColumnRange(startLine, empty, endLine, empty) {}
276+
explicit LineColumnRange(const KInstruction *ki) { setRange(ki); }
277+
278+
void setRange(const KInstruction *ki) final;
279+
280+
LineColumnRange getRange() const final { return *this; }
281+
282+
void clearColumns() { startColumn = (endColumn = empty); }
283+
284+
Precision maxPrecision() const final {
285+
return onlyLine() ? Precision::Line : Precision::Column;
286+
}
287+
288+
size_t hash() const final {
289+
size_t hashValue = 0;
290+
hashValue = hash_combine2(hashValue, startLine);
291+
hashValue = hash_combine2(hashValue, endLine);
292+
hashValue = hash_combine2(hashValue, startColumn);
293+
return hash_combine2(hashValue, endColumn);
294+
}
295+
296+
std::string toString() const final {
297+
if (onlyLine())
298+
return std::to_string(startLine) + "-" + std::to_string(endLine);
299+
return std::to_string(startLine) + ":" + std::to_string(startColumn) + "-" +
300+
std::to_string(endLine) + ":" + std::to_string(endColumn);
301+
}
302+
303+
bool hasInsideInternal(InstrWithPrecision &kp) const final;
304+
305+
bool operator==(const LineColumnRange &p) const {
306+
return startLine == p.startLine && endLine == p.endLine &&
307+
startColumn == p.startColumn && endColumn == p.endColumn;
308+
}
309+
};
310+
311+
using OpCode = unsigned;
312+
168313
struct Location {
169314
struct LocationHash {
170315
std::size_t operator()(const Location *l) const { return l->hash(); }
@@ -184,35 +329,30 @@ struct Location {
184329
}
185330
};
186331
std::string filename;
187-
unsigned int startLine;
188-
unsigned int endLine;
189-
optional<unsigned int> startColumn;
190-
optional<unsigned int> endColumn;
332+
std::unique_ptr<LocRange> range;
191333

192-
static ref<Location> create(std::string filename_, unsigned int startLine_,
334+
static ref<Location> create(std::string &&filename_, unsigned int startLine_,
193335
optional<unsigned int> endLine_,
194336
optional<unsigned int> startColumn_,
195-
optional<unsigned int> endColumn_);
337+
optional<unsigned int> endColumn_,
338+
ToolName toolName, EventKind &kind);
196339

197-
~Location();
198-
std::size_t hash() const { return hashValue; }
340+
virtual ~Location();
341+
virtual std::size_t hash() const { return hashValue; }
199342

200343
/// @brief Required by klee::ref-managed objects
201344
class ReferenceCounter _refCount;
202345

203-
bool operator==(const Location &other) const {
204-
return filename == other.filename && startLine == other.startLine &&
205-
endLine == other.endLine && startColumn == other.startColumn &&
206-
endColumn == other.endColumn;
207-
}
346+
bool operator==(const Location &other) const;
208347

209348
bool isInside(const std::string &name) const;
210349

211350
using Instructions = std::unordered_map<
212351
unsigned int,
213-
std::unordered_map<unsigned int, std::unordered_set<unsigned int>>>;
352+
std::unordered_map<unsigned int, std::unordered_set<OpCode>>>;
214353

215-
bool isInside(KBlock *block, const Instructions &origInsts) const;
354+
void isInside(InstrWithPrecision &kp, const Instructions &origInsts) const;
355+
void isInside(BlockWithPrecision &bp, const Instructions &origInsts) const;
216356

217357
std::string toString() const;
218358

@@ -226,28 +366,20 @@ struct Location {
226366
static LocationHashSet locations;
227367

228368
size_t hashValue = 0;
229-
void computeHash() {
230-
hash_combine(hashValue, filename);
231-
hash_combine(hashValue, startLine);
232-
hash_combine(hashValue, endLine);
233-
hash_combine(hashValue, startColumn);
234-
hash_combine(hashValue, endColumn);
235-
}
369+
void computeHash(EventKind &kind);
236370

237-
template <class T> inline void hash_combine(std::size_t &s, const T &v) {
238-
std::hash<T> h;
239-
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
240-
}
371+
static Location *createCooddy(std::string &&filename_, LineColumnRange &range,
372+
EventKind &kind);
241373

242-
Location(std::string filename_, unsigned int startLine_,
243-
optional<unsigned int> endLine_, optional<unsigned int> startColumn_,
244-
optional<unsigned int> endColumn_)
245-
: filename(filename_), startLine(startLine_),
246-
endLine(endLine_.has_value() ? *endLine_ : startLine_),
247-
startColumn(startColumn_),
248-
endColumn(endColumn_.has_value() ? endColumn_ : startColumn_) {
249-
computeHash();
374+
protected:
375+
Location(std::string &&filename_, std::unique_ptr<LocRange> range,
376+
EventKind &kind)
377+
: filename(std::move(filename_)), range(std::move(range)) {
378+
computeHash(kind);
250379
}
380+
381+
virtual void isInsideInternal(BlockWithPrecision &bp,
382+
const Instructions &origInsts) const;
251383
};
252384

253385
struct RefLocationHash {
@@ -262,9 +394,9 @@ struct RefLocationCmp {
262394

263395
struct Result {
264396
std::vector<ref<Location>> locations;
265-
std::vector<optional<json>> metadatas;
266-
std::string id;
267-
std::vector<ReachWithError> errors;
397+
const std::vector<optional<json>> metadatas;
398+
const std::string id;
399+
const ReachWithErrors errors;
268400
};
269401

270402
struct SarifReport {

include/klee/Module/Target.h

+10-21
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,6 @@ DISABLE_WARNING_POP
3636
namespace klee {
3737
using nonstd::optional;
3838

39-
struct ErrorLocation {
40-
unsigned int startLine;
41-
unsigned int endLine;
42-
optional<unsigned int> startColumn;
43-
optional<unsigned int> endColumn;
44-
45-
ErrorLocation(const klee::ref<klee::Location> &loc);
46-
ErrorLocation(const KInstruction *ki);
47-
};
48-
4939
class ReproduceErrorTarget;
5040

5141
class Target {
@@ -174,23 +164,22 @@ class CoverBranchTarget : public Target {
174164

175165
class ReproduceErrorTarget : public Target {
176166
private:
177-
std::vector<ReachWithError>
178-
errors; // None - if it is not terminated in error trace
179-
std::string id; // "" - if it is not terminated in error trace
180-
ErrorLocation loc; // TODO(): only for check in reportTruePositive
167+
ReachWithErrors errors; // None - if it is not terminated in error trace
168+
std::string id; // "" - if it is not terminated in error trace
169+
LineColumnRange loc; // TODO(): only for check in reportTruePositive
181170

182171
protected:
183-
explicit ReproduceErrorTarget(const std::vector<ReachWithError> &_errors,
184-
const std::string &_id, ErrorLocation _loc,
172+
explicit ReproduceErrorTarget(const ReachWithErrors &_errors,
173+
const std::string &_id, LineColumnRange _loc,
185174
KBlock *_block)
186-
: Target(_block), errors(_errors), id(_id), loc(_loc) {
175+
: Target(_block), errors(_errors), id(_id), loc(std::move(_loc)) {
187176
assert(errors.size() > 0);
188177
std::sort(errors.begin(), errors.end());
189178
}
190179

191180
public:
192-
static ref<Target> create(const std::vector<ReachWithError> &_errors,
193-
const std::string &_id, ErrorLocation _loc,
181+
static ref<Target> create(const ReachWithErrors &_errors,
182+
const std::string &_id, LineColumnRange _loc,
194183
KBlock *_block);
195184

196185
Kind getKind() const override { return Kind::ReproduceError; }
@@ -207,12 +196,12 @@ class ReproduceErrorTarget : public Target {
207196

208197
bool isReported = false;
209198

210-
const std::vector<ReachWithError> &getErrors() const { return errors; }
199+
const ReachWithErrors &getErrors() const { return errors; }
211200
bool isThatError(ReachWithError err) const {
212201
return std::find(errors.begin(), errors.end(), err) != errors.end();
213202
}
214203

215-
bool isTheSameAsIn(const KInstruction *instr) const;
204+
bool isTheSameAsIn(KInstruction *instr) const;
216205
};
217206
} // namespace klee
218207

lib/Core/Executor.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -6707,7 +6707,7 @@ void Executor::runFunctionAsMain(Function *f, int argc, char **argv,
67076707
KBlock *kCallBlock = kfunction->entryKBlock;
67086708
forest->add(ReproduceErrorTarget::create(
67096709
{ReachWithError::Reachable}, "",
6710-
ErrorLocation(kCallBlock->getFirstInstruction()), kCallBlock));
6710+
LineColumnRange(kCallBlock->getFirstInstruction()), kCallBlock));
67116711
prepTargets.emplace(kEntryFunction, forest);
67126712
}
67136713

0 commit comments

Comments
 (0)