Skip to content

Commit

Permalink
Analysis Printer (#677)
Browse files Browse the repository at this point in the history
* Analysis Printer (#17)

* Initial Commit

* AnalysisPrinter Second commit

* Initial Commit

* Integrate Printer with client Analysis and test

* Addressing Review comments

* Integrate AnalysisPrinter with all analyses and template class modified

* vector emplace_back instead of push_back

* Testcase for AnalysisPrinter

* GroundTruth derived class initial commit

* AnalysisPrinter Test complete and Test

* fixing myphasartool file

* Test pre-commit fix

* Adding Test cases and fixing PR failure

* 1.template params to N,D,L  2.remove AnalysisType param from AnalysisResults 3.rearranging class variables

* 1.template params to N,D,L 2.remove AnalysisType param from AnalysisResults 3.rearranging class variables

* Null AnalysisPrinter singleton

* Adding AnalysisPrinter to IDETabulation Problem

* making free (N,D,L)ToString functions

* disable copy and move for analysis-printer

* Default NullAnalysisPrinter and explicit print methods

* removing SetAnalysisPrinter from client analyses and modified Testcase for AnalysisPrinter

* Adding superclass for AnalysisPrinter

* Addressing review comments and fixing PR build failure

* fix: minors

* fix: minor (clang-tidy)

* fix: review feedback

* misc: minor refactoring

---------

Co-authored-by: SanthoshMohan <[email protected]>
Co-authored-by: Sriteja Kummita <[email protected]>

* fix: review feedback

---------

Co-authored-by: SanthoshMohan <[email protected]>
Co-authored-by: Sriteja Kummita <[email protected]>
  • Loading branch information
3 people authored Nov 25, 2023
1 parent fc14480 commit 1e9f3b7
Show file tree
Hide file tree
Showing 13 changed files with 295 additions and 70 deletions.
14 changes: 13 additions & 1 deletion include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h"
#include "phasar/DataFlow/IfdsIde/InitialSeeds.h"
#include "phasar/DataFlow/IfdsIde/SolverResults.h"
#include "phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h"
#include "phasar/Utils/JoinLattice.h"
#include "phasar/Utils/Printer.h"
#include "phasar/Utils/Soundness.h"
Expand Down Expand Up @@ -78,10 +79,19 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
std::optional<d_t>
ZeroValue) noexcept(std::is_nothrow_move_constructible_v<d_t>)
: IRDB(IRDB), EntryPoints(std::move(EntryPoints)),
ZeroValue(std::move(ZeroValue)) {
ZeroValue(std::move(ZeroValue)),
Printer(NullAnalysisPrinter<AnalysisDomainTy>::getInstance()) {
assert(IRDB != nullptr);
}

void setAnalysisPrinter(AnalysisPrinterBase<AnalysisDomainTy> *P) {
if (P) {
Printer = P;
} else {
Printer = NullAnalysisPrinter<AnalysisDomainTy>::getInstance();
}
}

~IDETabulationProblem() override = default;

/// Checks if the given data-flow fact is the special tautological lambda (or
Expand Down Expand Up @@ -167,6 +177,8 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
IFDSIDESolverConfig SolverConfig{};

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

AnalysisPrinterBase<AnalysisDomainTy> *Printer;
};

} // namespace psr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_EXTENDEDVALUE_H
#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_EXTENDEDVALUE_H

#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"

#include <cassert>
#include <functional>
#include <string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,70 +519,41 @@ class IDETypeStateAnalysis
void emitTextReport(const SolverResults<n_t, d_t, l_t> &SR,
llvm::raw_ostream &OS = llvm::outs()) override {
LLVMBasedCFG CFG;
OS << "\n======= TYPE STATE RESULTS =======\n";
for (const auto &F : this->IRDB->getAllFunctions()) {
OS << '\n' << F->getName() << '\n';
for (const auto &BB : *F) {
for (const auto &I : BB) {
auto Results = SR.resultsAt(&I, true);

if (CFG.isExitInst(&I)) {
OS << "\nAt exit stmt: " << NToString(&I) << '\n';
for (auto Res : Results) {
if (const auto *Alloca =
llvm::dyn_cast<llvm::AllocaInst>(Res.first)) {
if (Res.second == TSD->error()) {
OS << "\n=== ERROR STATE DETECTED ===\nAlloca: "
<< DToString(Res.first) << '\n';
for (const auto *Pred : CFG.getPredsOf(&I)) {
OS << "\nPredecessor: " << NToString(Pred) << '\n';
auto PredResults = SR.resultsAt(Pred, true);
for (auto Res : PredResults) {
if (Res.first == Alloca) {
OS << "Pred State: " << LToString(Res.second) << '\n';
}
}
}
OS << "============================\n";
} else {
OS << "\nAlloca : " << DToString(Res.first)
<< "\nState : " << LToString(Res.second) << '\n';
Warning<IDETypeStateAnalysisDomain<TypeStateDescriptionTy>>
Warn(&I, Res.first, TSD->error());
// ERROR STATE DETECTED
this->Printer->onResult(Warn);
}
} else {
OS << "\nInst: " << NToString(&I) << '\n'
<< "Fact: " << DToString(Res.first) << '\n'
<< "State: " << LToString(Res.second) << '\n';
}
}
} else {
for (auto Res : Results) {
if (const auto *Alloca =
llvm::dyn_cast<llvm::AllocaInst>(Res.first)) {
if (Res.second == TSD->error()) {
OS << "\n=== ERROR STATE DETECTED ===\nAlloca: "
<< DToString(Res.first) << '\n'
<< "\nAt IR Inst: " << NToString(&I) << '\n';
for (const auto *Pred : CFG.getPredsOf(&I)) {
OS << "\nPredecessor: " << NToString(Pred) << '\n';
auto PredResults = SR.resultsAt(Pred, true);
for (auto Res : PredResults) {
if (Res.first == Alloca) {
OS << "Pred State: " << LToString(Res.second) << '\n';
}
}
}
OS << "============================\n";
Warning<IDETypeStateAnalysisDomain<TypeStateDescriptionTy>>
Warn(&I, Res.first, TSD->error());
// ERROR STATE DETECTED
this->Printer->onResult(Warn);
}
} else {
OS << "\nInst: " << NToString(&I) << '\n'
<< "Fact: " << DToString(Res.first) << '\n'
<< "State: " << LToString(Res.second) << '\n';
}
}
}
}
}
OS << "\n--------------------------------------------\n";
}

this->Printer->onFinalize(OS);
}

private:
Expand Down
44 changes: 44 additions & 0 deletions include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H
#define PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H

#include "llvm/Support/raw_ostream.h"

namespace psr {

template <typename AnalysisDomainTy> struct Warning {
using n_t = typename AnalysisDomainTy::n_t;
using d_t = typename AnalysisDomainTy::d_t;
using l_t = typename AnalysisDomainTy::l_t;

n_t Instr;
d_t Fact;
l_t LatticeElement;

// Constructor
Warning(n_t Inst, d_t DfFact, l_t Lattice)
: Instr(std::move(Inst)), Fact(std::move(DfFact)),
LatticeElement(std::move(Lattice)) {}
};

template <typename AnalysisDomainTy> struct DataflowAnalysisResults {
std::vector<Warning<AnalysisDomainTy>> War;
};

template <typename AnalysisDomainTy> class AnalysisPrinterBase {
public:
virtual void onResult(Warning<AnalysisDomainTy> /*War*/) = 0;
virtual void onInitialize() = 0;
virtual void onFinalize(llvm::raw_ostream & /*OS*/) const = 0;

AnalysisPrinterBase() = default;
virtual ~AnalysisPrinterBase() = default;
AnalysisPrinterBase(const AnalysisPrinterBase &) = delete;
AnalysisPrinterBase &operator=(const AnalysisPrinterBase &) = delete;

AnalysisPrinterBase(AnalysisPrinterBase &&) = delete;
AnalysisPrinterBase &operator=(AnalysisPrinterBase &&) = delete;
};

} // namespace psr

#endif
47 changes: 47 additions & 0 deletions include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H
#define PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H

#include "phasar/Domain/BinaryDomain.h"
#include "phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h"
#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
#include "phasar/Utils/Printer.h"

#include <optional>
#include <type_traits>
#include <vector>

namespace psr {

template <typename AnalysisDomainTy>
class DefaultAnalysisPrinter : public AnalysisPrinterBase<AnalysisDomainTy> {
using l_t = typename AnalysisDomainTy::l_t;

public:
~DefaultAnalysisPrinter() override = default;
DefaultAnalysisPrinter() = default;

void onResult(Warning<AnalysisDomainTy> War) override {
AnalysisResults.War.emplace_back(std::move(War));
}

void onInitialize() override{};
void onFinalize(llvm::raw_ostream &OS = llvm::outs()) const override {
for (const auto &Iter : AnalysisResults.War) {

OS << "\nAt IR statement: " << NToString(Iter.Instr) << "\n";

OS << "\tFact: " << DToString(Iter.Fact) << "\n";

if constexpr (std::is_same_v<l_t, BinaryDomain>) {
OS << "Value: " << LToString(Iter.LatticeElement) << "\n";
}
}
}

private:
DataflowAnalysisResults<AnalysisDomainTy> AnalysisResults{};
};

} // namespace psr

#endif
25 changes: 25 additions & 0 deletions include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef PHASAR_PHASARLLVM_UTILS_NULLANALYSISPRINTER_H
#define PHASAR_PHASARLLVM_UTILS_NULLANALYSISPRINTER_H

#include "phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h"

namespace psr {

template <typename AnalysisDomainTy>
class NullAnalysisPrinter final : public AnalysisPrinterBase<AnalysisDomainTy> {
public:
static NullAnalysisPrinter *getInstance() {
static auto Instance = NullAnalysisPrinter();
return &Instance;
}

void onInitialize() override{};
void onResult(Warning<AnalysisDomainTy> /*War*/) override{};
void onFinalize(llvm::raw_ostream & /*OS*/) const override{};

private:
NullAnalysisPrinter() = default;
};

} // namespace psr
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ void IDEExtendedTaintAnalysis::reportLeakIfNecessary(
const llvm::Value *LeakCandidate) {
if (isSink(SinkCandidate, Inst)) {
Leaks[Inst].insert(LeakCandidate);
Warning<IDEExtendedTaintAnalysisDomain> Warn(
Inst, makeFlowFact(LeakCandidate), Top{});
Printer->onResult(Warn);
}
}

Expand Down Expand Up @@ -744,19 +747,20 @@ auto IDEExtendedTaintAnalysis::getSummaryEdgeFunction(n_t Curr, d_t CurrNode,

void IDEExtendedTaintAnalysis::emitTextReport(
const SolverResults<n_t, d_t, l_t> &SR, llvm::raw_ostream &OS) {
OS << "===== IDEExtendedTaintAnalysis-Results =====\n";

if (!PostProcessed) {
doPostProcessing(SR);
}

for (auto &[Inst, LeakSet] : Leaks) {
OS << "At " << NToString(Inst) << '\n';
for (const auto &Leak : LeakSet) {
OS << "\t" << llvmIRToShortString(Leak) << "\n";
Warning<IDEExtendedTaintAnalysisDomain> Warn(Inst, makeFlowFact(Leak),
Top{});
Printer->onResult(Warn);
}
}
OS << '\n';

Printer->onFinalize(OS);
}

// Helpers:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h"

#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"

#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Value.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@
#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h"

#include "llvm/IR/IntrinsicInst.h"
#include "llvm/Support/raw_ostream.h"

#include <set>
#include <string>
#include <utility>
#include <vector>

#include <llvm/Support/raw_ostream.h>

namespace psr {

IFDSFieldSensTaintAnalysis::IFDSFieldSensTaintAnalysis(
Expand Down
33 changes: 12 additions & 21 deletions lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h"
#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h"
#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h"
#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h"
#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h"
#include "phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h"
#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h"
Expand Down Expand Up @@ -408,7 +409,11 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite,
return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, this,
CallSite](d_t Source) -> container_type {
if (Leak.count(Source)) {
Leaks[CallSite].insert(Source);
if (Leaks[CallSite].insert(Source).second) {
Warning<LLVMIFDSAnalysisDomainDefault> Warn(CallSite, Source,
topElement());
Printer->onResult(Warn);
}
}

if (Kill.count(Source)) {
Expand All @@ -433,7 +438,11 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite,
}

if (Leak.count(Source)) {
Leaks[CallSite].insert(Source);
if (Leaks[CallSite].insert(Source).second) {
Warning<LLVMIFDSAnalysisDomainDefault> Warn(CallSite, Source,
topElement());
Printer->onResult(Warn);
}
}

return {Source};
Expand Down Expand Up @@ -478,25 +487,7 @@ void IFDSTaintAnalysis::emitTextReport(
const SolverResults<n_t, d_t, BinaryDomain> & /*SR*/,
llvm::raw_ostream &OS) {
OS << "\n----- Found the following leaks -----\n";
if (Leaks.empty()) {
OS << "No leaks found!\n";
return;
}

for (const auto &Leak : Leaks) {
OS << "At instruction\nIR : " << llvmIRToString(Leak.first) << '\n';
OS << "\nLeak(s):\n";
for (const auto *LeakedValue : Leak.second) {
OS << "IR : ";
// Get the actual leaked alloca instruction if possible
if (const auto *Load = llvm::dyn_cast<llvm::LoadInst>(LeakedValue)) {
OS << llvmIRToString(Load->getPointerOperand()) << '\n';
} else {
OS << llvmIRToString(LeakedValue) << '\n';
}
}
OS << "-------------------\n";
}
Printer->onFinalize(OS);
}

} // namespace psr
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@

#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h"

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"

#include <string>

#include <llvm/ADT/STLExtras.h>

using namespace std;
using namespace psr;

Expand Down
Loading

0 comments on commit 1e9f3b7

Please sign in to comment.