Skip to content

Commit f532ed5

Browse files
authored
Merge branch 'development' into f-DeboostifyBitVectorSet
2 parents 701b1ec + 501c7e3 commit f532ed5

23 files changed

+340
-166
lines changed

examples/how-to/04-run-ifds-analysis/otf-reporter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77

88
namespace {
99
/// A listener that gets notified, whenever the taint analysis detects a leak
10+
///
11+
/// Checkout the analysis-printers that are already provided by PhASAR:
12+
/// - "phasar/Utils/OnTheFlyReporter.h"
13+
/// - "phasar/PhasarLLVM/Utils/LLVMAnalysisPrinter.h"
14+
/// - "phasar/PhasarLLVM/Utils/SourceMgrPrinter.h"
1015
class LeakReporter
1116
: public psr::AnalysisPrinterBase<psr::LLVMIFDSAnalysisDomainDefault> {
1217

include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,18 @@
1818
#include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h"
1919
#include "phasar/DataFlow/IfdsIde/InitialSeeds.h"
2020
#include "phasar/DataFlow/IfdsIde/Solver/GenericSolverResults.h"
21-
#include "phasar/DataFlow/IfdsIde/SolverResults.h"
21+
#include "phasar/Utils/DefaultAnalysisPrinterSelector.h"
2222
#include "phasar/Utils/JoinLattice.h"
23+
#include "phasar/Utils/Macros.h"
24+
#include "phasar/Utils/MaybeUniquePtr.h"
2325
#include "phasar/Utils/NullAnalysisPrinter.h"
2426
#include "phasar/Utils/SemiRing.h"
2527
#include "phasar/Utils/Soundness.h"
2628

29+
#include "llvm/Support/raw_ostream.h"
30+
2731
#include <cassert>
32+
#include <memory>
2833
#include <optional>
2934
#include <set>
3035
#include <string>
@@ -96,20 +101,28 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
96101
ZeroValue) noexcept(std::is_nothrow_move_constructible_v<d_t>)
97102
: IRDB(IRDB), EntryPoints(std::move(EntryPoints)),
98103
ZeroValue(std::move(ZeroValue)),
99-
Printer(NullAnalysisPrinter<AnalysisDomainTy>::getInstance()) {
104+
Printer(std::make_unique<typename DefaultAnalysisPrinterSelector<
105+
AnalysisDomainTy>::type>()) {
100106
assert(IRDB != nullptr);
101107
}
102108

103-
void setAnalysisPrinter(AnalysisPrinterBase<AnalysisDomainTy> *P) {
109+
IDETabulationProblem(IDETabulationProblem &&) noexcept = default;
110+
IDETabulationProblem &operator=(IDETabulationProblem &&) noexcept = default;
111+
112+
IDETabulationProblem(const IDETabulationProblem &) = delete;
113+
IDETabulationProblem &operator=(const IDETabulationProblem &) = delete;
114+
115+
~IDETabulationProblem() override = default;
116+
117+
void
118+
setAnalysisPrinter(MaybeUniquePtr<AnalysisPrinterBase<AnalysisDomainTy>> P) {
104119
if (P) {
105-
Printer = P;
120+
Printer = std::move(P);
106121
} else {
107122
Printer = NullAnalysisPrinter<AnalysisDomainTy>::getInstance();
108123
}
109124
}
110125

111-
~IDETabulationProblem() override = default;
112-
113126
/// Checks if the given data-flow fact is the special tautological lambda (or
114127
/// zero) fact.
115128
[[nodiscard]] virtual bool isZeroValue(d_t FlowFact) const noexcept {
@@ -148,7 +161,7 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
148161
virtual void
149162
emitTextReport([[maybe_unused]] GenericSolverResults<n_t, d_t, l_t> Results,
150163
llvm::raw_ostream &OS = llvm::outs()) {
151-
OS << "No text report available!\n";
164+
Printer->onFinalize(OS);
152165
}
153166

154167
/// Generates a graphical report, e.g. in html or other markup languages, of
@@ -163,7 +176,9 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
163176
/// the level of soundness is ignored. Otherwise, true.
164177
virtual bool setSoundness(Soundness /*S*/) { return false; }
165178

166-
const ProjectIRDBBase<db_t> *getProjectIRDB() const noexcept { return IRDB; }
179+
[[nodiscard]] const ProjectIRDBBase<db_t> *getProjectIRDB() const noexcept {
180+
return IRDB;
181+
}
167182

168183
protected:
169184
typename FlowFunctions<AnalysisDomainTy, Container>::FlowFunctionPtrType
@@ -172,6 +187,19 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
172187
std::move(FactToGenerate), getZeroValue());
173188
}
174189

190+
template <typename D = d_t, typename L = l_t>
191+
void onResult(n_t Instr, D &&DfFact, L &&LatticeElement,
192+
DataFlowAnalysisType AnalysisType) {
193+
Printer->onResult(Instr, PSR_FWD(DfFact), PSR_FWD(LatticeElement),
194+
AnalysisType);
195+
}
196+
197+
template <typename D = d_t, typename L = l_t>
198+
std::enable_if_t<std::is_same_v<L, psr::BinaryDomain>>
199+
onResult(n_t Instr, D &&DfFact, DataFlowAnalysisType AnalysisType) {
200+
Printer->onResult(Instr, PSR_FWD(DfFact), AnalysisType);
201+
}
202+
175203
/// Seeds that just start with ZeroValue and bottomElement() at the starting
176204
/// points of each EntryPoint function.
177205
/// Takes the __ALL__ EntryPoint into account.
@@ -196,7 +224,7 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
196224

197225
[[maybe_unused]] Soundness SF = Soundness::Soundy;
198226

199-
AnalysisPrinterBase<AnalysisDomainTy> *Printer;
227+
MaybeUniquePtr<AnalysisPrinterBase<AnalysisDomainTy>> Printer;
200228
};
201229

202230
} // namespace psr

include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ class IFDSTabulationProblem
5959
std::vector<std::string> EntryPoints,
6060
d_t ZeroValue)
6161
: Base(IRDB, std::move(EntryPoints), std::move(ZeroValue)) {}
62+
63+
IFDSTabulationProblem(IFDSTabulationProblem &&) noexcept = default;
64+
IFDSTabulationProblem &operator=(IFDSTabulationProblem &&) noexcept = default;
65+
66+
IFDSTabulationProblem(const IFDSTabulationProblem &) = delete;
67+
IFDSTabulationProblem &operator=(const IFDSTabulationProblem &) = delete;
68+
6269
~IFDSTabulationProblem() override = default;
6370

6471
EdgeFunction<l_t> getNormalEdgeFunction(n_t /*Curr*/, d_t /*CurrNode*/,

include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ class IDETypeStateAnalysisBase
5454
public:
5555
virtual ~IDETypeStateAnalysisBase() = default;
5656

57+
IDETypeStateAnalysisBase(IDETypeStateAnalysisBase &&) noexcept = default;
58+
IDETypeStateAnalysisBase &
59+
operator=(IDETypeStateAnalysisBase &&) noexcept = default;
60+
61+
IDETypeStateAnalysisBase(const IDETypeStateAnalysisBase &) = delete;
62+
IDETypeStateAnalysisBase &
63+
operator=(const IDETypeStateAnalysisBase &) noexcept = delete;
64+
5765
protected:
5866
IDETypeStateAnalysisBase(LLVMAliasInfoRef PT) noexcept : PT(PT) {}
5967

@@ -195,8 +203,7 @@ class IDETypeStateAnalysis
195203
}
196204

197205
[[no_unique_address]] std::conditional_t<HasJoinLatticeTraits<l_t>,
198-
EmptyType, l_t>
199-
BotElement{};
206+
EmptyType, l_t> BotElement{};
200207

201208
static EdgeFunction<l_t> join(EdgeFunctionRef<TSEdgeFunctionComposer> This,
202209
const EdgeFunction<l_t> &OtherFunction) {
@@ -348,8 +355,6 @@ class IDETypeStateAnalysis
348355
assert(PT);
349356
}
350357

351-
~IDETypeStateAnalysis() override = default;
352-
353358
// start formulating our analysis by specifying the parts required for IFDS
354359

355360
FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override {
@@ -513,40 +518,27 @@ class IDETypeStateAnalysis
513518

514519
void emitTextReport(GenericSolverResults<n_t, d_t, l_t> SR,
515520
llvm::raw_ostream &OS = llvm::outs()) override {
516-
LLVMBasedCFG CFG;
521+
517522
for (const auto &F : this->IRDB->getAllFunctions()) {
518523
for (const auto &BB : *F) {
519524
for (const auto &I : BB) {
520525
auto Results = SR.resultsAt(&I, true);
521526

522-
if (CFG.isExitInst(&I)) {
523-
for (auto Res : Results) {
524-
if (const auto *Alloca =
525-
llvm::dyn_cast<llvm::AllocaInst>(Res.first)) {
526-
if (Res.second == TSD->error()) {
527-
// ERROR STATE DETECTED
528-
this->Printer->onResult(&I, Res.first, TSD->error(),
529-
TSD->analysisType());
530-
}
531-
}
532-
}
533-
} else {
534-
for (auto Res : Results) {
535-
if (const auto *Alloca =
536-
llvm::dyn_cast<llvm::AllocaInst>(Res.first)) {
537-
if (Res.second == TSD->error()) {
538-
// ERROR STATE DETECTED
539-
this->Printer->onResult(&I, Res.first, TSD->error(),
540-
TSD->analysisType());
541-
}
527+
for (auto Res : Results) {
528+
if (const auto *Alloca =
529+
llvm::dyn_cast<llvm::AllocaInst>(Res.first)) {
530+
if (Res.second == TSD->error()) {
531+
// ERROR STATE DETECTED
532+
this->onResult(&I, Res.first, TSD->error(),
533+
TSD->analysisType());
542534
}
543535
}
544536
}
545537
}
546538
}
547539
}
548540

549-
this->Printer->onFinalize();
541+
this->Printer->onFinalize(OS);
550542
}
551543

552544
[[nodiscard]] bool

include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ class IFDSConstAnalysis
4949
IFDSConstAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT,
5050
std::vector<std::string> EntryPoints = {"main"});
5151

52-
~IFDSConstAnalysis() override = default;
53-
5452
/**
5553
* If the current instruction is a store instruction, the memory locations's
5654
* state of initialization is checked. If the memory location was already

include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ class IFDSTaintAnalysis
5858
std::vector<std::string> EntryPoints = {"main"},
5959
bool TaintMainArgs = true);
6060

61-
~IFDSTaintAnalysis() override = default;
62-
6361
FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override;
6462

6563
FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override;

include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ class IFDSUninitializedVariables
4040
IFDSUninitializedVariables(const LLVMProjectIRDB *IRDB,
4141
std::vector<std::string> EntryPoints = {"main"});
4242

43-
~IFDSUninitializedVariables() override = default;
44-
4543
FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override;
4644

4745
FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override;

include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#define PHASAR_PHASARLLVM_DOMAIN_LLVMANALYSISDOMAIN_H
1212

1313
#include "phasar/Domain/AnalysisDomain.h"
14+
#include "phasar/PhasarLLVM/Utils/LLVMAnalysisPrinter.h"
15+
#include "phasar/Utils/DefaultAnalysisPrinterSelector.h"
16+
#include "phasar/Utils/TypeTraits.h"
1417

1518
namespace llvm {
1619
class Value;
@@ -43,6 +46,13 @@ struct LLVMAnalysisDomainDefault : public AnalysisDomain {
4346
using LLVMIFDSAnalysisDomainDefault =
4447
WithBinaryValueDomain<LLVMAnalysisDomainDefault>;
4548

49+
extern template class DefaultLLVMAnalysisPrinter<LLVMIFDSAnalysisDomainDefault>;
50+
51+
template <>
52+
struct DefaultAnalysisPrinterSelector<LLVMIFDSAnalysisDomainDefault>
53+
: type_identity<DefaultLLVMAnalysisPrinter<LLVMIFDSAnalysisDomainDefault>> {
54+
};
55+
4656
} // namespace psr
4757

4858
#endif // PHASAR_PHASARLLVM_DOMAIN_LLVMANALYSISDOMAIN_H
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#ifndef PHASAR_PHASARLLVM_UTILS_LLVMANALYSISPRINTER_H
2+
#define PHASAR_PHASARLLVM_UTILS_LLVMANALYSISPRINTER_H
3+
4+
#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h"
5+
#include "phasar/Utils/ByRef.h"
6+
#include "phasar/Utils/DefaultAnalysisPrinter.h"
7+
8+
#include "llvm/ADT/ArrayRef.h"
9+
#include "llvm/ADT/SmallVector.h"
10+
#include "llvm/IR/Function.h"
11+
12+
#include <type_traits>
13+
14+
namespace psr {
15+
16+
template <typename AnalysisDomainTy>
17+
class DefaultLLVMAnalysisPrinter
18+
: public AnalysisPrinterBase<AnalysisDomainTy> {
19+
using n_t = typename AnalysisDomainTy::n_t;
20+
using d_t = typename AnalysisDomainTy::d_t;
21+
using l_t = typename AnalysisDomainTy::l_t;
22+
23+
public:
24+
DefaultLLVMAnalysisPrinter() noexcept = default;
25+
26+
private:
27+
static std::optional<DebugLocation> getDbgLoc(n_t Instr,
28+
ByConstRef<d_t> DfFact) {
29+
auto Ret = getDebugLocation(Instr);
30+
if constexpr (std::is_convertible_v<ByConstRef<d_t>, const llvm::Value *>) {
31+
if (!Ret) {
32+
Ret = getDebugLocation(static_cast<const llvm::Value *>(DfFact));
33+
}
34+
}
35+
return Ret;
36+
}
37+
38+
void printVariables(llvm::raw_ostream &OS,
39+
llvm::ArrayRef<Warning<AnalysisDomainTy>> Results) {
40+
if constexpr (std::is_convertible_v<const d_t &, const llvm::Value *>) {
41+
bool HasVariable = false;
42+
for (const auto &Warn : Results) {
43+
if (auto VarName = getVarNameFromIR(Warn.Fact); !VarName.empty()) {
44+
if (!HasVariable) {
45+
HasVariable = true;
46+
OS << " Variable: " << VarName;
47+
} else {
48+
OS << ", " << VarName;
49+
}
50+
}
51+
}
52+
if (HasVariable) {
53+
OS << '\n';
54+
}
55+
}
56+
}
57+
58+
void doOnResult(n_t Instr, d_t DfFact, l_t Lattice,
59+
DataFlowAnalysisType AnalysisType) override {
60+
if (auto DbgLoc = getDbgLoc(Instr, DfFact)) {
61+
DbgResultsEntries[*DbgLoc].emplace_back(Instr, std::move(DfFact),
62+
std::move(Lattice), AnalysisType);
63+
} else {
64+
NonDbgResultsEntries.emplace_back(Instr, std::move(DfFact),
65+
std::move(Lattice), AnalysisType);
66+
}
67+
}
68+
69+
void doOnFinalize(llvm::raw_ostream &OS) override {
70+
size_t Ctr = 0;
71+
for (const auto &[DbgLoc, Results] : DbgResultsEntries) {
72+
OS << '#' << ++Ctr << ": ";
73+
OS << "At " << getFilePathFromIR(DbgLoc.File) << ':' << DbgLoc.Line << ':'
74+
<< DbgLoc.Column << ":\n";
75+
OS << " In Function: " << Results.front().Instr->getFunction()->getName()
76+
<< '\n';
77+
if (auto SrcCode = getSrcCodeFromIR(DbgLoc); !SrcCode.empty()) {
78+
OS << " Source code: " << SrcCode << '\n';
79+
}
80+
printVariables(OS, Results);
81+
OS << "\n Corresponding IR Statements:\n";
82+
for (const auto &Warn : Results) {
83+
OS << " At IR statement: " << NToString(Warn.Instr) << '\n';
84+
OS << " Fact: " << DToString(Warn.Fact) << '\n';
85+
86+
if constexpr (!std::is_same_v<l_t, BinaryDomain>) {
87+
OS << " Value: " << LToString(Warn.LatticeElement) << '\n';
88+
}
89+
OS << '\n';
90+
}
91+
}
92+
93+
// Fallback in case we don't have debug information:
94+
for (const auto &Iter : NonDbgResultsEntries) {
95+
OS << "At IR statement: " << NToString(Iter.Instr) << '\n';
96+
OS << " In Function: " << Iter.Instr->getFunction()->getName() << '\n';
97+
OS << " Fact: " << DToString(Iter.Fact) << '\n';
98+
99+
if constexpr (!std::is_same_v<l_t, BinaryDomain>) {
100+
OS << " Value: " << LToString(Iter.LatticeElement) << '\n';
101+
}
102+
OS << '\n';
103+
}
104+
105+
DbgResultsEntries.clear();
106+
NonDbgResultsEntries.clear();
107+
}
108+
109+
std::map<DebugLocation, llvm::SmallVector<Warning<AnalysisDomainTy>, 1>>
110+
DbgResultsEntries;
111+
std::vector<Warning<AnalysisDomainTy>> NonDbgResultsEntries{};
112+
};
113+
114+
} // namespace psr
115+
116+
#endif // PHASAR_PHASARLLVM_UTILS_LLVMANALYSISPRINTER_H

0 commit comments

Comments
 (0)