From 73ae1b61495b88d4de66415fdb3522353409c1f4 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 24 Aug 2022 15:23:04 +0200 Subject: [PATCH 01/65] Add explicit ExplodedSuperGraph and a version of the IDESolver that fills it with content. TODO: Add PathSensitivityManager + unittests --- .../IfdsIde/ExplodedSuperGraph.h | 255 ++++++++++++++++++ .../IfdsIde/Solver/PathAwareIDESolver.h | 50 ++++ include/phasar/PhasarLLVM/Utils/Printer.h | 3 +- 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h new file mode 100644 index 0000000000..6d11838866 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h @@ -0,0 +1,255 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EXPLODEDSUPERGRAPH_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EXPLODEDSUPERGRAPH_H + +#include "phasar/PhasarLLVM/Utils/Printer.h" +#include "phasar/Utils/LLVMIRToSrc.h" +#include "phasar/Utils/StableVector.h" +#include "phasar/Utils/Utilities.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_os_ostream.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace psr { + +/// An explicit representation of the ExplodedSuperGraph (ESG) of an IFDS/IDE +/// analysis. +/// +/// Not all covered instructions of a BasicBlock might be present; however, it +/// is guaranteed that for each BasicBlock covered by the analysis there is at +/// least one node in the ExplicitESG containing an instruction from that BB. +template > +class ExplodedSuperGraph { +public: + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using container_type = Container; + + struct Node { + d_t Value{}; + n_t Source{}; + Node *Predecessor = nullptr; + llvm::TinyPtrVector Neighbors; + }; + + explicit ExplodedSuperGraph( + d_t ZeroValue, const psr::NodePrinter &NPrinter, + const psr::DataFlowFactPrinter + &DPrinter) noexcept(std::is_nothrow_move_constructible_v) + : ZeroValue(std::move(ZeroValue)), NPrinter(NPrinter), + DPrinter(DPrinter) {} + + [[nodiscard]] Node *getNodeOrNull(n_t Inst, d_t Fact) const { + auto It = FlowFactVertexMap.find( + std::make_pair(std::move(Inst), std::move(Fact))); + if (It != FlowFactVertexMap.end()) { + return It->second; + } + return nullptr; + } + + [[nodiscard]] const d_t &getZeroValue() const noexcept { return ZeroValue; } + + void saveEdges(n_t Curr, d_t CurrNode, n_t Succ, + const container_type &SuccNodes, bool /*IsInterProc*/) { + auto Pred = getNodeOrNull(Curr, std::move(CurrNode)); + for (const d_t &SuccNode : SuccNodes) { + saveEdge(Pred, Curr, CurrNode, Succ, SuccNode); + } + } + + // NOLINTNEXTLINE(readability-identifier-naming) + [[nodiscard]] auto node_begin() const noexcept { return NodeOwner.cbegin(); } + // NOLINTNEXTLINE(readability-identifier-naming) + [[nodiscard]] auto node_end() const noexcept { return NodeOwner.cend(); } + [[nodiscard]] auto nodes() const noexcept { + return llvm::make_range(node_begin(), node_end()); + } + + [[nodiscard]] size_t size() const noexcept { return NodeOwner.size(); } + + // LLVM_DUMP_METHOD void dump() const { node_owner.dump(llvm::errs()); } + + void validate(Node *Vtx) const noexcept { + + // NOLINTNEXTLINE(readability-identifier-naming) + auto toHexString = [](void *ptr) { + std::string Ret(2 + 2 * sizeof(void *), '\0'); + Ret.resize(snprintf(Ret.data(), Ret.size() + 1, "%p", ptr)); + return Ret; + }; + + if (!NodeOwner.member(Vtx)) { + llvm::report_fatal_error(llvm::StringRef("Vtx ") + toHexString(Vtx) + + " is no member of the NodeOwner!"); + } + + for (auto *NB : Vtx->Neighbors) { + if (!NodeOwner.member(NB)) { + llvm::report_fatal_error(llvm::StringRef("NB ") + toHexString(Vtx) + + " of Vtx " + toHexString(Vtx) + + " is no member of the NodeOwner!"); + } + } + + if (Vtx->Predecessor && !NodeOwner.member(Vtx->Predecessor)) { + llvm::report_fatal_error( + llvm::StringRef("Pred ") + toHexString(Vtx->Predecessor) + + " of Vtx " + toHexString(Vtx) + " is no member of the NodeOwner!"); + } + } + + /// Printing: + + void printAsDot(llvm::raw_ostream &OS) const { + OS << "digraph ESG{\n"; + psr::scope_exit ClosingBrace = [&OS] { OS << '}'; }; + + for (const auto &Nod : NodeOwner) { + + OS << intptr_t(&Nod) << "[label=\""; + OS.write_escaped(DPrinter.DtoString(Nod.value)) << "\"];\n"; + + OS << intptr_t(&Nod) << "->" << intptr_t(Nod.predecessor) + << "[style=\"bold\" label=\""; + OS.write_escaped(NPrinter.NtoString(Nod.source)) << "\"];\n"; + for (auto *NB : Nod.neighbors) { + OS << intptr_t(&Nod) << "->" << intptr_t(NB) << "[color=\"red\"];\n"; + } + } + } + + void printAsDot(std::ostream &OS) const { + llvm::raw_os_ostream ROS(OS); + printAsDot(ROS); + } + + void printESGNodes(llvm::raw_ostream &OS) const { + for (const auto &[Node, Vtx] : FlowFactVertexMap) { + OS << "( " << NPrinter.NtoString(Node.first) << "; " + << DPrinter.DtoString(Node.second) << " )\n"; + } + } + +private: + struct PathInfoHash { + size_t operator()(const std::pair &ND) const { + return std::hash()(ND.first) * 31 + std::hash()(ND.second); + } + }; + + struct PathInfoEq { + bool operator()(const std::pair &Lhs, + const std::pair &Rhs) const { + return Lhs.first == Rhs.first && Lhs.second == Rhs.second; + } + }; + + void saveEdge(Node *Pred, n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode, + bool DontSkip = false) { + auto &SuccVtx = FlowFactVertexMap[std::make_pair(Succ, SuccNode)]; + + // NOLINTNEXTLINE(readability-identifier-naming) + auto makeNode = [this, Pred, Curr, + SuccNode{std::move(SuccNode)}]() mutable { + auto Ret = &NodeOwner.emplace_back(); + Ret->Value = std::move(SuccNode); + Ret->Predecessor = Pred; + + Ret->Source = Curr; + return Ret; + }; + + if (!DontSkip && Pred && Pred->Value == SuccNode && + Pred->Source->getParent() == Succ->getParent() && + SuccNode != ZeroValue) { + + if (!SuccVtx) { + SuccVtx = Pred; + return; + } + + if (Pred == SuccVtx) { + return; + } + } + + if (!SuccVtx) { + SuccVtx = makeNode(); + return; + } + + /// Check for meaningless loop: + if (auto Br = llvm::dyn_cast(Curr); + SuccNode != ZeroValue && Br && !Br->isConditional()) { + auto Nod = Pred; + llvm::SmallPtrSet VisitedNodes; + while (Nod && Nod->Value == SuccNode) { + if (LLVM_UNLIKELY(!VisitedNodes.insert(Nod).second)) { + printAsDot(llvm::errs()); + llvm::errs().flush(); + abort(); + } + if (Nod == SuccVtx) { + llvm::errs() << "> saveEdge -- skip meaningless loop: (" + << NPrinter.NtoString(Curr) << ", " + << DPrinter.DtoString(CurrNode) << ") --> (" + << NPrinter.NtoString(Succ) << ", " + << DPrinter.DtoString(SuccNode) << ")\n"; + return; + } + Nod = Nod->Predecessor; + } + } + + if (SuccVtx->Predecessor != Pred && + llvm::none_of(SuccVtx->Neighbors, [Pred](const Node *Nd) { + return Nd->Predecessor == Pred; + })) { + SuccVtx->Neighbors.push_back(makeNode()); + return; + } + } + + std::pmr::unsynchronized_pool_resource MRes; + psr::StableVector NodeOwner; + std::pmr::unordered_map, Node *, PathInfoHash, PathInfoEq> + FlowFactVertexMap{&MRes}; + + // ZeroValue + d_t ZeroValue; + // References to Node and DataFlowFactPrinters required for visualizing the + // results + const psr::NodePrinter &NPrinter; + const psr::DataFlowFactPrinter &DPrinter; +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EXPLODEDSUPERGRAPH_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h new file mode 100644 index 0000000000..c65673e63b --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h @@ -0,0 +1,50 @@ +#pragma once + +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" +#include "phasar/Utils/Logger.h" + +namespace psr { +template > +class PathAwareIDESolver : public IDESolver { + using base_t = IDESolver; + +public: + using domain_t = AnalysisDomainTy; + using n_t = typename base_t::n_t; + using d_t = typename base_t::d_t; + using container_type = typename base_t::container_type; + + explicit PathAwareIDESolver( + IDETabulationProblem &Problem) + : base_t(Problem), ESG(Problem.getZeroValue(), Problem, Problem) { + + if (Problem.getIFDSIDESolverConfig().autoAddZero()) { + PHASAR_LOG_LEVEL( + WARNING, + "The PathAwareIDESolver is initialized with the option 'autoAddZero' " + "being set. This might degrade the quality of the computed paths!"); + } + } + + [[nodiscard]] const ExplodedSuperGraph & + getExplicitESG() const noexcept { + return ESG; + } + +private: + void saveEdges(n_t Curr, n_t Succ, d_t CurrNode, + const container_type &SuccNodes, bool IsInterProc) override { + ESG.saveEdges(Curr, CurrNode, Succ, SuccNodes, IsInterProc); + } + + ExplodedSuperGraph ESG; +}; + +template +PathAwareIDESolver(ProblemTy &) + -> PathAwareIDESolver; + +} // namespace psr diff --git a/include/phasar/PhasarLLVM/Utils/Printer.h b/include/phasar/PhasarLLVM/Utils/Printer.h index cdd8fc117e..b8a8a9b84b 100644 --- a/include/phasar/PhasarLLVM/Utils/Printer.h +++ b/include/phasar/PhasarLLVM/Utils/Printer.h @@ -17,8 +17,7 @@ #ifndef PHASAR_PHASARLLVM_UTILS_PRINTER_H_ #define PHASAR_PHASARLLVM_UTILS_PRINTER_H_ -#include -#include +#include "llvm/Support/raw_ostream.h" #include namespace psr { From b868728502dbf3a2de4db317d7876ce3501b87c6 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 24 Aug 2022 15:45:12 +0200 Subject: [PATCH 02/65] Add more TODOs --- .../IfdsIde/Solver/PathAwareIDESolver.h | 6 ++-- .../ExplodedSuperGraph.h | 16 ++++----- .../PathSensitivity/PathSensitivityManager.h | 36 +++++++++++++++++++ 3 files changed, 46 insertions(+), 12 deletions(-) rename include/phasar/PhasarLLVM/DataFlowSolver/{IfdsIde => PathSensitivity}/ExplodedSuperGraph.h (93%) create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h index c65673e63b..539dd11ab4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h @@ -1,8 +1,8 @@ #pragma once -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" #include "phasar/Utils/Logger.h" namespace psr { @@ -29,7 +29,7 @@ class PathAwareIDESolver : public IDESolver { } } - [[nodiscard]] const ExplodedSuperGraph & + [[nodiscard]] const ExplodedSuperGraph & getExplicitESG() const noexcept { return ESG; } @@ -40,7 +40,7 @@ class PathAwareIDESolver : public IDESolver { ESG.saveEdges(Curr, CurrNode, Succ, SuccNodes, IsInterProc); } - ExplodedSuperGraph ESG; + ExplodedSuperGraph ESG; }; template diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h rename to include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h index 6d11838866..b8db257800 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/ExplodedSuperGraph.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EXPLODEDSUPERGRAPH_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EXPLODEDSUPERGRAPH_H +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H #include "phasar/PhasarLLVM/Utils/Printer.h" #include "phasar/Utils/LLVMIRToSrc.h" @@ -43,13 +43,10 @@ namespace psr { /// Not all covered instructions of a BasicBlock might be present; however, it /// is guaranteed that for each BasicBlock covered by the analysis there is at /// least one node in the ExplicitESG containing an instruction from that BB. -template > -class ExplodedSuperGraph { +template class ExplodedSuperGraph { public: using n_t = typename AnalysisDomainTy::n_t; using d_t = typename AnalysisDomainTy::d_t; - using container_type = Container; struct Node { d_t Value{}; @@ -76,8 +73,9 @@ class ExplodedSuperGraph { [[nodiscard]] const d_t &getZeroValue() const noexcept { return ZeroValue; } - void saveEdges(n_t Curr, d_t CurrNode, n_t Succ, - const container_type &SuccNodes, bool /*IsInterProc*/) { + template + void saveEdges(n_t Curr, d_t CurrNode, n_t Succ, const Container &SuccNodes, + bool /*IsInterProc*/) { auto Pred = getNodeOrNull(Curr, std::move(CurrNode)); for (const d_t &SuccNode : SuccNodes) { saveEdge(Pred, Curr, CurrNode, Succ, SuccNode); @@ -252,4 +250,4 @@ class ExplodedSuperGraph { } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EXPLODEDSUPERGRAPH_H +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h new file mode 100644 index 0000000000..4d31319fb0 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h @@ -0,0 +1,36 @@ +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H + +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" + +#include + +namespace psr { +template class PathSensitivityManager { + + static ExplodedSuperGraph & + assertNotNull(ExplodedSuperGraph *ESG) noexcept { + assert(ESG != nullptr && "The exploded supergraph passed to the " + "pathSensitivityManager must not be nullptr!"); + return *ESG; + } + +public: + PathSensitivityManager( + const ExplodedSuperGraph *ESG) noexcept + : ESG(assertNotNull(ESG)) {} + + /// TODO: Add graph_type + /// TODO: Add PathBuilder + /// TODO: Add LLVMPathConstraints + + /// TODO: graph_type pathsDagTo(n_t, d_t) + + /// TODO: FlowPathSequence pathsTo(n_t, d_t) + +private: + const ExplodedSuperGraph &ESG; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H From 709405e39610f8e46bb762d768fb906af2971208 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 24 Aug 2022 16:29:21 +0200 Subject: [PATCH 03/65] Add GraphTraits --- .../PathSensitivity/ExplodedSuperGraph.h | 2 +- .../PathSensitivity/PathSensitivityManager.h | 10 +- include/phasar/Utils/AdjacencyList.h | 194 ++++++++++++++++++ include/phasar/Utils/GraphTraits.h | 164 +++++++++++++++ include/phasar/Utils/RepeatIterator.h | 72 +++++++ include/phasar/Utils/TypeTraits.h | 22 +- 6 files changed, 457 insertions(+), 7 deletions(-) create mode 100644 include/phasar/Utils/AdjacencyList.h create mode 100644 include/phasar/Utils/GraphTraits.h create mode 100644 include/phasar/Utils/RepeatIterator.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h index b8db257800..17113bd909 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h @@ -135,7 +135,7 @@ template class ExplodedSuperGraph { OS.write_escaped(DPrinter.DtoString(Nod.value)) << "\"];\n"; OS << intptr_t(&Nod) << "->" << intptr_t(Nod.predecessor) - << "[style=\"bold\" label=\""; + << R"([style="bold" label=")"; OS.write_escaped(NPrinter.NtoString(Nod.source)) << "\"];\n"; for (auto *NB : Nod.neighbors) { OS << intptr_t(&Nod) << "->" << intptr_t(NB) << "[color=\"red\"];\n"; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h index 4d31319fb0..160ac79486 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h @@ -2,6 +2,7 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" +#include "phasar/Utils/AdjacencyList.h" #include @@ -16,15 +17,20 @@ template class PathSensitivityManager { } public: + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using graph_type = AdjacencyList>; + PathSensitivityManager( const ExplodedSuperGraph *ESG) noexcept : ESG(assertNotNull(ESG)) {} - /// TODO: Add graph_type /// TODO: Add PathBuilder /// TODO: Add LLVMPathConstraints - /// TODO: graph_type pathsDagTo(n_t, d_t) + graph_type pathsDagTo(n_t Inst, d_t Fact) const { + /// TODO: implement + } /// TODO: FlowPathSequence pathsTo(n_t, d_t) diff --git a/include/phasar/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h new file mode 100644 index 0000000000..b689879b46 --- /dev/null +++ b/include/phasar/Utils/AdjacencyList.h @@ -0,0 +1,194 @@ +#pragma once + +#include "phasar/Utils/GraphTraits.h" +#include "phasar/Utils/RepeatIterator.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" + +#include +#include + +namespace psr { + +template struct AdjacencyList { + llvm::SmallVector Nodes{}; + llvm::SmallVector, 0> Adj{}; + llvm::SmallVector Roots{}; +}; + +template struct AdjacencyList { + llvm::SmallVector, 0> Adj{}; + llvm::SmallVector Roots{}; +}; + +template +struct GraphTraits> { + using graph_type = AdjacencyList; + using value_type = T; + using vertex_t = unsigned; + using edge_t = EdgeTy; + + static inline constexpr auto Invalid = std::numeric_limits::max(); + + template >> + static vertex_t addNode(graph_type &G, TT &&Val) { + assert(G.Adj.size() == G.Nodes.size()); + + auto Ret = G.Nodes.size(); + G.Nodes.push_back(std::forward(Val)); + G.Adj.emplace_back(); + return Ret; + } + + template >> + static vertex_t addNode(graph_type &G, llvm::NoneType /*Val*/ = llvm::None) { + auto Ret = G.Adj.size(); + G.Adj.emplace_back(); + return Ret; + } + + static void addRoot(graph_type &G, vertex_t Vtx) { + if constexpr (!std::is_same_v) { + assert(Vtx < G.Nodes.size()); + assert(G.Adj.size() == G.Nodes.size()); + } + G.Roots.push_back(Vtx); + } + + static llvm::ArrayRef roots(const graph_type &G) noexcept { + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + return G.Roots; + } + + static void addEdge(graph_type &G, vertex_t From, edge_t To) { + assert(From < G.Adj.size()); + if constexpr (!std::is_same_v) { + assert(B.Adj.size() == G.Nodes.size()); + } + G.Adj[From].push_back(std::move(To)); + } + + static llvm::ArrayRef outEdges(const graph_type &G, + vertex_t Vtx) noexcept { + if constexpr (!std::is_same_v) { + assert(Vtx < G.Nodes.size()); + assert(G.Adj.size() == G.Nodes.size()); + } + return G.Adj[Vtx]; + } + + static size_t outDegree(const graph_type &G, vertex_t Vtx) noexcept { + if constexpr (!std::is_same_v) { + assert(Vtx < G.Nodes.size()); + assert(G.Adj.size() == G.Nodes.size()); + } + return G.Adj[Vtx].size(); + } + + static void dedupOutEdges(graph_type &G, vertex_t Vtx) noexcept { + if constexpr (!std::is_same_v) { + assert(Vtx < G.Nodes.size()); + assert(G.Adj.size() == G.Nodes.size()); + } + auto &OutEdges = G.Adj[Vtx]; + std::sort(OutEdges.begin(), OutEdges.end()); + OutEdges.erase(std::unique(OutEdges.begin(), OutEdges.end()), + OutEdges.end()); + } + + template >> + static llvm::ArrayRef nodes(const graph_type &G) noexcept { + assert(G.Adj.size() == G.Nodes.size()); + return G.Nodes; + } + template + static std::enable_if_t, + llvm::MutableArrayRef> + nodes(graph_type &G) noexcept { + assert(G.Adj.size() == G.Nodes.size()); + return G.Nodes; + } + template >> + static std::enable_if_t, + RepeatRangeType> + nodes(const graph_type &G) noexcept { + return repeat(llvm::None, G.Adj.size()); + } + + template >> + static const value_type &node(const graph_type &G, vertex_t Vtx) noexcept { + assert(Vtx < G.Nodes.size()); + assert(G.Adj.size() == G.Nodes.size()); + return G.Nodes[Vtx]; + } + template >> + static value_type &node(graph_type &G, vertex_t Vtx) noexcept { + assert(Vtx < G.Nodes.size()); + assert(G.Adj.size() == G.Nodes.size()); + return G.Nodes[Vtx]; + } + + template >> + static llvm::NoneType node([[maybe_unused]] const graph_type &G, + [[maybe_unused]] vertex_t Vtx) noexcept { + assert(Vtx < G.Adj.size()); + return llvm::None; + } + + static size_t size(const graph_type &G) noexcept { + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + return G.Adj.size(); + } + + static void reserve(graph_type &G, size_t Capacity) { + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + G.Nodes.reserve(Capacity); + } + + G.Adj.reserve(Capacity); + } + + static bool pop(graph_type &G, vertex_t Vtx) { + if (Vtx == G.Adj.size() - 1) { + G.Adj.pop_back(); + if constexpr (!std::is_same_v) { + G.Nodes.pop_back(); + } + return true; + } + return false; + } + + template + static std::enable_if_t, vertex_t> + target(edge_t Edge) noexcept { + return Edge; + } + + template + static std::enable_if_t, edge_t> + withEdgeTarget(edge_t /*edge*/, vertex_t Tar) noexcept { + return Tar; + } + +#if __cplusplus >= 202002L + static_assert(is_graph>); + static_assert(is_reservable_graph_trait>>); +#endif +}; + +} // namespace psr diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h new file mode 100644 index 0000000000..570e7ddd0c --- /dev/null +++ b/include/phasar/Utils/GraphTraits.h @@ -0,0 +1,164 @@ +#pragma once + +#include "phasar/Utils/TypeTraits.h" +#include "phasar/Utils/Utilities.h" + +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +namespace psr { + +template struct GraphTraits; + +#if __cplusplus >= 202002L + +template +concept is_graph_edge = requires(const Edge e1, Edge e2) { + { e1 == e2 } -> std::convertible_to; + { e1 != e2 } -> std::convertible_to; + { e1 < e2 } -> std::convertible_to; +}; + +template +concept is_graph_trait = requires(typename GraphTrait::graph_type &graph, + const typename GraphTrait::graph_type &cgraph, + typename GraphTrait::value_type val, + typename GraphTrait::vertex_t vtx, + typename GraphTrait::edge_t edge) { + typename GraphTrait::graph_type; + typename GraphTrait::value_type; + typename GraphTrait::vertex_t; + typename GraphTrait::edge_t; + requires is_graph_edge; + { GraphTrait::Invalid } -> std::convertible_to; + { + GraphTrait::addNode(graph, val) + } -> std::convertible_to; + {GraphTrait::addEdge(graph, vtx, edge)}; + { + GraphTrait::outEdges(cgraph, vtx) + } -> psr::is_iterable_over_v; + { GraphTrait::outDegree(cgraph, vtx) } -> std::convertible_to; + {GraphTrait::dedupOutEdges(graph, vtx)}; + { + GraphTrait::nodes(cgraph) + } -> psr::is_iterable_over_v; + { + GraphTrait::node(cgraph, vtx) + } -> std::convertible_to; + { GraphTrait::size(cgraph) } -> std::convertible_to; + {GraphTrait::addRoot(graph, vtx)}; + { + GraphTrait::roots(cgraph) + } -> psr::is_iterable_over_v; + { GraphTrait::pop(graph, vtx) } -> std::same_as; + { + GraphTrait::target(edge) + } -> std::convertible_to; + { + GraphTrait::withEdgeTarget(edge, vtx) + } -> std::convertible_to; +}; + +template +concept is_graph = requires(Graph g) { + typename GraphTraits>; + requires is_graph_trait>>; +}; + +template +concept is_reservable_graph_trait_v = is_graph_trait && + requires(typename GraphTrait::graph_type &g) { + {GraphTrait::reserve(g, size_t(0))}; +}; + +#else +namespace detail { +template +// NOLINTNEXTLINE(readability-identifier-naming) +struct is_reservable_graph_trait : std::false_type {}; +template +struct is_reservable_graph_trait< + GraphTrait, + std::void_t(), size_t()))>> + : std::true_type {}; +} // namespace detail + +template +// NOLINTNEXTLINE(readability-identifier-naming) +static constexpr bool is_reservable_graph_trait_v = + detail::is_reservable_graph_trait::value; +#endif + +template +std::decay_t reverseGraph(GraphTy &&G) +#if __cplusplus >= 202002L + requires is_graph +#endif +{ + std::decay_t Ret; + using traits_t = GraphTraits>; + if constexpr (is_reservable_graph_trait_v) { + traits_t::reserve(Ret, traits_t::size(G)); + } + + for (auto &Nod : traits_t::nodes(G)) { + /// NOTE: in case of a const reference, nod will be const as well preventing + /// moving + traits_t::addNode(Ret, std::move(Nod)); + } + + for (size_t I = 0, End = traits_t::size(G); I != End; ++I) { + for (auto Child : traits_t::outEdges(G, I)) { + traits_t::addEdge(Ret, traits_t::target(Child), + traits_t::withEdgeTarget(Child, I)); + } + if (traits_t::outDegree(G, I) == 0) { + traits_t::addRoot(Ret, I); + } + } + return Ret; +} + +template +void printGraph(const GraphTy &G, llvm::raw_ostream &OS, + llvm::StringRef Name = "") +#if __cplusplus >= 202002L + requires is_graph +#endif +{ + using traits_t = GraphTraits; + + OS << "digraph " << Name << " {\n"; + psr::scope_exit CloseBrace = [&OS] { OS << "}\n"; }; + + auto Sz = traits_t::size(G); + std::string Buf; + + for (size_t I = 0; I < Sz; ++I) { + OS << I; + if constexpr (!std::is_same_v) { + OS << "[label=\""; + + Buf.clear(); + llvm::raw_string_ostream ROS(Buf); + ROS << traits_t::node(G, I); + OS.write_escaped(ROS.str()); + OS << "\"]"; + } + OS << ";\n"; + for (const auto &Edge : traits_t::outEdges(G, I)) { + OS << I << "->" << Edge << ";\n"; + } + } +} + +} // namespace psr diff --git a/include/phasar/Utils/RepeatIterator.h b/include/phasar/Utils/RepeatIterator.h new file mode 100644 index 0000000000..e2113b923d --- /dev/null +++ b/include/phasar/Utils/RepeatIterator.h @@ -0,0 +1,72 @@ +#pragma once + +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/iterator_range.h" + +#include +#include +#include +#include + +namespace psr { +/// An iterator that iterates over the same value a specified number of times +template class RepeatIterator { +public: + using value_type = T; + using reference = const T &; + using pointer = const T *; + using difference_type = ptrdiff_t; + using iterator_category = std::input_iterator_tag; + + reference operator*() const noexcept { + assert(elem.has_value() && "Dereferencing end()-iterator"); + return *Elem; + } + pointer operator->() const noexcept { + assert(elem.has_value() && "Dereferencing end()-iterator"); + return &*Elem; + } + + RepeatIterator &operator++() noexcept { + ++Index; + return *this; + } + RepeatIterator operator++(int) noexcept { + auto Ret = *this; + ++*this; + return Ret; + } + + bool operator==(const RepeatIterator &Other) const noexcept { + return Other.Index == Index; + } + bool operator!=(const RepeatIterator &Other) const noexcept { + return !(*this == Other); + } + + template >>> + explicit RepeatIterator(TT &&Elem) : Elem(std::forward(Elem)) {} + explicit RepeatIterator(size_t Index, std::true_type /*AsEndIterator*/) + : Index(Index), Elem(std::nullopt) {} + + RepeatIterator() noexcept = default; + +private: + size_t Index{}; + std::optional Elem{}; +}; + +template +using RepeatRangeType = llvm::iterator_range>; +template auto repeat(T &&Elem, size_t Num) { + using iterator_type = RepeatIterator>; + auto Ret = llvm::make_range(iterator_type(std::forward(Elem)), + iterator_type(Num, std::true_type{})); + return Ret; +} + +static_assert(is_iterable_over_v, int>); + +} // namespace psr diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 6f1ee8281f..95e6f63722 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -16,6 +16,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" namespace psr { @@ -25,9 +26,18 @@ namespace detail { template struct is_iterable : public std::false_type {}; // NOLINT template -struct is_iterable().begin()), - decltype(std::declval().end())>> +struct is_iterable())), + decltype(llvm::adl_end(std::declval()))>> + : public std::true_type {}; + +template +struct is_iterable_over : std::false_type {}; // NOLINT +template +struct is_iterable_over< + T, U, + std::enable_if_t::value && + std::is_same_v()))>>>> : public std::true_type {}; template struct is_pair : public std::false_type {}; // NOLINT @@ -77,7 +87,7 @@ struct is_llvm_hashable()))> // NOLINT : std::true_type {}; template -struct has_setIFDSIDESolverConfig : std::false_type {}; +struct has_setIFDSIDESolverConfig : std::false_type {}; // NOLINT template struct has_setIFDSIDESolverConfig< T, decltype(std::declval().setIFDSIDESolverConfig( @@ -88,6 +98,10 @@ struct has_setIFDSIDESolverConfig< template constexpr bool is_iterable_v = detail::is_iterable::value; // NOLINT +template +constexpr bool is_iterable_over_v = // NOLINT + detail::is_iterable_over::value; // NOLINT + template constexpr bool is_pair_v = detail::is_pair::value; // NOLINT From 3d9df06c20da9d8d05247d51ee7d30518ff42492 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 25 Aug 2022 13:00:23 +0200 Subject: [PATCH 04/65] Add pathsDagTo (not tested yet) --- .../PathSensitivity/PathSensitivityConfig.h | 44 +++ .../PathSensitivity/PathSensitivityManager.h | 270 +++++++++++++++++- include/phasar/Utils/AdjacencyList.h | 26 +- include/phasar/Utils/DFAMinimizer.h | 130 +++++++++ include/phasar/Utils/GraphTraits.h | 32 ++- include/phasar/Utils/IotaIterator.h | 73 +++++ include/phasar/Utils/RepeatIterator.h | 16 +- include/phasar/Utils/Utilities.h | 11 + 8 files changed, 591 insertions(+), 11 deletions(-) create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h create mode 100644 include/phasar/Utils/DFAMinimizer.h create mode 100644 include/phasar/Utils/IotaIterator.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h new file mode 100644 index 0000000000..a19117b684 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h @@ -0,0 +1,44 @@ +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H + +#include +#include + +namespace psr { +struct PathSensitivityConfig { + size_t DAGSizeThreshold = SIZE_MAX; + size_t DAGDepthThreshold = SIZE_MAX; + size_t NumPathsThreshold = SIZE_MAX; + bool MinimizeDAG = true; + + [[nodiscard]] PathSensitivityConfig + withDAGSizeThreshold(size_t MaxDAGSize) const noexcept { + auto Ret = *this; + Ret.DAGSizeThreshold = MaxDAGSize; + return Ret; + } + + [[nodiscard]] PathSensitivityConfig + withDAGDepthThreshold(size_t MaxDAGDepth) const noexcept { + auto Ret = *this; + Ret.DAGDepthThreshold = MaxDAGDepth; + return Ret; + } + + [[nodiscard]] PathSensitivityConfig + withNumPathsThreshold(size_t MaxNumPaths) const noexcept { + auto Ret = *this; + Ret.NumPathsThreshold = MaxNumPaths; + return Ret; + } + + [[nodiscard]] PathSensitivityConfig + withMinimizeDAG(bool DoMinimize) const noexcept { + auto Ret = *this; + Ret.MinimizeDAG = DoMinimize; + return Ret; + } +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h index 160ac79486..461f1388d4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h @@ -2,9 +2,18 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" #include "phasar/Utils/AdjacencyList.h" +#include "phasar/Utils/DFAMinimizer.h" +#include "phasar/Utils/GraphTraits.h" +#include "phasar/Utils/Logger.h" + +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" #include +#include namespace psr { template class PathSensitivityManager { @@ -21,6 +30,8 @@ template class PathSensitivityManager { using d_t = typename AnalysisDomainTy::d_t; using graph_type = AdjacencyList>; + static_assert(std::is_integral_v::vertex_t>); + PathSensitivityManager( const ExplodedSuperGraph *ESG) noexcept : ESG(assertNotNull(ESG)) {} @@ -28,13 +39,268 @@ template class PathSensitivityManager { /// TODO: Add PathBuilder /// TODO: Add LLVMPathConstraints - graph_type pathsDagTo(n_t Inst, d_t Fact) const { - /// TODO: implement + graph_type pathsDagTo(n_t Inst, d_t Fact, + const PathSensitivityConfig &Config = {}) const { + auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); + + if (!Nod) { + llvm::report_fatal_error( + "Invalid Instruction-FlowFact pair. Only use those pairs that are " + "part of the IDE analysis results!"); + } + + graph_type Dag; + auto Rt = pathsToImpl(Inst, Nod, Dag); + graph_traits_t::addRoot(Dag, Rt); + +#ifndef NDEBUG + if (!assertIsDAG(Dag)) { + llvm::report_fatal_error("Invariant violated: DAG has a circle in it!"); + } else { + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + "The DAG indeed has no circles"); + } +#endif + + if (Config.MinimizeDAG) { + auto Equiv = minimizeGraph(Dag); + Dag = reverseDAG(std::move(Dag), Equiv); + } else { + Dag = reverseGraph(std::move(Dag)); + } + + /// TODO: assertIsDAG + minimizeDAG + reverseDAG + + return Dag; } /// TODO: FlowPathSequence pathsTo(n_t, d_t) private: + using Node = typename ExplodedSuperGraph::Node; + using graph_traits_t = GraphTraits; + using vertex_t = typename graph_traits_t::vertex_t; + + struct PathsToContext { + llvm::DenseMap Cache; + llvm::SetVector> CurrPath; + }; + + bool pathsToImplLAInvoke(vertex_t Ret, Node *Vtx, PathsToContext &Ctx, + graph_type &RetDag, bool AutoSkipZero) { + + // NOLINTNEXTLINE(readability-identifier-naming) + auto reachedEnd = [this, AutoSkipZero](Node *Vtx) { + return !Vtx || (AutoSkipZero && Vtx->Value == ESG.getZeroValue()); + }; + + do { + graph_traits_t::node(RetDag, Ret).push_back(Vtx->Source); + Vtx = Vtx->Predecessor; + } while (!reachedEnd(Vtx) && Vtx->Neighbors.empty()); + + if (reachedEnd(Vtx)) { + return true; + } + + if (!Ctx.CurrPath.insert(Ret)) { + PHASAR_LOG_LEVEL(ERROR, "Node " << Ret << " already on path"); + return false; + } + scope_exit PopRet = [&Ctx] { Ctx.CurrPath.pop_back(); }; + + // NOLINTNEXTLINE(readability-identifier-naming) + auto traverseNext = [&Ctx, this, Ret, &RetDag, AutoSkipZero](Node *Nxt) { + auto Succ = pathsToImplLA(Nxt, Ctx, RetDag, AutoSkipZero); + if (Succ != graph_traits_t::Invalid && !Ctx.CurrPath.contains(Succ)) { + graph_traits_t::addEdge(RetDag, Ret, Succ); + } + }; + + for (auto Nxt : Vtx->Neighbors) { + traverseNext(Nxt); + } + + traverseNext(Vtx); + + graph_traits_t::dedupOutEdges(RetDag, Ret); + + return graph_traits_t::outDegree(RetDag, Ret) != 0; + } + + vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, graph_type &RetDag, + bool AutoSkipZero) { + /// Idea: Treat the graph as firstChild-nextSibling notation and always + /// traverse with one predecessor lookAhead + + auto [It, Inserted] = Ctx.Cache.try_emplace(Vtx, graph_traits_t::Invalid); + if (!Inserted) { + return It->second; + } + + auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); + // auto Ret = RetDag.addNode(); + It->second = Ret; + + if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag, AutoSkipZero)) { + /// NOTE: Don't erase Vtx from Cache to guarantee termination + Ctx.Cache[Vtx] = graph_traits_t::Invalid; + + if (Ctx.CurrPath.contains(Ret) || !graph_traits_t::pop(RetDag, Ret)) { + PHASAR_LOG_LEVEL(WARNING, "Cannot remove invalid path at: " << Ret); + graph_traits_t::node(RetDag, Ret).clear(); + } + + // if (RetDag.isLast(Ret) && !Ctx.CurrPath.contains(Ret)) { + // /// Assume, Ret is not referenced by any other node + // RetDag.pop(); + // } else { + // PHASAR_LOG_LEVEL(WARNING, << "Cannot remove invalid path at: " << + // Ret); RetDag.PartialPath[Ret].clear(); + // } + + return graph_traits_t::Invalid; + } + return Ret; + } + + vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag, + bool AutoSkipZero) { + assert(Vtx->Source != QueryInst); + + auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); + graph_traits_t::node(RetDag, Ret).push_back(QueryInst); + // RetDag.PartialPath[Ret].push_back(QueryInst); + + PathsToContext Ctx; + + for (auto *NB : Vtx->Neighbors) { + auto NBNode = pathsToImplLA(NB, Ctx, RetDag, AutoSkipZero); + if (NBNode != graph_traits_t::Invalid) { + graph_traits_t::addEdge(RetDag, Ret, NBNode); + // Succs.push_back(NBNode); + } + } + auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag, AutoSkipZero); + if (VtxNode != graph_traits_t::Invalid) { + graph_traits_t::addEdge(RetDag, Ret, VtxNode); + // Succs.push_back(VtxNode); + } + + graph_traits_t::dedupOutEdges(RetDag, Ret); + + /// Deduplicate the successors relation + // std::sort(Succs.begin(), Succs.end()); + // Succs.erase(std::unique(Succs.begin(), Succs.end()), Succs.end()); + + // RetDag.Successors[Ret] = std::move(Succs); + return Ret; + } + + bool assertIsDAG(const graph_type &Dag) { + llvm::BitVector Visited(Dag.size()); + llvm::DenseSet CurrPath; + CurrPath.reserve(graph_traits_t::size(Dag)); + + // NOLINTNEXTLINE(readability-identifier-naming) + auto doAssertIsDAG = [&CurrPath, &Visited, &Dag](auto &doAssertIsDAG, + vertex_t Vtx) { + if (!CurrPath.insert(Vtx).second) { + PHASAR_LOG_LEVEL(ERROR, "DAG has circle: Vtx: " << uintptr_t(Vtx)); + return false; + } + + scope_exit CurrPathPop = [&CurrPath, Vtx] { CurrPath.erase(Vtx); }; + if (Visited.test(Vtx)) { + /// We have already analyzed this node + /// NOTE: We must check this _after_ doing the circle check. Otherwise, + /// that can never be true + return true; + } + + Visited.set(Vtx); + + for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { + if (!doAssertIsDAG(doAssertIsDAG, Succ)) { + return false; + } + } + return true; + }; + + return doAssertIsDAG(doAssertIsDAG, Dag.Root); + } + + graph_type reverseDAG(graph_type &&Dag, const llvm::IntEqClasses &Equiv, + size_t MaxDepth = SIZE_MAX) { + + struct ReverseDAGContext { + llvm::SmallVector Cache; + size_t CurrDepth = 0; + size_t MaxDepth = 0; + } Ctx; + + Ctx.Cache.resize(Equiv.getNumClasses(), graph_traits_t::Invalid); + Ctx.MaxDepth = MaxDepth; + + graph_type Ret{}; + // Ret.Dag = &Dag; + // Ret.Leaf = Equiv[Dag.Root]; + if constexpr (is_reservable_graph_trait_v) { + graph_traits_t::reserve(Ret, Equiv.getNumClasses()); + } + // Ret.Adj.reserve(Equiv.getNumClasses()); + // Ret.Rev2Vtx.reserve(Equiv.getNumClasses()); + + // NOLINTNEXTLINE(readability-identifier-naming) + auto buildReverseDag = [&Ctx, &Ret, &Equiv, &Dag](auto &buildReverseDag, + vertex_t Vtx) { + auto Eq = Equiv[Vtx]; + if (Ctx.Cache[Eq] != graph_traits_t::Invalid) { + return Ctx.Cache[Eq]; + } + + // typename ReverseDAG::vertex_t Rev = Ret.size(); + // Ret.Rev2Vtx.push_back(Vtx); + // Ret.Adj.emplace_back(); + auto Rev = graph_traits_t::addNode( + Ret, std::move(graph_traits_t::node(Dag, Vtx))); + Ctx.Cache[Eq] = Rev; + + if (Ctx.CurrDepth >= Ctx.MaxDepth) { + graph_traits_t::addRoot(Ret, Rev); + // Ret.Roots.push_back(Rev); + return Rev; + } + + ++Ctx.CurrDepth; + scope_exit DecreaseDepth = [&Ctx] { --Ctx.CurrDepth; }; + + for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { + /// NOTE: Depending on the depth of SuccRev, we can still get DAGs + /// deeper than MaxDepth! + /// However, this is not considered harmful as of now - the DAG still + /// does not exceed a particular program-slice which size is fixed + auto SuccRev = + buildReverseDag(buildReverseDag, graph_traits_t::target(Succ)); + graph_traits_t::addEdge(Ret, SuccRev, + graph_traits_t::withEdgeTarget(Succ, Rev)); + // Ret.Adj[SuccRev].push_back(Rev); + } + + if (graph_traits_t::outDegree(Dag, Vtx) == 0) { + graph_traits_t::addRoot(Ret, Rev); + // Ret.Roots.push_back(Rev); + } + + return Rev; + }; + + buildReverseDag(buildReverseDag, Dag.Root); + + return Ret; + } + const ExplodedSuperGraph &ESG; }; } // namespace psr diff --git a/include/phasar/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h index b689879b46..d24bc67d7d 100644 --- a/include/phasar/Utils/AdjacencyList.h +++ b/include/phasar/Utils/AdjacencyList.h @@ -1,6 +1,17 @@ -#pragma once +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel + *****************************************************************************/ + +#ifndef PHASAR_UTILS_ADJACENCYLIST_H +#define PHASAR_UTILS_ADJACENCYLIST_H #include "phasar/Utils/GraphTraits.h" +#include "phasar/Utils/IotaIterator.h" #include "phasar/Utils/RepeatIterator.h" #include "llvm/ADT/ArrayRef.h" @@ -123,6 +134,13 @@ struct GraphTraits> { return repeat(llvm::None, G.Adj.size()); } + static auto vertices(const graph_type &G) noexcept { + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + return psr::iota(0, G.Adj.size()); + } + template >> static const value_type &node(const graph_type &G, vertex_t Vtx) noexcept { @@ -185,6 +203,10 @@ struct GraphTraits> { return Tar; } + static llvm::NoneType weight(edge_t /*unused*/) noexcept { + return llvm::None; + } + #if __cplusplus >= 202002L static_assert(is_graph>); static_assert(is_reservable_graph_trait>>); @@ -192,3 +214,5 @@ struct GraphTraits> { }; } // namespace psr + +#endif // PHASAR_UTILS_ADJACENCYLIST_H diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h new file mode 100644 index 0000000000..7443fef26a --- /dev/null +++ b/include/phasar/Utils/DFAMinimizer.h @@ -0,0 +1,130 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel + *****************************************************************************/ + +#ifndef PHASAR_UTILS_DFAMINIMIZER_H +#define PHASAR_UTILS_DFAMINIMIZER_H + +#include "phasar/Utils/GraphTraits.h" +#include "phasar/Utils/Logger.h" + +#include "llvm/ADT/IntEqClasses.h" + +namespace psr { + +template +[[nodiscard]] llvm::IntEqClasses minimizeGraph(const GraphTy &G) +#if __cplusplus >= 202002L + requires is_graph +#endif +{ + + using traits_t = GraphTraits; + using vertex_t = typename traits_t::vertex_t; + using edge_t = typename traits_t::edge_t; + + auto DagSize = G.size(); + llvm::SmallVector> WorkList; + WorkList.reserve(DagSize); + + const auto &Vertices = traits_t::vertices(G); + + for (auto VtxBegin = Vertices.begin(), VtxEnd = Vertices.end(); + VtxBegin != VtxEnd; ++VtxBegin) { + for (auto Inner = std::next(VtxBegin); Inner != VtxEnd; ++Inner) { + if (traits_t::node(G, *VtxBegin) == traits_t::node(G, *Inner) && + traits_t::outDegree(G, *VtxBegin) == traits_t::outDegree(G, *Inner)) { + WorkList.emplace_back(*VtxBegin, *Inner); + } + } + } + + size_t Idx = 0; + + llvm::IntEqClasses Equiv(traits_t::size(G)); + + auto isEquivalent = [&Equiv](edge_t LHS, edge_t RHS) { + if (traits_t::weight(LHS) != traits_t::weight(RHS)) { + return false; + } + + if (traits_t::target(LHS) == traits_t::target(RHS)) { + return true; + } + + return Equiv.findLeader(traits_t::target(LHS)) == + Equiv.findLeader(traits_t::target(RHS)); + }; + + auto makeEquivalent = [&Equiv](vertex_t LHS, vertex_t RHS) { + if (LHS == RHS) { + return; + } + + Equiv.join(LHS, RHS); + }; + + auto removeAt = [&WorkList](size_t I) { + std::swap(WorkList[I], WorkList.back()); + WorkList.pop_back(); + return I - 1; + }; + + /// NOTE: This algorithm can be further optimized, but for now it is fast + /// enough + + bool Changed = true; + while (Changed) { + Changed = false; + for (size_t I = 0; I < WorkList.size(); ++I) { + auto [LHS, RHS] = WorkList[I]; + bool Eq = true; + for (auto [LSucc, RSucc] : + llvm::zip(traits_t::outEdges(G, LHS), traits_t::outEdges(G, RHS))) { + if (!isEquivalent(traits_t::target(LSucc), traits_t::target(RSucc))) { + Eq = false; + break; + } + } + + if (Eq) { + makeEquivalent(LHS, RHS); + I = removeAt(I); + Changed = true; + continue; + } + + if (traits_t::outDegree(G, LHS) == 2) { + auto LFirst = *traits_t::outEdges(G, LHS).begin(); + auto LSecond = *std::next(traits_t::outEdges(G, LHS).begin()); + auto RFirst = *traits_t::outEdges(G, RHS).begin(); + auto RSecond = *std::next(traits_t::outEdges(G, RHS).begin()); + + if (isEquivalent(LFirst, RSecond) && isEquivalent(LSecond, RFirst)) { + makeEquivalent(LHS, RHS); + I = removeAt(I); + Changed = true; + continue; + } + } + } + } + + Equiv.compress(); + + PHASAR_LOG_LEVEL_CAT(DEBUG, "GraphTraits", + "> Computed " << Equiv.getNumClasses() + << " Equivalence classes for " << DagSize + << " nodes"); + + return Equiv; +} + +} // namespace psr + +#endif // PHASAR_UTILS_DFAMINIMIZER_H diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index 570e7ddd0c..2fc9d733b5 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -1,4 +1,14 @@ -#pragma once +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel + *****************************************************************************/ + +#ifndef PHASAR_UTILS_GRAPHTRAITS_H +#define PHASAR_UTILS_GRAPHTRAITS_H #include "phasar/Utils/TypeTraits.h" #include "phasar/Utils/Utilities.h" @@ -14,6 +24,12 @@ namespace psr { +/// We aim to get rid of boost, so introduce a new GraphTraits class to replace +/// it. +/// This GraphTraits type should be specialized for each typy that should +/// implement a "graph". All the functionality should be reflected by the +/// GraphTraits class. +/// Once moving to C++20, we have nice type-checking using concepts template struct GraphTraits; #if __cplusplus >= 202002L @@ -49,6 +65,10 @@ concept is_graph_trait = requires(typename GraphTrait::graph_type &graph, { GraphTrait::nodes(cgraph) } -> psr::is_iterable_over_v; + { + GraphTrait::vertices(cgraph) + ->psr::is_iterable_over_v; + } { GraphTrait::node(cgraph, vtx) } -> std::convertible_to; @@ -64,6 +84,7 @@ concept is_graph_trait = requires(typename GraphTrait::graph_type &graph, { GraphTrait::withEdgeTarget(edge, vtx) } -> std::convertible_to; + {GraphTrait::weight(edge)}; }; template @@ -110,12 +131,9 @@ std::decay_t reverseGraph(GraphTy &&G) } for (auto &Nod : traits_t::nodes(G)) { - /// NOTE: in case of a const reference, nod will be const as well preventing - /// moving - traits_t::addNode(Ret, std::move(Nod)); + traits_t::addNode(Ret, forward_from(Nod)); } - - for (size_t I = 0, End = traits_t::size(G); I != End; ++I) { + for (auto I : traits_t::vertices(G)) { for (auto Child : traits_t::outEdges(G, I)) { traits_t::addEdge(Ret, traits_t::target(Child), traits_t::withEdgeTarget(Child, I)); @@ -162,3 +180,5 @@ void printGraph(const GraphTy &G, llvm::raw_ostream &OS, } } // namespace psr + +#endif // PHASAR_UTILS_GRAPHTRAITS_H diff --git a/include/phasar/Utils/IotaIterator.h b/include/phasar/Utils/IotaIterator.h new file mode 100644 index 0000000000..9eab786b61 --- /dev/null +++ b/include/phasar/Utils/IotaIterator.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel + *****************************************************************************/ + +#ifndef PHASAR_UTILS_IOTAITERATOR_H +#define PHASAR_UTILS_IOTAITERATOR_H + +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/iterator_range.h" + +#include +#include +#include +#include + +namespace psr { +/// An iterator that iterates over the same value a specified number of times +template class IotaIterator { +public: + using value_type = T; + using reference = T; + using pointer = const T *; + using difference_type = ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + constexpr reference operator*() const noexcept { return Elem; } + constexpr pointer operator->() const noexcept { return &Elem; } + + constexpr IotaIterator &operator++() noexcept { + ++Elem; + return *this; + } + constexpr IotaIterator operator++(int) noexcept { + auto Ret = *this; + ++*this; + return Ret; + } + + constexpr bool operator==(const IotaIterator &Other) const noexcept { + return Other.Elem == Elem; + } + constexpr bool operator!=(const IotaIterator &Other) const noexcept { + return !(*this == Other); + } + + constexpr explicit IotaIterator(T Elem) noexcept : Elem(Elem) {} + + constexpr IotaIterator() noexcept = default; + +private: + T Elem{}; +}; + +template +using IotaRangeType = llvm::iterator_range>; +template constexpr auto iota(T From, T To) noexcept { + static_assert(std::is_integral_v, "Iota only works on integers"); + using iterator_type = IotaIterator>; + auto Ret = llvm::make_range(iterator_type(From), iterator_type(To)); + return Ret; +} + +static_assert(is_iterable_over_v, int>); + +} // namespace psr + +#endif // PHASAR_UTILS_IOTAITERATOR_H diff --git a/include/phasar/Utils/RepeatIterator.h b/include/phasar/Utils/RepeatIterator.h index e2113b923d..2ff746138c 100644 --- a/include/phasar/Utils/RepeatIterator.h +++ b/include/phasar/Utils/RepeatIterator.h @@ -1,4 +1,14 @@ -#pragma once +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel + *****************************************************************************/ + +#ifndef PHASAR_UTILS_REPEATITERATOR_H +#define PHASAR_UTILS_REPEATITERATOR_H #include "phasar/Utils/TypeTraits.h" @@ -17,7 +27,7 @@ template class RepeatIterator { using reference = const T &; using pointer = const T *; using difference_type = ptrdiff_t; - using iterator_category = std::input_iterator_tag; + using iterator_category = std::forward_iterator_tag; reference operator*() const noexcept { assert(elem.has_value() && "Dereferencing end()-iterator"); @@ -70,3 +80,5 @@ template auto repeat(T &&Elem, size_t Num) { static_assert(is_iterable_over_v, int>); } // namespace psr + +#endif // PHASAR_UTILS_REPEATITERATOR_H diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 3d07e8e6ea..8d7e50891b 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -260,6 +260,17 @@ auto remove_by_index(Container &Cont, const Indices &Idx) { return remove_by_index(begin(Cont), end(Cont), begin(Idx), end(Idx)); } +/// Similar to std::forward, but takes the info, which of lvalue or rvalue +/// reference to return from Fwd +template +constexpr decltype(auto) forward_from(T &Val) noexcept { // NOLINT + if constexpr (std::is_lvalue_reference_v) { + return static_cast(Val); + } else { + return static_cast(Val); + } +} + } // namespace psr #endif From e35d04ffcd654aa2e28f6c83e99430af54fce6a3 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 25 Aug 2022 14:59:21 +0200 Subject: [PATCH 05/65] Add Z3 submodule --- .gitmodules | 4 ++++ external/z3 | 1 + 2 files changed, 5 insertions(+) create mode 160000 external/z3 diff --git a/.gitmodules b/.gitmodules index dce1dba82e..840e0ac563 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,7 @@ [submodule "external/json-schema-validator"] path = external/json-schema-validator url = https://github.com/pboettch/json-schema-validator.git +[submodule "external/z3"] + path = external/z3 + url = https://github.com/Z3Prover/z3.git + branch = z3-4.11.0 diff --git a/external/z3 b/external/z3 new file mode 160000 index 0000000000..6c165e89dc --- /dev/null +++ b/external/z3 @@ -0,0 +1 @@ +Subproject commit 6c165e89dcc88da56f7fdc8a51349478f0574947 From ddef57895f1a16a30a85938228f8c61f0fff36b7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 25 Aug 2022 15:00:55 +0200 Subject: [PATCH 06/65] Set Z3 version --- external/z3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/z3 b/external/z3 index 6c165e89dc..19da3c7086 160000 --- a/external/z3 +++ b/external/z3 @@ -1 +1 @@ -Subproject commit 6c165e89dcc88da56f7fdc8a51349478f0574947 +Subproject commit 19da3c7086dcf5cd0c78a82db9f99f5ef295b8ff From e90df7b5bcf0890aa5c495763eb984e254a99f80 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 Aug 2022 08:43:35 +0200 Subject: [PATCH 07/65] Add Z3-related stuff (WIP) --- CMakeLists.txt | 219 ++++++++----- .../PathSensitivity/LLVMPathConstraints.h | 35 ++ .../PathSensitivity/PathSensitivityConfig.h | 9 + .../PathSensitivity/PathSensitivityManager.h | 302 ++---------------- .../PathSensitivityManagerBase.h | 138 ++++++++ .../PathSensitivityManagerMixin.h | 204 ++++++++++++ .../Z3BasedPathSensitivityConfig.h | 40 +++ .../Z3BasedPathSensitvityManager.h | 67 ++++ include/phasar/Utils/AdjacencyList.h | 62 +++- include/phasar/Utils/GraphTraits.h | 22 ++ .../Z3BasedPathSensitivityManager.cpp | 118 +++++++ 11 files changed, 849 insertions(+), 367 deletions(-) create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h create mode 100644 lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 73000661e8..1391dfdc7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,14 @@ -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required(VERSION 3.0) # Check if we build within the llvm source tree -if (DEFINED LLVM_MAIN_SRC_DIR) +if(DEFINED LLVM_MAIN_SRC_DIR) set(PHASAR_IN_TREE 1) endif() -if (NOT PHASAR_IN_TREE) - project (phasar) +if(NOT PHASAR_IN_TREE) + project(phasar) set(CMAKE_PROJECT_NAME "phasar") -endif () +endif() set(CMAKE_EXPORT_COMPILE_COMMANDS YES) set(CMAKE_CXX_STANDARD 17) @@ -19,9 +19,9 @@ include(GNUInstallDirs) set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF) -if (NOT CMAKE_BUILD_TYPE) +if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build mode ('DebugSan' or 'Debug' or 'Release', default is 'Debug')" FORCE) -endif () +endif() if(CMAKE_BUILD_TYPE STREQUAL "DebugSan") message(STATUS "Selected Debug Build with sanitizers") @@ -39,9 +39,8 @@ enable_testing() # TODO: allow Phasar to be build as a llvm drop-in as well # if (NOT DEFINED LLVM_MAIN_SRC_DIR) -# message(FATAL_ERROR "Phasar is not a llvm drop-in, abort!") +# message(FATAL_ERROR "Phasar is not a llvm drop-in, abort!") # endif() - set(PHASAR_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PHASAR_SRC_DIR}/cmake") @@ -66,19 +65,22 @@ option(PHASAR_DEBUG_LIBDEPS "Debug internal library dependencies (private linkag option(BUILD_SHARED_LIBS "Build shared libraries (default is ON)" ON) option(PHASAR_ENABLE_WARNINGS "Enable warnings" ON) -if (PHASAR_ENABLE_WARNINGS) + +if(PHASAR_ENABLE_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-return-type-c-linkage ") -endif (PHASAR_ENABLE_WARNINGS) +endif(PHASAR_ENABLE_WARNINGS) option(PHASAR_ENABLE_PIC "Build Position-Independed Code" ON) -if (PHASAR_ENABLE_PIC) + +if(PHASAR_ENABLE_PIC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") -endif (PHASAR_ENABLE_PIC) +endif(PHASAR_ENABLE_PIC) -if (NOT PHASAR_ENABLE_PAMM) +if(NOT PHASAR_ENABLE_PAMM) set(PHASAR_ENABLE_PAMM "Off" CACHE STRING "Enable the performance measurement mechanism ('Off', 'Core' or 'Full', default is 'Off')" FORCE) set_property(CACHE PHASAR_ENABLE_PAMM PROPERTY STRINGS "Off" "Core" "Full") endif() + if(PHASAR_ENABLE_PAMM STREQUAL "Core" AND NOT PHASAR_BUILD_UNITTESTS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPAMM_CORE") message("PAMM metric severity level: Core") @@ -93,7 +95,7 @@ endif() option(PHASAR_ENABLE_DYNAMIC_LOG "Makes it possible to switch the logger on and off at runtime (default is ON)" ON) -if (PHASAR_ENABLE_DYNAMIC_LOG) +if(PHASAR_ENABLE_DYNAMIC_LOG) message(STATUS "Dynamic log enabled") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDYNAMIC_LOG") else() @@ -109,24 +111,25 @@ include_directories( set(PHASAR_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}/phasar) -if (NOT PHASAR_IN_TREE) +if(NOT PHASAR_IN_TREE) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${PHASAR_INSTALL_LIBDIR}) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() -if (LLVM_ENABLE_LIBCXX) +if(LLVM_ENABLE_LIBCXX) set(PHASAR_STD_FILESYSTEM c++fs) else() set(PHASAR_STD_FILESYSTEM stdc++fs) endif() -### Adding external libraries +# ## Adding external libraries # Threads find_package(Threads) # Boost find_package(Boost 1.65.1 COMPONENTS graph program_options ${BOOST_THREAD} REQUIRED) -#find_package(Boost 1.72.0 COMPONENTS graph program_options ${BOOST_THREAD} REQUIRED) + +# find_package(Boost 1.72.0 COMPONENTS graph program_options ${BOOST_THREAD} REQUIRED) include_directories(${Boost_INCLUDE_DIRS}) # Disable clang-tidy for the external projects @@ -140,13 +143,13 @@ set(CMAKE_CXX_CLANG_TIDY "") # The following workaround may collapse or become unnecessary once the issue is # changed or fixed in nlohmann_json_schema_validator. -#Override option of nlohmann_json_schema_validator to not build its tests +# Override option of nlohmann_json_schema_validator to not build its tests set(BUILD_TESTS OFF CACHE BOOL "Build json-schema-validator-tests") # Make nlohmann_json_schema_validator happy by telling it how to find the single include of nlohmann_json include_directories(external/json/single_include/) -if (PHASAR_IN_TREE) +if(PHASAR_IN_TREE) set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json_schema_validator) endif() @@ -163,7 +166,7 @@ set(JSON_Install ON) add_subdirectory(external/json) # Googletest -if (NOT PHASAR_IN_TREE) +if(NOT PHASAR_IN_TREE) add_subdirectory(external/googletest EXCLUDE_FROM_ALL) include_directories(external/googletest/googletest/include) include_directories(external/googletest/googlemock/include) @@ -179,7 +182,7 @@ find_library(SQLITE3_LIBRARY NAMES sqlite3) include_directories(${SQLITE3_INCLUDE_DIR}) # LLVM -if (NOT PHASAR_IN_TREE) +if(NOT PHASAR_IN_TREE) # Only search for LLVM if we build out of tree find_package(LLVM 14 REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) @@ -188,8 +191,40 @@ endif() add_definitions(${LLVM_DEFINITIONS}) -if (NOT PHASAR_IN_TREE) +# Z3 Solver +if(NOT Z3_FOUND) + # Z3 does not compile with '-Werror', so disable it for Z3's build + # string(REPLACE "-Werror" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + + # Do not pass DebugSan to z3 as it is unable to handle it + if(CMAKE_BUILD_TYPE STREQUAL "DebugSan") + set(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3 ON) + set(CMAKE_BUILD_TYPE "Debug") + endif() + + # Convince z3 to install its library along with phasar libs + # To avoid possible side effects we only change CMAKE_INSTALL_LIBDIR + # for including z3 (here) and restore it afterwards + set(ORIGINAL_CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) + set(CMAKE_INSTALL_LIBDIR ${PHASAR_INSTALL_LIBDIR}) + add_subdirectory(external/z3/) + set(CMAKE_INSTALL_LIBDIR ${ORIGINAL_CMAKE_INSTALL_LIBDIR}) + + if(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3) + set(CMAKE_BUILD_TYPE "DebugSan") + endif() + + include_directories(external/z3/src/) + include_directories(external/z3/src/api/) + include_directories(external/z3/src/api/c++/) + link_directories(${Z3_BINARY_DIR}) + + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") +endif() + +if(NOT PHASAR_IN_TREE) find_library(LLVM_LIBRARY NAMES LLVM PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH) + if(NOT ${LLVM_LIBRARY} STREQUAL "LLVM_LIBRARY-NOTFOUND") message(STATUS "Found consolidated shared LLVM lib " ${LLVM_LIBRARY} " that will be linked against.") set(USE_LLVM_FAT_LIB on) @@ -200,10 +235,12 @@ endif() # The clang-cpp shared library is now the preferred way to link dynamically against libclang if we build out of tree. if(NOT PHASAR_IN_TREE) find_library(CLANG_LIBRARY NAMES clang-cpp libclang-cpp REQUIRED HINTS ${LLVM_LIBRARY_DIRS}) + if(${CLANG_LIBRARY} STREQUAL "CLANG_LIBRARY-NOTFOUND") set(NEED_LIBCLANG_COMPONENT_LIBS on) endif() endif() + # As fallback, look for the small clang libraries if(PHASAR_IN_TREE OR NEED_LIBCLANG_COMPONENT_LIBS) set(CLANG_LIBRARY @@ -229,12 +266,13 @@ if(PHASAR_IN_TREE OR NEED_LIBCLANG_COMPONENT_LIBS) clangBasic LLVMFrontendOpenMP) endif() -if (NOT PHASAR_IN_TREE) + +if(NOT PHASAR_IN_TREE) # Only search for clang if we build out of tree link_directories(${CLANG_LIB_PATH}) endif() -if (PHASAR_IN_TREE) +if(PHASAR_IN_TREE) # Phasar needs clang headers, specificaly some that are generated by clangs table-gen include_directories( ${CLANG_INCLUDE_DIR} @@ -248,14 +286,15 @@ add_subdirectory(external/WALi-OpenNWA) include_directories(external/WALi-OpenNWA/Source/wali/include) # Set up clang-tidy to run during PhASAR's compilation to indicate code smells -if (PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD) +if(PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD) message(STATUS "Enabled clang-tidy during build") set(CMAKE_CXX_CLANG_TIDY clang-tidy; -header-filter=include/phasar.*h$; + # -warnings-as-errors=*; ) -endif () +endif() # Add PhASAR's subdirectories add_subdirectory(include) @@ -291,14 +330,14 @@ llvm_map_components_to_libnames(llvm_libs add_subdirectory(tools) # Add Phasar unittests and build all IR test code -if (PHASAR_BUILD_UNITTESTS) +if(PHASAR_BUILD_UNITTESTS) message("Phasar unittests") add_subdirectory(unittests) set(PHASAR_BUILD_IR ON) endif() # Build all IR test code -if (PHASAR_BUILD_IR) +if(PHASAR_BUILD_IR) message("Building IR test code") add_subdirectory(test) endif() @@ -332,8 +371,8 @@ install(DIRECTORY utils/ DESTINATION bin FILES_MATCHING PATTERN "phasar-*" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ - GROUP_EXECUTE GROUP_READ - WORLD_EXECUTE WORLD_READ + GROUP_EXECUTE GROUP_READ + WORLD_EXECUTE WORLD_READ ) # Install the Phasar config files into ~/.config/phasar/ @@ -341,8 +380,8 @@ install(DIRECTORY config/ DESTINATION $ENV{HOME}/.config/phasar PATTERN "config/*" PERMISSIONS OWNER_WRITE OWNER_READ - GROUP_WRITE GROUP_READ - WORLD_READ + GROUP_WRITE GROUP_READ + WORLD_READ ) include(CMakePackageConfigHelpers) @@ -351,86 +390,90 @@ configure_package_config_file( phasarConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/phasar PATH_VARS INCLUDE_INSTALL_DIR - ) +) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/phasarConfigVersion.cmake VERSION 1.0.0 COMPATIBILITY SameMajorVersion - ) +) -### Install Config and ConfigVersion files +# ## Install Config and ConfigVersion files install( FILES "${CMAKE_CURRENT_BINARY_DIR}/phasarConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/phasarConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/phasarConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/phasar" - ) +) # If the Phasar shared object libraries are not installed into a system folder # the so libs must be added manually to the linker search path and the linker # config must be updated as follows: # -# $ export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/home/philipp/Schreibtisch/tmp/lib -# $ sudo ldconfig +# $ export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/home/philipp/Schreibtisch/tmp/lib +# $ sudo ldconfig # # Or even better: just link statically when trying to package Phasar <- this is no longer possible # Settings for building various packages using Cpack -# How to pack using the following settings? -# $ mkdir build -# $ cd build -# $ cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr/local .. -# $ cpack .. -# $ dpkg -i ./.deb or better: apt-get install ./.deb +# How to pack using the following settings? +# $ mkdir build +# $ cd build +# $ cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr/local .. +# $ cpack .. +# $ dpkg -i ./.deb or better: apt-get install ./.deb set(MAJOR_VERSION 1) set(MINOR_VERSION 0) set(PATCH_VERSION 0) -if (NOT PHASAR_IN_TREE) -IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") -INCLUDE(InstallRequiredSystemLibraries) -set(CPACK_SET_DESTDIR "on") -set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") - -#set(CPACK_GENERATOR "DEB") -set(CPACK_GENERATOR "RPM") -set(CPACK_PACKAGE_DESCRIPTION "Phasar") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Phasar a LLVM-based static analysis framework") -set(CPACK_PACKAGE_VENDOR "Phasar Team - Philipp Schubert and others") -set(CPACK_PACKAGE_CONTACT "philipp.schubert@upb.de") -set(CPACK_PACKAGE_VERSION_MAJOR "${MAJOR_VERSION}") -set(CPACK_PACKAGE_VERSION_MINOR "${MINOR_VERSION}") -set(CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") -set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") -set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") -# package dependencies can be set-up here -# better use autogenerated dependency information -set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) -# set(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost_program_options (>= 1.66.0), -# libboost_graph (>= 1.66.0), -# libboost_thread (>= 1.66.0), -# libsqlite3 (>= 4.5.0), -# libpthread (>= 4.5.0), -# libdl (>= 4.5.0), -# librt (>= 4.5.0), -# libtinfo (>= 4.5.0), -# libz (>= 4.5.0), -# libm (>= 4.5.0), -# libstdc++ (>= 4.5.0), -# libgcc_s (>= 4.5.0), -# libc (>= 4.5.0), -# ld-linux-x86-64 (>= 4.5.0)") -set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") -set(CPACK_DEBIAN_PACKAGE_SECTION "kde") -set(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) -set(CPACK_COMPONENTS_ALL Libraries ApplicationData) -INCLUDE(CPack) -ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + +if(NOT PHASAR_IN_TREE) + IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + INCLUDE(InstallRequiredSystemLibraries) + set(CPACK_SET_DESTDIR "on") + set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + + # set(CPACK_GENERATOR "DEB") + set(CPACK_GENERATOR "RPM") + set(CPACK_PACKAGE_DESCRIPTION "Phasar") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Phasar a LLVM-based static analysis framework") + set(CPACK_PACKAGE_VENDOR "Phasar Team - Philipp Schubert and others") + set(CPACK_PACKAGE_CONTACT "philipp.schubert@upb.de") + set(CPACK_PACKAGE_VERSION_MAJOR "${MAJOR_VERSION}") + set(CPACK_PACKAGE_VERSION_MINOR "${MINOR_VERSION}") + set(CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") + set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") + set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") + + # package dependencies can be set-up here + # better use autogenerated dependency information + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + + # set(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost_program_options (>= 1.66.0), + # libboost_graph (>= 1.66.0), + # libboost_thread (>= 1.66.0), + # libsqlite3 (>= 4.5.0), + # libpthread (>= 4.5.0), + # libdl (>= 4.5.0), + # librt (>= 4.5.0), + # libtinfo (>= 4.5.0), + # libz (>= 4.5.0), + # libm (>= 4.5.0), + # libstdc++ (>= 4.5.0), + # libgcc_s (>= 4.5.0), + # libc (>= 4.5.0), + # ld-linux-x86-64 (>= 4.5.0)") + set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") + set(CPACK_DEBIAN_PACKAGE_SECTION "kde") + set(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) + set(CPACK_COMPONENTS_ALL Libraries ApplicationData) + INCLUDE(CPack) + ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") endif() # Setup the doxygen code documentation if(PHASAR_BUILD_DOC) find_package(Doxygen) - if (DOXYGEN_FOUND) + + if(DOXYGEN_FOUND) set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in) set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h new file mode 100644 index 0000000000..b28220ade9 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H + +#include "z3++.h" + +#include + +namespace llvm { +class Instruction; +} // namespace llvm + +namespace psr { +class LLVMPathConstraints { + /// TODO: implement +public: + z3::context &getContext() noexcept { return Z3Context; } + + std::optional getConstraintFromEdge(const llvm::Instruction *Curr, + const llvm::Instruction *Succ); + +private: + z3::context Z3Context; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h index a19117b684..53ecbbfeda 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h @@ -1,3 +1,12 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h index 461f1388d4..d21982d1f6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h @@ -1,8 +1,19 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" #include "phasar/Utils/AdjacencyList.h" #include "phasar/Utils/DFAMinimizer.h" #include "phasar/Utils/GraphTraits.h" @@ -16,292 +27,27 @@ #include namespace psr { -template class PathSensitivityManager { - static ExplodedSuperGraph & - assertNotNull(ExplodedSuperGraph *ESG) noexcept { - assert(ESG != nullptr && "The exploded supergraph passed to the " - "pathSensitivityManager must not be nullptr!"); - return *ESG; - } +template +class PathSensitivityManager + : public PathSensitivityManagerBase, + public PathSensitivityManagerMixin< + PathSensitivityManager, AnalysisDomainTy, + typename PathSensitivityManagerBase< + typename AnalysisDomainTy::n_t>::graph_type> { + using base_t = PathSensitivityManagerBase; + using mixin_t = + PathSensitivityManagerMixin; public: using n_t = typename AnalysisDomainTy::n_t; using d_t = typename AnalysisDomainTy::d_t; - using graph_type = AdjacencyList>; - - static_assert(std::is_integral_v::vertex_t>); + using typename PathSensitivityManagerBase::graph_type; PathSensitivityManager( const ExplodedSuperGraph *ESG) noexcept - : ESG(assertNotNull(ESG)) {} - - /// TODO: Add PathBuilder - /// TODO: Add LLVMPathConstraints - - graph_type pathsDagTo(n_t Inst, d_t Fact, - const PathSensitivityConfig &Config = {}) const { - auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); - - if (!Nod) { - llvm::report_fatal_error( - "Invalid Instruction-FlowFact pair. Only use those pairs that are " - "part of the IDE analysis results!"); - } - - graph_type Dag; - auto Rt = pathsToImpl(Inst, Nod, Dag); - graph_traits_t::addRoot(Dag, Rt); - -#ifndef NDEBUG - if (!assertIsDAG(Dag)) { - llvm::report_fatal_error("Invariant violated: DAG has a circle in it!"); - } else { - PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", - "The DAG indeed has no circles"); - } -#endif - - if (Config.MinimizeDAG) { - auto Equiv = minimizeGraph(Dag); - Dag = reverseDAG(std::move(Dag), Equiv); - } else { - Dag = reverseGraph(std::move(Dag)); - } - - /// TODO: assertIsDAG + minimizeDAG + reverseDAG - - return Dag; - } - - /// TODO: FlowPathSequence pathsTo(n_t, d_t) - -private: - using Node = typename ExplodedSuperGraph::Node; - using graph_traits_t = GraphTraits; - using vertex_t = typename graph_traits_t::vertex_t; - - struct PathsToContext { - llvm::DenseMap Cache; - llvm::SetVector> CurrPath; - }; - - bool pathsToImplLAInvoke(vertex_t Ret, Node *Vtx, PathsToContext &Ctx, - graph_type &RetDag, bool AutoSkipZero) { - - // NOLINTNEXTLINE(readability-identifier-naming) - auto reachedEnd = [this, AutoSkipZero](Node *Vtx) { - return !Vtx || (AutoSkipZero && Vtx->Value == ESG.getZeroValue()); - }; - - do { - graph_traits_t::node(RetDag, Ret).push_back(Vtx->Source); - Vtx = Vtx->Predecessor; - } while (!reachedEnd(Vtx) && Vtx->Neighbors.empty()); - - if (reachedEnd(Vtx)) { - return true; - } - - if (!Ctx.CurrPath.insert(Ret)) { - PHASAR_LOG_LEVEL(ERROR, "Node " << Ret << " already on path"); - return false; - } - scope_exit PopRet = [&Ctx] { Ctx.CurrPath.pop_back(); }; - - // NOLINTNEXTLINE(readability-identifier-naming) - auto traverseNext = [&Ctx, this, Ret, &RetDag, AutoSkipZero](Node *Nxt) { - auto Succ = pathsToImplLA(Nxt, Ctx, RetDag, AutoSkipZero); - if (Succ != graph_traits_t::Invalid && !Ctx.CurrPath.contains(Succ)) { - graph_traits_t::addEdge(RetDag, Ret, Succ); - } - }; - - for (auto Nxt : Vtx->Neighbors) { - traverseNext(Nxt); - } - - traverseNext(Vtx); - - graph_traits_t::dedupOutEdges(RetDag, Ret); - - return graph_traits_t::outDegree(RetDag, Ret) != 0; - } - - vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, graph_type &RetDag, - bool AutoSkipZero) { - /// Idea: Treat the graph as firstChild-nextSibling notation and always - /// traverse with one predecessor lookAhead - - auto [It, Inserted] = Ctx.Cache.try_emplace(Vtx, graph_traits_t::Invalid); - if (!Inserted) { - return It->second; - } - - auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); - // auto Ret = RetDag.addNode(); - It->second = Ret; - - if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag, AutoSkipZero)) { - /// NOTE: Don't erase Vtx from Cache to guarantee termination - Ctx.Cache[Vtx] = graph_traits_t::Invalid; - - if (Ctx.CurrPath.contains(Ret) || !graph_traits_t::pop(RetDag, Ret)) { - PHASAR_LOG_LEVEL(WARNING, "Cannot remove invalid path at: " << Ret); - graph_traits_t::node(RetDag, Ret).clear(); - } - - // if (RetDag.isLast(Ret) && !Ctx.CurrPath.contains(Ret)) { - // /// Assume, Ret is not referenced by any other node - // RetDag.pop(); - // } else { - // PHASAR_LOG_LEVEL(WARNING, << "Cannot remove invalid path at: " << - // Ret); RetDag.PartialPath[Ret].clear(); - // } - - return graph_traits_t::Invalid; - } - return Ret; - } - - vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag, - bool AutoSkipZero) { - assert(Vtx->Source != QueryInst); - - auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); - graph_traits_t::node(RetDag, Ret).push_back(QueryInst); - // RetDag.PartialPath[Ret].push_back(QueryInst); - - PathsToContext Ctx; - - for (auto *NB : Vtx->Neighbors) { - auto NBNode = pathsToImplLA(NB, Ctx, RetDag, AutoSkipZero); - if (NBNode != graph_traits_t::Invalid) { - graph_traits_t::addEdge(RetDag, Ret, NBNode); - // Succs.push_back(NBNode); - } - } - auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag, AutoSkipZero); - if (VtxNode != graph_traits_t::Invalid) { - graph_traits_t::addEdge(RetDag, Ret, VtxNode); - // Succs.push_back(VtxNode); - } - - graph_traits_t::dedupOutEdges(RetDag, Ret); - - /// Deduplicate the successors relation - // std::sort(Succs.begin(), Succs.end()); - // Succs.erase(std::unique(Succs.begin(), Succs.end()), Succs.end()); - - // RetDag.Successors[Ret] = std::move(Succs); - return Ret; - } - - bool assertIsDAG(const graph_type &Dag) { - llvm::BitVector Visited(Dag.size()); - llvm::DenseSet CurrPath; - CurrPath.reserve(graph_traits_t::size(Dag)); - - // NOLINTNEXTLINE(readability-identifier-naming) - auto doAssertIsDAG = [&CurrPath, &Visited, &Dag](auto &doAssertIsDAG, - vertex_t Vtx) { - if (!CurrPath.insert(Vtx).second) { - PHASAR_LOG_LEVEL(ERROR, "DAG has circle: Vtx: " << uintptr_t(Vtx)); - return false; - } - - scope_exit CurrPathPop = [&CurrPath, Vtx] { CurrPath.erase(Vtx); }; - if (Visited.test(Vtx)) { - /// We have already analyzed this node - /// NOTE: We must check this _after_ doing the circle check. Otherwise, - /// that can never be true - return true; - } - - Visited.set(Vtx); - - for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { - if (!doAssertIsDAG(doAssertIsDAG, Succ)) { - return false; - } - } - return true; - }; - - return doAssertIsDAG(doAssertIsDAG, Dag.Root); - } - - graph_type reverseDAG(graph_type &&Dag, const llvm::IntEqClasses &Equiv, - size_t MaxDepth = SIZE_MAX) { - - struct ReverseDAGContext { - llvm::SmallVector Cache; - size_t CurrDepth = 0; - size_t MaxDepth = 0; - } Ctx; - - Ctx.Cache.resize(Equiv.getNumClasses(), graph_traits_t::Invalid); - Ctx.MaxDepth = MaxDepth; - - graph_type Ret{}; - // Ret.Dag = &Dag; - // Ret.Leaf = Equiv[Dag.Root]; - if constexpr (is_reservable_graph_trait_v) { - graph_traits_t::reserve(Ret, Equiv.getNumClasses()); - } - // Ret.Adj.reserve(Equiv.getNumClasses()); - // Ret.Rev2Vtx.reserve(Equiv.getNumClasses()); - - // NOLINTNEXTLINE(readability-identifier-naming) - auto buildReverseDag = [&Ctx, &Ret, &Equiv, &Dag](auto &buildReverseDag, - vertex_t Vtx) { - auto Eq = Equiv[Vtx]; - if (Ctx.Cache[Eq] != graph_traits_t::Invalid) { - return Ctx.Cache[Eq]; - } - - // typename ReverseDAG::vertex_t Rev = Ret.size(); - // Ret.Rev2Vtx.push_back(Vtx); - // Ret.Adj.emplace_back(); - auto Rev = graph_traits_t::addNode( - Ret, std::move(graph_traits_t::node(Dag, Vtx))); - Ctx.Cache[Eq] = Rev; - - if (Ctx.CurrDepth >= Ctx.MaxDepth) { - graph_traits_t::addRoot(Ret, Rev); - // Ret.Roots.push_back(Rev); - return Rev; - } - - ++Ctx.CurrDepth; - scope_exit DecreaseDepth = [&Ctx] { --Ctx.CurrDepth; }; - - for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { - /// NOTE: Depending on the depth of SuccRev, we can still get DAGs - /// deeper than MaxDepth! - /// However, this is not considered harmful as of now - the DAG still - /// does not exceed a particular program-slice which size is fixed - auto SuccRev = - buildReverseDag(buildReverseDag, graph_traits_t::target(Succ)); - graph_traits_t::addEdge(Ret, SuccRev, - graph_traits_t::withEdgeTarget(Succ, Rev)); - // Ret.Adj[SuccRev].push_back(Rev); - } - - if (graph_traits_t::outDegree(Dag, Vtx) == 0) { - graph_traits_t::addRoot(Ret, Rev); - // Ret.Roots.push_back(Rev); - } - - return Rev; - }; - - buildReverseDag(buildReverseDag, Dag.Root); - - return Ret; - } - - const ExplodedSuperGraph &ESG; + : mixin_t(ESG) {} }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h new file mode 100644 index 0000000000..e3d648b64b --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h @@ -0,0 +1,138 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H + +#include "phasar/Utils/AdjacencyList.h" + +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/IntEqClasses.h" +#include "llvm/ADT/SmallVector.h" + +namespace psr { +template class PathSensitivityManagerBase { +public: + using n_t = N; + using graph_type = AdjacencyList>; + + static_assert(std::is_integral_v::vertex_t>); + +protected: + using graph_traits_t = GraphTraits; + using vertex_t = typename graph_traits_t::vertex_t; + +private: + bool assertIsDAG(const graph_type &Dag) { + llvm::BitVector Visited(Dag.size()); + llvm::DenseSet CurrPath; + CurrPath.reserve(graph_traits_t::size(Dag)); + + // NOLINTNEXTLINE(readability-identifier-naming) + auto doAssertIsDAG = [&CurrPath, &Visited, &Dag](auto &doAssertIsDAG, + vertex_t Vtx) { + if (!CurrPath.insert(Vtx).second) { + PHASAR_LOG_LEVEL(ERROR, "DAG has circle: Vtx: " << uintptr_t(Vtx)); + return false; + } + + scope_exit CurrPathPop = [&CurrPath, Vtx] { CurrPath.erase(Vtx); }; + if (Visited.test(Vtx)) { + /// We have already analyzed this node + /// NOTE: We must check this _after_ doing the circle check. Otherwise, + /// that can never be true + return true; + } + + Visited.set(Vtx); + + for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { + if (!doAssertIsDAG(doAssertIsDAG, Succ)) { + return false; + } + } + return true; + }; + + return doAssertIsDAG(doAssertIsDAG, Dag.Root); + } + + graph_type reverseDAG(graph_type &&Dag, const llvm::IntEqClasses &Equiv, + size_t MaxDepth = SIZE_MAX) { + + struct ReverseDAGContext { + llvm::SmallVector Cache; + size_t CurrDepth = 0; + size_t MaxDepth = 0; + } Ctx; + + Ctx.Cache.resize(Equiv.getNumClasses(), graph_traits_t::Invalid); + Ctx.MaxDepth = MaxDepth; + + graph_type Ret{}; + // Ret.Dag = &Dag; + // Ret.Leaf = Equiv[Dag.Root]; + if constexpr (is_reservable_graph_trait_v) { + graph_traits_t::reserve(Ret, Equiv.getNumClasses()); + } + // Ret.Adj.reserve(Equiv.getNumClasses()); + // Ret.Rev2Vtx.reserve(Equiv.getNumClasses()); + + // NOLINTNEXTLINE(readability-identifier-naming) + auto buildReverseDag = [&Ctx, &Ret, &Equiv, &Dag](auto &buildReverseDag, + vertex_t Vtx) { + auto Eq = Equiv[Vtx]; + if (Ctx.Cache[Eq] != graph_traits_t::Invalid) { + return Ctx.Cache[Eq]; + } + + // typename ReverseDAG::vertex_t Rev = Ret.size(); + // Ret.Rev2Vtx.push_back(Vtx); + // Ret.Adj.emplace_back(); + auto Rev = graph_traits_t::addNode( + Ret, std::move(graph_traits_t::node(Dag, Vtx))); + Ctx.Cache[Eq] = Rev; + + if (Ctx.CurrDepth >= Ctx.MaxDepth) { + graph_traits_t::addRoot(Ret, Rev); + // Ret.Roots.push_back(Rev); + return Rev; + } + + ++Ctx.CurrDepth; + scope_exit DecreaseDepth = [&Ctx] { --Ctx.CurrDepth; }; + + for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { + /// NOTE: Depending on the depth of SuccRev, we can still get DAGs + /// deeper than MaxDepth! + /// However, this is not considered harmful as of now - the DAG still + /// does not exceed a particular program-slice which size is fixed + auto SuccRev = + buildReverseDag(buildReverseDag, graph_traits_t::target(Succ)); + graph_traits_t::addEdge(Ret, SuccRev, + graph_traits_t::withEdgeTarget(Succ, Rev)); + // Ret.Adj[SuccRev].push_back(Rev); + } + + if (graph_traits_t::outDegree(Dag, Vtx) == 0) { + graph_traits_t::addRoot(Ret, Rev); + // Ret.Roots.push_back(Rev); + } + + return Rev; + }; + + buildReverseDag(buildReverseDag, Dag.Root); + + return Ret; + } +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h new file mode 100644 index 0000000000..d24fe870e3 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -0,0 +1,204 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H + +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/Utils/GraphTraits.h" +#include "llvm/ADT/SetVector.h" +#include + +namespace psr { +template +class PathSensitivityManagerMixin { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + + static ExplodedSuperGraph & + assertNotNull(ExplodedSuperGraph *ESG) noexcept { + assert(ESG != nullptr && "The exploded supergraph passed to the " + "pathSensitivityManager must not be nullptr!"); + return *ESG; + } + +protected: + PathSensitivityManagerMixin( + const ExplodedSuperGraph *ESG) noexcept + : ESG(assertNotNull(ESG)) { + static_assert(std::is_base_of_v, Derived>, + "Invalid CTRP instantiation: The Derived type must inherit " + "from PathSensitivityManagerBase!"); + } + +public: + [[nodiscard]] GraphType + pathsDagTo(n_t Inst, d_t Fact, + const PathSensitivityConfig &Config = {}) const { + auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); + + if (!Nod) { + llvm::report_fatal_error( + "Invalid Instruction-FlowFact pair. Only use those pairs that are " + "part of the IDE analysis results!"); + } + + graph_type Dag; + auto Rt = pathsToImpl(Inst, Nod, Dag); + graph_traits_t::addRoot(Dag, Rt); + +#ifndef NDEBUG + if (!static_cast(this)->assertIsDAG(Dag)) { + llvm::report_fatal_error("Invariant violated: DAG has a circle in it!"); + } else { + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + "The DAG indeed has no circles"); + } +#endif + + if (Config.MinimizeDAG) { + auto Equiv = minimizeGraph(Dag); + Dag = + static_cast(this)->reverseDAG(std::move(Dag), Equiv); + } else { + Dag = reverseGraph(std::move(Dag)); + } + + return Dag; + } + +private: + using Node = typename ExplodedSuperGraph::Node; + using graph_type = GraphType; + using graph_traits_t = GraphTraits; + using vertex_t = typename graph_traits_t::vertex_t; + + struct PathsToContext { + llvm::DenseMap Cache; + llvm::SetVector> CurrPath; + }; + + bool pathsToImplLAInvoke(vertex_t Ret, Node *Vtx, PathsToContext &Ctx, + graph_type &RetDag, bool AutoSkipZero) { + + // NOLINTNEXTLINE(readability-identifier-naming) + auto reachedEnd = [this, AutoSkipZero](Node *Vtx) { + return !Vtx || (AutoSkipZero && Vtx->Value == ESG.getZeroValue()); + }; + + do { + graph_traits_t::node(RetDag, Ret).push_back(Vtx->Source); + Vtx = Vtx->Predecessor; + } while (!reachedEnd(Vtx) && Vtx->Neighbors.empty()); + + if (reachedEnd(Vtx)) { + return true; + } + + if (!Ctx.CurrPath.insert(Ret)) { + PHASAR_LOG_LEVEL(ERROR, "Node " << Ret << " already on path"); + return false; + } + scope_exit PopRet = [&Ctx] { Ctx.CurrPath.pop_back(); }; + + // NOLINTNEXTLINE(readability-identifier-naming) + auto traverseNext = [&Ctx, this, Ret, &RetDag, AutoSkipZero](Node *Nxt) { + auto Succ = pathsToImplLA(Nxt, Ctx, RetDag, AutoSkipZero); + if (Succ != graph_traits_t::Invalid && !Ctx.CurrPath.contains(Succ)) { + graph_traits_t::addEdge(RetDag, Ret, Succ); + } + }; + + for (auto Nxt : Vtx->Neighbors) { + traverseNext(Nxt); + } + + traverseNext(Vtx); + + graph_traits_t::dedupOutEdges(RetDag, Ret); + + return graph_traits_t::outDegree(RetDag, Ret) != 0; + } + + vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, graph_type &RetDag, + bool AutoSkipZero) { + /// Idea: Treat the graph as firstChild-nextSibling notation and always + /// traverse with one predecessor lookAhead + + auto [It, Inserted] = Ctx.Cache.try_emplace(Vtx, graph_traits_t::Invalid); + if (!Inserted) { + return It->second; + } + + auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); + // auto Ret = RetDag.addNode(); + It->second = Ret; + + if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag, AutoSkipZero)) { + /// NOTE: Don't erase Vtx from Cache to guarantee termination + Ctx.Cache[Vtx] = graph_traits_t::Invalid; + + if (Ctx.CurrPath.contains(Ret) || !graph_traits_t::pop(RetDag, Ret)) { + PHASAR_LOG_LEVEL(WARNING, "Cannot remove invalid path at: " << Ret); + graph_traits_t::node(RetDag, Ret).clear(); + } + + // if (RetDag.isLast(Ret) && !Ctx.CurrPath.contains(Ret)) { + // /// Assume, Ret is not referenced by any other node + // RetDag.pop(); + // } else { + // PHASAR_LOG_LEVEL(WARNING, << "Cannot remove invalid path at: " << + // Ret); RetDag.PartialPath[Ret].clear(); + // } + + return graph_traits_t::Invalid; + } + return Ret; + } + + vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag, + bool AutoSkipZero) { + assert(Vtx->Source != QueryInst); + + auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); + graph_traits_t::node(RetDag, Ret).push_back(QueryInst); + // RetDag.PartialPath[Ret].push_back(QueryInst); + + PathsToContext Ctx; + + for (auto *NB : Vtx->Neighbors) { + auto NBNode = pathsToImplLA(NB, Ctx, RetDag, AutoSkipZero); + if (NBNode != graph_traits_t::Invalid) { + graph_traits_t::addEdge(RetDag, Ret, NBNode); + // Succs.push_back(NBNode); + } + } + auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag, AutoSkipZero); + if (VtxNode != graph_traits_t::Invalid) { + graph_traits_t::addEdge(RetDag, Ret, VtxNode); + // Succs.push_back(VtxNode); + } + + graph_traits_t::dedupOutEdges(RetDag, Ret); + + /// Deduplicate the successors relation + // std::sort(Succs.begin(), Succs.end()); + // Succs.erase(std::unique(Succs.begin(), Succs.end()), Succs.end()); + + // RetDag.Successors[Ret] = std::move(Succs); + return Ret; + } + + const ExplodedSuperGraph &ESG; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h new file mode 100644 index 0000000000..de573d10b6 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H + +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" + +#include "z3++.h" + +#include + +namespace psr { +struct Z3BasedPathSensitivityConfig : PathSensitivityConfig { + std::optional AdditionalConstraint; + + [[nodiscard]] Z3BasedPathSensitivityConfig + withAdditionalConstraint(const z3::expr &Constr) const &noexcept { + auto Ret = *this; + Ret.AdditionalConstraint = + Ret.AdditionalConstraint ? *Ret.AdditionalConstraint && Constr : Constr; + return Ret; + } + + [[nodiscard]] Z3BasedPathSensitivityConfig + withAdditionalConstraint(const z3::expr &Constr) &&noexcept { + AdditionalConstraint = + AdditionalConstraint ? *AdditionalConstraint && Constr : Constr; + return std::move(*this); + } +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h new file mode 100644 index 0000000000..e3ccd60fd6 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H + +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" + +#include "phasar/Utils/GraphTraits.h" +#include "z3++.h" + +#include + +namespace llvm { +class Instruction; +} // namespace llvm + +namespace psr { +class LLVMPathConstraints; + +class Z3BasedPathSensitivityManagerBase + : public PathSensitivityManagerBase { +public: + using n_t = const llvm::Instruction *; + + static_assert(is_removable_graph_trait_v, + "Invalid graph type: Must support edge-removal!"); + +private: + z3::expr filterOutUnreachableNodes(graph_type &RevDAG, + const Z3BasedPathSensitivityConfig &Config, + LLVMPathConstraints &LPC) const; +}; + +template >> +class Z3BasedPathSensitivityManager + : public Z3BasedPathSensitivityManagerBase, + public PathSensitivityManagerMixin< + Z3BasedPathSensitivityManager, AnalysisDomainTy, + typename Z3BasedPathSensitivityManagerBase::graph_type> { + using base_t = PathSensitivityManagerBase; + using mixin_t = PathSensitivityManagerMixin; + +public: + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using typename PathSensitivityManagerBase::graph_type; + + Z3BasedPathSensitivityManager( + const ExplodedSuperGraph *ESG) noexcept + : mixin_t(ESG) {} +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H diff --git a/include/phasar/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h index d24bc67d7d..509bb753fd 100644 --- a/include/phasar/Utils/AdjacencyList.h +++ b/include/phasar/Utils/AdjacencyList.h @@ -13,6 +13,7 @@ #include "phasar/Utils/GraphTraits.h" #include "phasar/Utils/IotaIterator.h" #include "phasar/Utils/RepeatIterator.h" +#include "phasar/Utils/Utilities.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" @@ -43,6 +44,9 @@ struct GraphTraits> { static inline constexpr auto Invalid = std::numeric_limits::max(); + /// Adds a new node to the graph G with node-tag Val + /// + /// \returns The vertex-descriptor for the newly created node template >> static vertex_t addNode(graph_type &G, TT &&Val) { @@ -54,6 +58,9 @@ struct GraphTraits> { return Ret; } + /// Adds a new node to the graph G without node-tag + /// + /// \returns The vertex-descriptor for the newly created node template >> static vertex_t addNode(graph_type &G, llvm::NoneType /*Val*/ = llvm::None) { @@ -62,6 +69,8 @@ struct GraphTraits> { return Ret; } + /// Makes the node Vtx as root in the graph G. A node should not be registered + /// as root multiple times static void addRoot(graph_type &G, vertex_t Vtx) { if constexpr (!std::is_same_v) { assert(Vtx < G.Nodes.size()); @@ -70,6 +79,7 @@ struct GraphTraits> { G.Roots.push_back(Vtx); } + /// Gets a range of all root nodes of graph G static llvm::ArrayRef roots(const graph_type &G) noexcept { if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); @@ -77,6 +87,10 @@ struct GraphTraits> { return G.Roots; } + /// Adds a new edge from node From to node To in graph G. From and T should be + /// nodes inside G. Multi-edges are supported, i.e. edges are not deduplicated + /// automatically; to manualy deduplicate the edges of one source-node, call + /// dedupOutEdges() static void addEdge(graph_type &G, vertex_t From, edge_t To) { assert(From < G.Adj.size()); if constexpr (!std::is_same_v) { @@ -85,6 +99,7 @@ struct GraphTraits> { G.Adj[From].push_back(std::move(To)); } + /// Gets a range of all edges outgoing from node Vtx in graph G static llvm::ArrayRef outEdges(const graph_type &G, vertex_t Vtx) noexcept { if constexpr (!std::is_same_v) { @@ -94,6 +109,7 @@ struct GraphTraits> { return G.Adj[Vtx]; } + /// Gets the number of edges outgoing from node Vtx in graph G static size_t outDegree(const graph_type &G, vertex_t Vtx) noexcept { if constexpr (!std::is_same_v) { assert(Vtx < G.Nodes.size()); @@ -102,6 +118,8 @@ struct GraphTraits> { return G.Adj[Vtx].size(); } + /// Deduplicates the edges outgoing from node Vtx in graph G. Deduplication is + /// based on operator< and operator== of the edge_t type static void dedupOutEdges(graph_type &G, vertex_t Vtx) noexcept { if constexpr (!std::is_same_v) { assert(Vtx < G.Nodes.size()); @@ -113,12 +131,14 @@ struct GraphTraits> { OutEdges.end()); } + /// Gets a const range of all nodes in graph G template >> static llvm::ArrayRef nodes(const graph_type &G) noexcept { assert(G.Adj.size() == G.Nodes.size()); return G.Nodes; } + /// Gets a mutable range of all nodes in graph G template static std::enable_if_t, llvm::MutableArrayRef> @@ -126,6 +146,7 @@ struct GraphTraits> { assert(G.Adj.size() == G.Nodes.size()); return G.Nodes; } + /// Gets a range of all nodes in graph G template >> static std::enable_if_t, @@ -134,13 +155,15 @@ struct GraphTraits> { return repeat(llvm::None, G.Adj.size()); } + /// Gets a range of vertex-descriptors for all nodes in graph G static auto vertices(const graph_type &G) noexcept { if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); } - return psr::iota(0, G.Adj.size()); + return psr::iota(size_t(0), G.Adj.size()); } + /// Gets the node-tag for node Vtx in graph G. Vtx must be part of G template >> static const value_type &node(const graph_type &G, vertex_t Vtx) noexcept { @@ -148,6 +171,7 @@ struct GraphTraits> { assert(G.Adj.size() == G.Nodes.size()); return G.Nodes[Vtx]; } + /// Gets the node-tag for node Vtx in graph G. Vtx must be part of G template >> static value_type &node(graph_type &G, vertex_t Vtx) noexcept { @@ -156,6 +180,7 @@ struct GraphTraits> { return G.Nodes[Vtx]; } + /// Gets the node-tag for node Vtx in graph G. Vtx must be part of G template >> static llvm::NoneType node([[maybe_unused]] const graph_type &G, @@ -164,6 +189,7 @@ struct GraphTraits> { return llvm::None; } + /// Gets the number of nodes in graph G static size_t size(const graph_type &G) noexcept { if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); @@ -171,6 +197,15 @@ struct GraphTraits> { return G.Adj.size(); } + /// Gets the number of nodes in graph G that are marked as root + static size_t roots_size(const graph_type &G) noexcept { + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + return G.Roots.size(); + } + + /// Pre-allocates space to hold up to Capacity nodes static void reserve(graph_type &G, size_t Capacity) { if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); @@ -180,6 +215,10 @@ struct GraphTraits> { G.Adj.reserve(Capacity); } + /// Tries to remove the last inserted node Vtx fro graph G. Fails, if there + /// was another not-popped node inserted in between. + /// + /// \returns True, iff the removal was successful static bool pop(graph_type &G, vertex_t Vtx) { if (Vtx == G.Adj.size() - 1) { G.Adj.pop_back(); @@ -191,22 +230,43 @@ struct GraphTraits> { return false; } + /// Gets the vertex-descriptor of the target-node of the given Edge template static std::enable_if_t, vertex_t> target(edge_t Edge) noexcept { return Edge; } + /// Copies the given edge, but replaces the target node by Tar; i.e. the + /// weight of the returned edge and the passed edge is same, but the target + /// nodes may differ. template static std::enable_if_t, edge_t> withEdgeTarget(edge_t /*edge*/, vertex_t Tar) noexcept { return Tar; } + /// Gets the weight associated with the given edge static llvm::NoneType weight(edge_t /*unused*/) noexcept { return llvm::None; } + /// Removes all outgoing edges from Vtx in graph G that match the target + /// vertices of the DestNodes range. This will sort the + template + static void removeEdges(graph_type &G, vertex_t Vtx, + const DestNodesRange &DestNodes, + bool IsAlreadySorted = false) { + assert(Vtx < G.Adj.size()); + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + if (!IsAlreadySorted) { + std::sort(G.Adj[Vtx].begin(), G.Adj[Vtx].end()); + } + G.Adj[Vtx].erase(remove_by_index(G.Adj[Vtx], DestNodes), G.Adj[Vtx].end()); + } + #if __cplusplus >= 202002L static_assert(is_graph>); static_assert(is_reservable_graph_trait>>); diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index 2fc9d733b5..99e8c9e007 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -13,6 +13,7 @@ #include "phasar/Utils/TypeTraits.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -78,6 +79,7 @@ concept is_graph_trait = requires(typename GraphTrait::graph_type &graph, GraphTrait::roots(cgraph) } -> psr::is_iterable_over_v; { GraphTrait::pop(graph, vtx) } -> std::same_as; + { GraphTrait::roots_size(cgraph) } -> std::convertible_to; { GraphTrait::target(edge) } -> std::convertible_to; @@ -110,12 +112,32 @@ struct is_reservable_graph_trait< std::void_t(), size_t()))>> : std::true_type {}; + +template +// NOLINTNEXTLINE(readability-identifier-naming) +struct is_removable_graph_trait : std::false_type {}; +template +struct is_removable_graph_trait< + GraphTrait, + std::void_t(), + std::declval(), + llvm::ArrayRef())), + decltype(GraphTrait::removeRoots( + std::declval(), + llvm::ArrayRef()))>> + : std::true_type {}; } // namespace detail template // NOLINTNEXTLINE(readability-identifier-naming) static constexpr bool is_reservable_graph_trait_v = detail::is_reservable_graph_trait::value; + +template +// NOLINTNEXTLINE(readability-identifier-naming) +static constexpr bool is_removable_graph_trait_v = + detail::is_removable_graph_trait::value; #endif template diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp new file mode 100644 index 0000000000..6bf22ad3e6 --- /dev/null +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -0,0 +1,118 @@ +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h" + +namespace psr { +z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( + graph_type &RevDAG, const Z3BasedPathSensitivityConfig &Config, + LLVMPathConstraints &LPC) const { + + struct FilterContext { + llvm::BitVector Visited{}; + z3::expr True; + z3::expr False; + llvm::SmallVector NodeConstraints{}; + size_t Ctr = 0; + z3::solver Solver; + + explicit FilterContext(z3::context &Z3Ctx) + : True(Z3Ctx.bool_val(true)), False(Z3Ctx.bool_val(false)), + Solver(Z3Ctx) {} + } Ctx(LPC.getContext()); + + Ctx.Visited.resize(graph_traits_t::size(RevDAG)); + Ctx.NodeConstraints.resize(graph_traits_t::size(RevDAG), Ctx.True); + + size_t TotalNumEdges = 0; + for (auto I : graph_traits_t::vertices(RevDAG)) { + TotalNumEdges += graph_traits_t::outDegree(RevDAG, I); + } + + if (Config.AdditionalConstraint) { + Ctx.Solver.add(*Config.AdditionalConstraint); + } + + auto doFilter = [&Ctx, &RevDAG, &LPC](auto &doFilter, + unsigned Vtx) -> z3::expr { + Ctx.Visited.set(Vtx); + z3::expr X = Ctx.True; + llvm::ArrayRef PartialPath = graph_traits_t::node(RevDAG, Vtx); + assert(!PartialPath.empty()); + + for (size_t I = PartialPath.size() - 1; I; --I) { + if (auto Constr = + LPC.getConstraintFromEdge(PartialPath[I], PartialPath[I - 1])) { + X = X && *Constr; + } + } + + llvm::SmallVector Ys; + llvm::SmallVector ToRemove; + + unsigned Idx = 0; + for (auto Edge : graph_traits_t::outEdges(RevDAG, Vtx)) { + auto Adj = graph_traits_t::target(Edge); + if (!Ctx.Visited.test(Adj)) { + doFilter(doFilter, Adj); + } + Ctx.Solver.push(); + Ctx.Solver.add(X); + auto Y = Ctx.NodeConstraints[Adj]; + const auto &AdjPP = graph_traits_t::node(RevDAG, Adj); + assert(!AdjPP.empty()); + if (auto Constr = + LPC.getConstraintFromEdge(PartialPath.front(), AdjPP.back())) { + Y = Y && *Constr; + } + + Ctx.Solver.add(Y); + + auto Sat = Ctx.Solver.check(); + if (Sat == z3::check_result::unsat) { + ToRemove.push_back(Idx); + } else { + Ys.push_back(std::move(Y)); + } + + Ctx.Solver.pop(); + Idx++; + } + + Ctx.Ctr += ToRemove.size(); + + graph_traits_t::removeEdges(RevDAG, Vtx, ToRemove); + // RevDAG.Adj[Vtx].erase(remove_by_index(RevDAG.Adj[Vtx], ToRemove), + // RevDAG.Adj[Vtx].end()); + if (graph_traits_t::outDegree(RevDAG, Vtx) == 0) { + return Ctx.NodeConstraints[Vtx] = Vtx == 0 ? X : Ctx.False; + } + if (Ys.empty()) { + llvm_unreachable("Adj nonempty and Ys empty is unexpected"); + } + auto Y = Ys[0]; + for (const auto &Constr : llvm::makeArrayRef(Ys).drop_front()) { + Y = Y || Constr; + } + return Ctx.NodeConstraints[Vtx] = (X && Y).simplify(); + }; + + z3::expr Ret = LPC.getContext().bool_val(false); + + for (unsigned I = 0; I < RevDAG.Roots.size(); ++I) { + auto Rt = RevDAG.Roots[I]; + auto Res = doFilter(doFilter, Rt); + Ret = Ret || Res; + if (Rt != RevDAG.Leaf && RevDAG.Adj[Rt].empty()) { + std::swap(RevDAG.Roots[I], RevDAG.Roots.back()); + RevDAG.Roots.pop_back(); + --I; + } + } + + LOG_IF_ENABLE(BOOST_LOG_SEV(lg::get(), DEBUG) + << "> Filtered out " << Ctx.Ctr << " edges from the DAG"); + LOG_IF_ENABLE(BOOST_LOG_SEV(lg::get(), DEBUG) + << ">> " << (TotalNumEdges - Ctx.Ctr) << " edges remaining"); + + return Ret.simplify(); +} +} // namespace psr From 2c5c0d4734208ece87b111ff49bc3ad0edcdccb7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 Aug 2022 10:04:02 +0200 Subject: [PATCH 08/65] Added now basic functionality for path sensitivity (compiles, but not tested yet) --- .clang-tidy | 1 + .../DataFlowSolver/PathSensitivity/FlowPath.h | 59 +++ .../PathSensitivity/LLVMPathConstraints.h | 11 + .../Z3BasedPathSensitvityManager.h | 87 +++- include/phasar/Utils/AdjacencyList.h | 35 +- include/phasar/Utils/GraphTraits.h | 10 +- include/phasar/Utils/Logger.h | 9 +- include/phasar/Utils/RepeatIterator.h | 4 +- include/phasar/Utils/Utilities.h | 5 +- lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt | 1 + .../PathSensitivity/CMakeLists.txt | 33 ++ .../Z3BasedPathSensitivityManager.cpp | 453 +++++++++++++++++- .../phasasr_pathsensitivity-config.cmake | 25 + 13 files changed, 686 insertions(+), 47 deletions(-) create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h create mode 100644 lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt create mode 100644 lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake diff --git a/.clang-tidy b/.clang-tidy index ad126f0017..57a4a45300 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -15,6 +15,7 @@ Checks: '-*, -readability-function-cognitive-complexity, -readability-convert-member-functions-to-static, -readability-isolate-declaration, + -readability-identifier-length, cppcoreguidelines-*, -cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h new file mode 100644 index 0000000000..dcbf903a5d --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOW_PATHSENSITIVITY_FLOWPATH_H +#define PHASAR_PHASARLLVM_DATAFLOW_PATHSENSITIVITY_FLOWPATH_H + +#include "z3++.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" + +namespace psr { +template struct FlowPath { + llvm::SmallVector Path; + z3::expr Constraint; + z3::model Model; + + FlowPath(llvm::ArrayRef Path, const z3::expr &Constraint) + : Path(Path.begin(), Path.end()), Constraint(Constraint), + Model(Constraint.ctx()) {} + FlowPath(llvm::ArrayRef Path, const z3::expr &Constraint, + const z3::model &Model) + : Path(Path.begin(), Path.end()), Constraint(Constraint), Model(Model) {} + + [[nodiscard]] auto begin() noexcept { return Path.begin(); } + [[nodiscard]] auto end() noexcept { return Path.end(); } + [[nodiscard]] auto begin() const noexcept { return Path.begin(); } + [[nodiscard]] auto end() const noexcept { return Path.end(); } + [[nodiscard]] auto cbegin() const noexcept { return Path.cbegin(); } + [[nodiscard]] auto cend() const noexcept { return Path.cend(); } + + [[nodiscard]] size_t size() const noexcept { return Path.size(); } + [[nodiscard]] bool empty() const noexcept { return Path.empty(); } + + [[nodiscard]] decltype(auto) operator[](size_t Idx) const { + return Path[Idx]; + } + + [[nodiscard]] operator llvm::ArrayRef() const noexcept { return Path; } + + [[nodiscard]] bool operator==(const FlowPath &Other) const noexcept { + return Other.Path == Path; + } + [[nodiscard]] bool operator!=(const FlowPath &Other) const noexcept { + return !(*this == Other); + } +}; + +template using FlowPathSequence = std::vector>; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOW_PATHSENSITIVITY_FLOWPATH_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h index b28220ade9..48226e8f0f 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h @@ -11,10 +11,12 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H #include "z3++.h" +#include "llvm/ADT/SmallVector.h" #include namespace llvm { +class Value; class Instruction; } // namespace llvm @@ -22,11 +24,20 @@ namespace psr { class LLVMPathConstraints { /// TODO: implement public: + struct ConstraintAndVariables { + z3::expr Constraint; + llvm::SmallVector Variables; + }; + z3::context &getContext() noexcept { return Z3Context; } std::optional getConstraintFromEdge(const llvm::Instruction *Curr, const llvm::Instruction *Succ); + std::optional + getConstraintAndVariablesFromEdge(const llvm::Instruction *Curr, + const llvm::Instruction *Succ); + private: z3::context Z3Context; }; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h index e3ccd60fd6..a0c8f490fd 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -10,12 +10,15 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" - #include "phasar/Utils/GraphTraits.h" + +#include "phasar/Utils/Logger.h" #include "z3++.h" +#include "llvm/Support/ErrorHandling.h" #include @@ -34,10 +37,28 @@ class Z3BasedPathSensitivityManagerBase static_assert(is_removable_graph_trait_v, "Invalid graph type: Must support edge-removal!"); -private: - z3::expr filterOutUnreachableNodes(graph_type &RevDAG, +protected: + z3::expr filterOutUnreachableNodes(graph_type &RevDAG, vertex_t Leaf, const Z3BasedPathSensitivityConfig &Config, LLVMPathConstraints &LPC) const; + + FlowPathSequence + filterAndFlattenRevDag(graph_type &RevDAG, vertex_t Leaf, n_t FinalInst, + const Z3BasedPathSensitivityConfig &Config, + LLVMPathConstraints &LPC) const; + + void deduplicatePaths(FlowPathSequence &Paths) { + /// Some kind of lexical sort for being able to deduplicate the paths easily + std::sort(Paths.begin(), Paths.end(), + [](const FlowPath &LHS, const FlowPath &RHS) { + return LHS.size() < RHS.size() || + (LHS.size() == RHS.size() && + std::lexicographical_compare(LHS.begin(), LHS.end(), + RHS.begin(), RHS.end())); + }); + + Paths.erase(std::unique(Paths.begin(), Paths.end()), Paths.end()); + } }; template ::graph_type; + using MaybeFlowPathSeq = std::variant, z3::expr>; Z3BasedPathSensitivityManager( const ExplodedSuperGraph *ESG) noexcept : mixin_t(ESG) {} + + FlowPathSequence pathsTo(n_t Inst, d_t Fact, + const Z3BasedPathSensitivityConfig &Config, + LLVMPathConstraints &LPC) const { + graph_type Dag = this->pathsDagTo(Inst, std::move(Fact)); + + vertex_t Leaf = [&Dag] { + for (auto Vtx : graph_traits_t::vertices(Dag)) { + if (graph_traits_t::outDegree(Dag, Vtx) == 0) { + return Vtx; + } + } + llvm_unreachable("Expect the DAG to have a leaf node!"); + }(); + + z3::expr Constraint = filterOutUnreachableNodes(Dag, Leaf, Config, LPC); + + if (Constraint.is_false()) { + PHASAR_LOG_LEVEL_CAT(INFO, "PathSensitivityManager", + "The query position is unreachable"); + return FlowPathSequence(); + } + + if (graph_traits_t::size(Dag) > Config.DAGSizeThreshold) { + PHASAR_LOG_LEVEL_CAT( + INFO, "PathSensitivityManager", + "Note: The DAG for query @ " + << getMetaDataID(Inst) + << " is too large. Don't collect the precise paths " + "here"); + return Constraint; + } + + auto Ret = filterAndFlattenRevDag(Dag, Leaf, Inst, Config, LPC); + + deduplicatePaths(Ret); + +#ifndef NDEBUG +#ifdef DYNAMIC_LOG + PHASAR_LOG_LEVEL_CAT( + DEBUG, "PathSensitivityManager", + "Recorded " << Ret.size() << " valid paths:"; + std::string Str; for (const FlowPath &Path + : Ret) { + Str.clear(); + llvm::raw_string_ostream ROS(Str); + ROS << "> "; + llvm::interleaveComma(Path.Path, ROS, [&ROS](auto *Inst) { + ROS << getMetaDataID(Inst); + }); + ROS << ": " << Path.Constraint.to_string(); + ROS.flush(); + S << Str; + }) +#endif // DYNAMIC_LOG +#endif // NDEBUG + + return Ret; + } }; } // namespace psr diff --git a/include/phasar/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h index 509bb753fd..900934ab0c 100644 --- a/include/phasar/Utils/AdjacencyList.h +++ b/include/phasar/Utils/AdjacencyList.h @@ -19,6 +19,7 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/SmallVector.h" +#include #include #include @@ -41,6 +42,8 @@ struct GraphTraits> { using value_type = T; using vertex_t = unsigned; using edge_t = EdgeTy; + using edge_iterator = typename llvm::ArrayRef::const_iterator; + using roots_iterator = typename llvm::ArrayRef::const_iterator; static inline constexpr auto Invalid = std::numeric_limits::max(); @@ -94,7 +97,7 @@ struct GraphTraits> { static void addEdge(graph_type &G, vertex_t From, edge_t To) { assert(From < G.Adj.size()); if constexpr (!std::is_same_v) { - assert(B.Adj.size() == G.Nodes.size()); + assert(G.Adj.size() == G.Nodes.size()); } G.Adj[From].push_back(std::move(To)); } @@ -251,20 +254,30 @@ struct GraphTraits> { return llvm::None; } - /// Removes all outgoing edges from Vtx in graph G that match the target - /// vertices of the DestNodes range. This will sort the - template - static void removeEdges(graph_type &G, vertex_t Vtx, - const DestNodesRange &DestNodes, - bool IsAlreadySorted = false) { - assert(Vtx < G.Adj.size()); + static edge_iterator removeEdge(graph_type &G, vertex_t Vtx, + edge_iterator It) noexcept { + assert(Vtx < G.Nodes.size()); if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); } - if (!IsAlreadySorted) { - std::sort(G.Adj[Vtx].begin(), G.Adj[Vtx].end()); + assert(G.Adj[Vtx].begin() <= It && It < G.Adj[Vtx].end()); + auto Idx = std::distance(std::cbegin(G.Adj[Vtx]), It); + + std::swap(G.Adj[Vtx][Idx], G.Adj[Vtx].back()); + G.Adj[Vtx].pop_back(); + return It; + } + + static roots_iterator removeRoot(graph_type &G, roots_iterator It) noexcept { + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); } - G.Adj[Vtx].erase(remove_by_index(G.Adj[Vtx], DestNodes), G.Adj[Vtx].end()); + assert(G.Roots.begin() <= It && It < G.Roots.end()); + + auto Idx = std::distance(std::cbegin(G.Roots), It); + std::swap(G.Roots[Idx], G.Roots.back()); + G.Roots.pop_back(); + return It; } #if __cplusplus >= 202002L diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index 99e8c9e007..337e950217 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -119,13 +119,15 @@ struct is_removable_graph_trait : std::false_type {}; template struct is_removable_graph_trait< GraphTrait, - std::void_t(), std::declval(), - llvm::ArrayRef())), - decltype(GraphTrait::removeRoots( + std::declval())), + decltype(GraphTrait::removeRoot( std::declval(), - llvm::ArrayRef()))>> + std::declval()))>> : std::true_type {}; } // namespace detail diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index 6e76701fa8..07a40291ff 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -102,7 +102,8 @@ class Logger final { auto &S = Logger::getLogStream(level, std::nullopt); \ Logger::addLinePrefix(S, level, std::nullopt); \ /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - S << message << '\n'; \ + S << message; \ + S << '\n'; \ } while (false);) #define PHASAR_LOG_LEVEL_CAT(level, cat, message) \ @@ -114,7 +115,8 @@ class Logger final { auto &S = Logger::getLogStream(level, cat); \ Logger::addLinePrefix(S, level, cat); \ /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - S << message << '\n'; \ + S << message; \ + S << '\n'; \ } while (false);) #define PHASAR_LOG_CAT(cat, message) \ @@ -124,7 +126,8 @@ class Logger final { auto &S = Logger::getLogStream(std::nullopt, cat); \ Logger::addLinePrefix(S, std::nullopt, cat); \ /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - S << message << '\n'; \ + S << message; \ + << '\n'; \ } while (false);) // For performance reason, we want to disable any diff --git a/include/phasar/Utils/RepeatIterator.h b/include/phasar/Utils/RepeatIterator.h index 2ff746138c..94245930a1 100644 --- a/include/phasar/Utils/RepeatIterator.h +++ b/include/phasar/Utils/RepeatIterator.h @@ -30,11 +30,11 @@ template class RepeatIterator { using iterator_category = std::forward_iterator_tag; reference operator*() const noexcept { - assert(elem.has_value() && "Dereferencing end()-iterator"); + assert(Elem.has_value() && "Dereferencing end()-iterator"); return *Elem; } pointer operator->() const noexcept { - assert(elem.has_value() && "Dereferencing end()-iterator"); + assert(Elem.has_value() && "Dereferencing end()-iterator"); return &*Elem; } diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 8d7e50891b..1296e019ef 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -162,9 +162,8 @@ struct StringIDLess { template class scope_exit { // NOLINT public: template ()())> - explicit scope_exit(FFn &&F) noexcept( - std::is_nothrow_constructible_v || - std::is_nothrow_constructible_v) + scope_exit(FFn &&F) noexcept(std::is_nothrow_constructible_v || + std::is_nothrow_constructible_v) : F(std::forward(F)) {} ~scope_exit() { F(); } diff --git a/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt b/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt index a32bf813ef..90971027f5 100644 --- a/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(IfdsIde) add_subdirectory(Mono) add_subdirectory(SyncPDS) add_subdirectory(WPDS) +add_subdirectory(PathSensitivity) diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt new file mode 100644 index 0000000000..bef004d7b0 --- /dev/null +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt @@ -0,0 +1,33 @@ +file(GLOB_RECURSE PATHSENSITIVITY_SRC *.h *.cpp) + +set(PHASAR_LINK_LIBS + phasar_config + phasar_utils + phasar_phasarllvm_utils + phasar_pointer + libz3 +) + +set(LLVM_LINK_COMPONENTS + Core + Support +) + +if(BUILD_SHARED_LIBS) + add_phasar_library(phasar_pathsensitivity + SHARED + ${PATHSENSITIVITY_SRC} + ) +else() + add_phasar_library(phasar_pathsensitivity + STATIC + ${PATHSENSITIVITY_SRC} + ) +endif() + + +set_target_properties(phasar_pathsensitivity + PROPERTIES + LINKER_LANGUAGE CXX + PREFIX "lib" +) diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp index 6bf22ad3e6..06df06f1b1 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -1,9 +1,11 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h" +#include "phasar/Utils/Logger.h" namespace psr { z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( - graph_type &RevDAG, const Z3BasedPathSensitivityConfig &Config, + graph_type &RevDAG, vertex_t Leaf, + const Z3BasedPathSensitivityConfig &Config, LLVMPathConstraints &LPC) const { struct FilterContext { @@ -31,6 +33,7 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( Ctx.Solver.add(*Config.AdditionalConstraint); } + // NOLINTNEXTLINE(readability-identifier-naming) auto doFilter = [&Ctx, &RevDAG, &LPC](auto &doFilter, unsigned Vtx) -> z3::expr { Ctx.Visited.set(Vtx); @@ -46,10 +49,13 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( } llvm::SmallVector Ys; - llvm::SmallVector ToRemove; - unsigned Idx = 0; - for (auto Edge : graph_traits_t::outEdges(RevDAG, Vtx)) { + const auto &OutEdges = graph_traits_t::outEdges(RevDAG, Vtx); + + for (auto Iter = OutEdges.begin(), End = OutEdges.end(); Iter != End;) { + // NOLINTNEXTLINE(readability-qualified-auto, llvm-qualified-auto) + auto It = Iter++; + auto Edge = *It; auto Adj = graph_traits_t::target(Edge); if (!Ctx.Visited.test(Adj)) { doFilter(doFilter, Adj); @@ -68,20 +74,16 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( auto Sat = Ctx.Solver.check(); if (Sat == z3::check_result::unsat) { - ToRemove.push_back(Idx); + Iter = graph_traits_t::removeEdge(RevDAG, Vtx, It); + Ctx.Ctr++; } else { Ys.push_back(std::move(Y)); } Ctx.Solver.pop(); - Idx++; + // Idx++; } - Ctx.Ctr += ToRemove.size(); - - graph_traits_t::removeEdges(RevDAG, Vtx, ToRemove); - // RevDAG.Adj[Vtx].erase(remove_by_index(RevDAG.Adj[Vtx], ToRemove), - // RevDAG.Adj[Vtx].end()); if (graph_traits_t::outDegree(RevDAG, Vtx) == 0) { return Ctx.NodeConstraints[Vtx] = Vtx == 0 ? X : Ctx.False; } @@ -97,22 +99,431 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( z3::expr Ret = LPC.getContext().bool_val(false); - for (unsigned I = 0; I < RevDAG.Roots.size(); ++I) { - auto Rt = RevDAG.Roots[I]; + const auto &Roots = graph_traits_t::roots(RevDAG); + for (auto Iter = Roots.begin(), End = Roots.end(); Iter != End;) { + // NOLINTNEXTLINE(readability-qualified-auto, llvm-qualified-auto) + auto It = Iter++; + auto Rt = *It; auto Res = doFilter(doFilter, Rt); Ret = Ret || Res; - if (Rt != RevDAG.Leaf && RevDAG.Adj[Rt].empty()) { - std::swap(RevDAG.Roots[I], RevDAG.Roots.back()); - RevDAG.Roots.pop_back(); - --I; + if (Rt != Leaf && RevDAG.Adj[Rt].empty()) { + Iter = graph_traits_t::removeRoot(RevDAG, It); } } - LOG_IF_ENABLE(BOOST_LOG_SEV(lg::get(), DEBUG) - << "> Filtered out " << Ctx.Ctr << " edges from the DAG"); - LOG_IF_ENABLE(BOOST_LOG_SEV(lg::get(), DEBUG) - << ">> " << (TotalNumEdges - Ctx.Ctr) << " edges remaining"); + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + "> Filtered out " << Ctx.Ctr << " edges from the DAG"); + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + ">> " << (TotalNumEdges - Ctx.Ctr) + << " edges remaining"); return Ret.simplify(); } + +/// This could be a C++20 concept! +struct PathFilter { + // void saveState(); + // void restoreState(); + // void saveEdge(n_t Prev, n_t Inst); + // bool isValid() const; + // bool saveFinalEdge(n_t Prev, n_t FinalInst); +}; + +template class PathFilterList : public std::tuple { +public: + using n_t = const llvm::Instruction *; + using std::tuple::tuple; + + void saveState() { saveStateImpl(std::make_index_sequence()); } + + void restoreState() { + restoreStateImpl(std::make_index_sequence()); + } + + void saveEdge(n_t Prev, n_t Inst) { + saveEdgeImpl(Prev, Inst, std::make_index_sequence()); + } + + [[nodiscard]] bool isValid() { + return isValidImpl(std::make_index_sequence()); + } + + bool saveFinalEdge(n_t Prev, n_t Inst) { + return saveFinalEdgeImpl(Prev, Inst, + std::make_index_sequence()); + } + +private: + template + void saveStateImpl(std::index_sequence /*unused*/) { + (std::get(*this).saveState(), ...); + } + template + void restoreStateImpl(std::index_sequence /*unused*/) { + (std::get(*this).restoreState(), ...); + } + template + void saveEdgeImpl(n_t Prev, n_t Inst, std::index_sequence /*unused*/) { + (std::get(*this).saveEdge(Prev, Inst), ...); + } + template + bool saveFinalEdgeImpl(n_t Prev, n_t Inst, + std::index_sequence /*unused*/) { + return (std::get(*this).saveFinalEdge(Prev, Inst) && ...); + } + template + bool isValidImpl(std::index_sequence /*unused*/) { + return (std::get(*this).isValid() && ...); + } +}; + +template +static PathFilterList makePathFilterList(T &&...Filters) { + return PathFilterList(std::forward(Filters)...); +} + +class CallStackPathFilter { +public: + using n_t = const llvm::Instruction *; + void saveState() { CallStackSafe.emplace_back(CallStackOwner.size(), TOS); } + + void restoreState() { + auto [SaveCallStackSize, CSSave] = CallStackSafe.pop_back_val(); + assert(CallStackOwner.size() >= SaveCallStackSize); + CallStackOwner.pop_back_n(CallStackOwner.size() - SaveCallStackSize); + TOS = CSSave; + Valid = true; + } + + void saveEdge(n_t Prev, n_t Inst) { + if (!Valid) { + return; + } + if (const auto *CS = llvm::dyn_cast(Prev); + CS && !isDirectSuccessorOf(Inst, CS)) { + pushCS(CS); + + } else if (llvm::isa(Prev) || + llvm::isa(Prev)) { + /// Allow unbalanced returns + if (!emptyCS()) { + const auto *CS = popCS(); + if (!isDirectSuccessorOf(Inst, CS)) { + /// Invalid return + Valid = false; + } + } + /// else: unbalanced return + } + } + + bool saveFinalEdge(n_t Prev, n_t FinalInst) { + if (!Valid) { + return false; + } + + if (Prev && (llvm::isa(Prev) || + llvm::isa(Prev))) { + if (!emptyCS() && !isDirectSuccessorOf(FinalInst, popCS())) { + /// Invalid return + return false; + } + } + return true; + } + + [[nodiscard]] bool isValid() const noexcept { return Valid; } + +private: + bool isDirectSuccessorOf(const llvm::Instruction *Succ, + const llvm::Instruction *Of) { + while (const auto *Nxt = Of->getNextNode()) { + if (Nxt == Succ) { + return true; + } + Of = Nxt; + } + + assert(Of->isTerminator()); + + return std::find_if(llvm::succ_begin(Of), llvm::succ_end(Of), + [&Succ](const llvm::BasicBlock *BB) { + return &BB->front() == Succ; + }) != llvm::succ_end(Of); + } + + void pushCS(const llvm::CallBase *CS) { + auto *NewNode = &CallStackOwner.emplace_back(); + NewNode->Prev = TOS; + NewNode->CS = CS; + TOS = NewNode; + } + + const llvm::CallBase *popCS() noexcept { + assert(TOS && "We should already have checked for nullness..."); + const auto *Ret = TOS->CS; + TOS = TOS->Prev; + /// Defer the deallocation, such that we still can rollback + return Ret; + } + + [[nodiscard]] bool emptyCS() const noexcept { return TOS == nullptr; } + + struct CallStackNode { + CallStackNode *Prev = nullptr; + const llvm::CallBase *CS = nullptr; + }; + /// Now, filter directly on the reversed DAG + + StableVector CallStackOwner; + llvm::SmallVector> CallStackSafe; + CallStackNode *TOS = nullptr; + bool Valid = true; +}; + +class ConstraintPathFilter { +public: + using n_t = const llvm::Instruction *; + + ConstraintPathFilter(LLVMPathConstraints &LPC, + const z3::expr &AdditionalConstraint, + size_t *CompletedCtr) noexcept + : LPC(LPC), Solver(LPC.getContext()), CompletedCtr(*CompletedCtr) { + Solver.add(AdditionalConstraint); + Solver.push(); + NumAtomsStack.push_back(0); + } + + void saveState() { + NumAtomsStack.push_back(NumAtomsStack.back()); + Solver.push(); + } + + void restoreState() { + Solver.pop(); + auto NumAtoms = NumAtomsStack.pop_back_val(); + assert(!NumAtomsStack.empty()); + auto Diff = NumAtoms - NumAtomsStack.back(); + for (size_t I = 0; I < Diff; ++I) { + SymbolicAtoms.pop_back(); + } + NeedSolverInvocation = false; + LocalAtoms.clear(); + Model = std::nullopt; + } + + void saveEdge(n_t Prev, n_t Inst) { + + if (auto ConstrAndVariables = + LPC.getConstraintAndVariablesFromEdge(Prev, Inst)) { + + Solver.add(ConstrAndVariables->Constraint); + + LocalAtoms.append(ConstrAndVariables->Variables); + } + } + + [[nodiscard]] bool isValid() { + ++IsValidCalls; + if (LocalAtoms.empty() && !NeedSolverInvocation) { + /// Nothing (new) to check + return true; + } + + if (!checkLocalAtomsOverlap()) { + return true; + } + + NeedSolverInvocation = false; + + auto Res = Solver.check(); + ++Ctr; +#ifdef DYNAMIC_LOG + if (Ctr % 10000 == 0) { + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + Ctr << " solver invocations so far..."); + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + ">> " << IsValidCalls << " calls to isValid()"); + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + ">> " << RejectedCtr << " paths rejected"); + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + ">> " << CompletedCtr << " paths completed"); + } +#endif + + auto Ret = Res != z3::check_result::unsat; + if (!Ret) { + ++RejectedCtr; + } else { + Model = Solver.get_model(); + } + + return Ret; + } + + bool saveFinalEdge(n_t Prev, n_t FinalInst) { + saveEdge(Prev, FinalInst); + NeedSolverInvocation = true; + return isValid(); + } + + z3::expr getPathConstraints() { + auto Vec = Solver.assertions(); + if (Vec.empty()) { + return LPC.getContext().bool_val(true); + } + + auto Ret = Vec[0]; + for (int I = 1, End = int(Vec.size()); I != End; ++I) { + Ret = Ret && Vec[I]; + } + return Ret.simplify(); + } + + z3::model getModel() { return Model.value(); } + + [[nodiscard]] size_t getNumSolverInvocations() const noexcept { return Ctr; } + +private: + [[nodiscard]] bool checkLocalAtomsOverlap() { + if (NeedSolverInvocation) { + return true; + } + + std::sort(LocalAtoms.begin(), LocalAtoms.end()); + LocalAtoms.erase(std::unique(LocalAtoms.begin(), LocalAtoms.end()), + LocalAtoms.end()); + size_t NumLocalAtoms = LocalAtoms.size(); + size_t OldSize = SymbolicAtoms.size(); + SymbolicAtoms.insert(LocalAtoms.begin(), LocalAtoms.end()); + size_t NewSize = SymbolicAtoms.size(); + LocalAtoms.clear(); + /// The newly added atoms don't overlap with the atoms from the + /// already seen constraints. So, there can be no contradicion (would + /// have already been filtered out in the previous step) + return NewSize - OldSize != NumLocalAtoms; + } + + LLVMPathConstraints &LPC; + z3::solver Solver; + llvm::SmallSetVector SymbolicAtoms; + llvm::SmallVector NumAtomsStack; + llvm::SmallVector LocalAtoms; + std::optional Model; + bool NeedSolverInvocation = false; + + size_t Ctr = 0; + size_t RejectedCtr = 0; + size_t IsValidCalls = 0; + size_t &CompletedCtr; +}; + +auto Z3BasedPathSensitivityManagerBase::filterAndFlattenRevDag( + graph_type &RevDAG, vertex_t Leaf, n_t FinalInst, + const Z3BasedPathSensitivityConfig &Config, LLVMPathConstraints &LPC) const + -> FlowPathSequence { + /// Here, we do the following: + /// - Traversing the ReverseDAG in a simple DFS order and maintaining the + /// exact path reaching the current node. + /// - On the fly constructing and updating a call-stack to regain + /// context-sensitivity by filtering out paths with invalid returns + /// - Similarly on the fly constructing and solving Z3 Path Constraints and + /// filtering out all paths with unsatisfiable constraints + /// - Saving all "surviving" paths that end at a leaf to the overall vector + /// that gets returned at the end + + /// Problem: We still have way too many Z3 solver invocations (> 900000 for + /// all teatcases) + /// Solution idea: In contrast to the context sensitivity check, the Path + /// constraints are context-independent. So, it might be beneficial to + /// compute the end-reachability constraints of each _node_ in a bottom-up + /// fashion leading to PathNodeOwner.size() solver invocations. We then + /// still need a subsequent DFS order traversal to collect all remaining + /// satisfiable paths, so there we can still apply the context-sensitivity + /// check OTF. + /// NOTE: This is implemented now in filterOutUnreachableNodes() + + FlowPathSequence Ret; + size_t CompletedCtr = 0; + auto Filters = makePathFilterList( + CallStackPathFilter{}, + ConstraintPathFilter{ + LPC, + Config.AdditionalConstraint.value_or(LPC.getContext().bool_val(true)), + &CompletedCtr}); + + llvm::SmallVector CurrPath; + + n_t Prev = nullptr; + + auto doFilter = [FinalInst, &Prev, &Filters, &RevDAG, &CurrPath, &Ret, + &CompletedCtr, MaxNumPaths{Config.NumPathsThreshold}, + Leaf](auto &doFilter, vertex_t Vtx) { + auto CurrPathSave = CurrPath.size(); + scope_exit RestoreCurrPath = [&CurrPath, CurrPathSave] { + assert(CurrPathSave <= CurrPath.size()); + CurrPath.resize(CurrPathSave); + }; + + const auto *PrevSave = Prev; + scope_exit RestorePrev = [PrevSave, &Prev] { Prev = PrevSave; }; + + Filters.saveState(); + scope_exit RestoreFilters = [&Filters] { Filters.restoreState(); }; + + for (const auto *Inst : llvm::reverse(graph_traits_t::node(RevDAG, Vtx))) { + CurrPath.push_back(Inst); + if (!Prev) { + Prev = Inst; + continue; + } + + Filters.saveEdge(Prev, Inst); + + Prev = Inst; + } + + if (Vtx == Leaf) { + assert(!CurrPath.empty() && "Reported paths must not be empty!"); + + /// Reached the end + /// TODO: No need to add the final inst separately anymore. Now, it + /// has its own PathNode and is handled implicitly + if (Filters.saveFinalEdge(Prev, FinalInst)) { + auto Model = std::get<1>(Filters).getModel(); + Ret.emplace_back(CurrPath, std::get<1>(Filters).getPathConstraints(), + Model); + ++CompletedCtr; + } + + return; + } + if (graph_traits_t::outDegree(RevDAG, Vtx) == 0) { + llvm::report_fatal_error("Non-leaf node has no successors!"); + } + + if (CompletedCtr >= MaxNumPaths) { + return; + } + if (!Filters.isValid()) { + return; + } + /// TODO: Verify that we have no concurrent modification here and the + /// iterator is never dangling! + for (auto Edge : graph_traits_t::outEdges(RevDAG, Vtx)) { + doFilter(doFilter, graph_traits_t::target(Edge)); + } + }; + + for (auto Rt : graph_traits_t::roots(RevDAG)) { + doFilter(doFilter, Rt); + } + + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + "Num Solver invocations: " + << std::get<1>(Filters).getNumSolverInvocations()); + + return Ret; +} + } // namespace psr diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake new file mode 100644 index 0000000000..8b684505bb --- /dev/null +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake @@ -0,0 +1,25 @@ +set(PHASAR_pathsensitivity_COMPONENT_FOUND 1) + + +list(APPEND + PHASAR_PATHSENSITIVITY_DEPS + utils +) + +foreach(dep ${PHASAR_PATHSENSITIVITY_DEPS}) + message("dsear " ${dep}) + list(APPEND + PHASAR_NEEDED_LIBS + phasar::phasar_${dep} + ) + if(NOT (${PHASAR_${dep}_COMPONENT_FOUND})) + find_package(phasar COMPONENTS ${dep}) + endif() +endforeach() + +find_package(Z3 PATHS ${phasar_DIR}/../../phasar/cmake/z3 NO_DEFAULT_PATH REQUIRED) + +list(APPEND + PHASAR_NEEDED_LIBS + phasar::phasar_pathsensitivity +) From 91fa523fc96126511ea23d0fd90bea9d647cdf71 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 Aug 2022 10:25:08 +0200 Subject: [PATCH 09/65] Implement LLVMPathConstraints --- .../PathSensitivity/LLVMPathConstraints.h | 60 +- include/phasar/Utils/LLVMShorthands.h | 5 + include/phasar/Utils/MaybeUniquePtr.h | 159 +++++ .../PathSensitivity/LLVMPathConstraints.cpp | 658 ++++++++++++++++++ lib/Utils/LLVMShorthands.cpp | 13 + 5 files changed, 891 insertions(+), 4 deletions(-) create mode 100644 include/phasar/Utils/MaybeUniquePtr.h create mode 100644 lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h index 48226e8f0f..580dc8b89c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h @@ -10,26 +10,40 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H -#include "z3++.h" +#include "phasar/Utils/MaybeUniquePtr.h" + #include "llvm/ADT/SmallVector.h" +#include "z3++.h" + #include namespace llvm { class Value; class Instruction; +class AllocaInst; +class LoadInst; +class GetElementPtrInst; +class PHINode; +class BranchInst; +class CmpInst; +class BinaryOperator; +class CallBase; } // namespace llvm namespace psr { class LLVMPathConstraints { - /// TODO: implement public: struct ConstraintAndVariables { z3::expr Constraint; llvm::SmallVector Variables; }; - z3::context &getContext() noexcept { return Z3Context; } + explicit LLVMPathConstraints(z3::context *Z3Ctx = nullptr, + bool IgnoreDebugInstructions = true); + + z3::context &getContext() noexcept { return *Z3Ctx; } + const z3::context &getContext() const noexcept { return *Z3Ctx; } std::optional getConstraintFromEdge(const llvm::Instruction *Curr, const llvm::Instruction *Succ); @@ -39,7 +53,45 @@ class LLVMPathConstraints { const llvm::Instruction *Succ); private: - z3::context Z3Context; + [[nodiscard]] std::optional + internalGetConstraintAndVariablesFromEdge(const llvm::Instruction *From, + const llvm::Instruction *To); + + /// Allocas are the most basic building blocks and represent a leaf value. + [[nodiscard]] ConstraintAndVariables + getAllocaInstAsZ3(const llvm::AllocaInst *Alloca); + + /// Load instrutions may also represent leafs. + [[nodiscard]] ConstraintAndVariables + getLoadInstAsZ3(const llvm::LoadInst *Load); + + /// GEP instructions may also represent leafs. + [[nodiscard]] ConstraintAndVariables + getGEPInstAsZ3(const llvm::GetElementPtrInst *GEP); + + [[nodiscard]] ConstraintAndVariables + handlePhiInstruction(const llvm::PHINode *Phi); + + [[nodiscard]] ConstraintAndVariables + handleCondBrInst(const llvm::BranchInst *Br, const llvm::Instruction *Succ); + + [[nodiscard]] ConstraintAndVariables handleCmpInst(const llvm::CmpInst *Cmp); + + [[nodiscard]] ConstraintAndVariables + handleBinaryOperator(const llvm::BinaryOperator *BinOp); + + [[nodiscard]] ConstraintAndVariables getLiteralAsZ3(const llvm::Value *V); + + [[nodiscard]] ConstraintAndVariables + getFunctionCallAsZ3(const llvm::CallBase *CallSite); + + friend class LLVMPathConstraints; + friend class SizeGuardCheck; + friend class LoopGuardCheck; + + MaybeUniquePtr Z3Ctx; + std::unordered_map Z3Expr; + bool IgnoreDebugInstructions; }; } // namespace psr diff --git a/include/phasar/Utils/LLVMShorthands.h b/include/phasar/Utils/LLVMShorthands.h index 0050d18261..0ca9f59baa 100644 --- a/include/phasar/Utils/LLVMShorthands.h +++ b/include/phasar/Utils/LLVMShorthands.h @@ -61,6 +61,11 @@ llvm::ModuleSlotTracker &getModuleSlotTrackerFor(const llvm::Value *V); */ std::string llvmIRToString(const llvm::Value *V); +/** + * @brief Returns a string representation of a LLVM Type. + */ +std::string llvmTypeToString(const llvm::Type *T); + /** * @brief Similar to llvmIRToString, but removes the metadata from the output as * they are not always stable. Prefer this function over llvmIRToString, if you diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h new file mode 100644 index 0000000000..6715b61844 --- /dev/null +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -0,0 +1,159 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_UTILS_MAYBEUNIQUEPTR_H_ +#define PHASAR_UTILS_MAYBEUNIQUEPTR_H_ + +#include "llvm/ADT/PointerIntPair.h" + +#include +#include + +namespace psr { + +/// A smart-pointer, similar to std::unique_ptr, that can optionally own an +/// object. +template class MaybeUniquePtr { + struct PointerBoolPairFallback { + T *Pointer = nullptr; + bool Flag = false; + + /// Compatibility with llvm::PointerIntPair: + [[nodiscard]] T *getPointer() const noexcept { return Pointer; } + [[nodiscard]] bool getInt() const noexcept { return Flag; } + void setInt(bool Flag) noexcept { this->Flag = Flag; } + }; + +public: + constexpr MaybeUniquePtr() noexcept = default; + + constexpr MaybeUniquePtr(T *Pointer, bool Owns = false) noexcept + : Data{Pointer, Owns} {} + + constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + : MaybeUniquePtr(Owner.release(), true) {} + + template + constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + : MaybeUniquePtr(Owner.release(), true) {} + + constexpr MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept : Data(Other.Data) { + Other.Data = {}; + } + + constexpr void swap(MaybeUniquePtr &Other) noexcept { + std::swap(Data, Other, Data); + } + + constexpr friend void swap(MaybeUniquePtr &LHS, + MaybeUniquePtr &RHS) noexcept { + LHS.swap(RHS); + } + + constexpr MaybeUniquePtr &operator=(MaybeUniquePtr &&Other) noexcept { + swap(Other); + return *this; + } + + constexpr MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {Owner.release(), true}; + return *this; + } + + template + constexpr MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {Owner.release(), true}; + return *this; + } + + MaybeUniquePtr(const MaybeUniquePtr &) = delete; + MaybeUniquePtr &operator=(const MaybeUniquePtr &) = delete; + +#if __cplusplus >= 202002L + constexpr +#endif + ~MaybeUniquePtr() { + if (owns()) { + delete Data.getPointer(); + Data = {}; + } + } + + [[nodiscard]] constexpr T *get() noexcept { return Data.getPointer(); } + [[nodiscard]] constexpr const T *get() const noexcept { + return Data.getPointer(); + } + + [[nodiscard]] constexpr T *operator->() noexcept { return get(); } + [[nodiscard]] constexpr const T *operator->() const noexcept { return get(); } + + [[nodiscard]] constexpr T &operator*() noexcept { return *get(); } + [[nodiscard]] constexpr const T &operator*() const noexcept { return *get(); } + + constexpr T *release() noexcept { + Data.setInt(false); + return Data.getPointer(); + } + + constexpr void reset() noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {}; + } + + [[nodiscard]] constexpr bool owns() const noexcept { + return Data.getInt() && Data.getPointer(); + } + + constexpr friend bool operator==(const MaybeUniquePtr &LHS, + const MaybeUniquePtr &RHS) noexcept { + return LHS.Data.getPointer() == RHS.Data.getPointer(); + } + constexpr friend bool operator!=(const MaybeUniquePtr &LHS, + const MaybeUniquePtr &RHS) noexcept { + return !(LHS == RHS); + } + + constexpr friend bool operator==(const MaybeUniquePtr &LHS, + const T *RHS) noexcept { + return LHS.Data.getPointer() == RHS; + } + constexpr friend bool operator!=(const MaybeUniquePtr &LHS, + const T *RHS) noexcept { + return !(LHS == RHS); + } + + constexpr friend bool operator==(const T *LHS, + const MaybeUniquePtr &RHS) noexcept { + return LHS == RHS.Data.getPointer(); + } + constexpr friend bool operator!=(const T *LHS, + const MaybeUniquePtr &RHS) noexcept { + return !(LHS == RHS); + } + + constexpr explicit operator bool() const noexcept { + return Data.getPointer() != nullptr; + } + +private: + std::conditional_t<(alignof(T) > 1), llvm::PointerIntPair, + PointerBoolPairFallback> + Data{}; +}; +} // namespace psr + +#endif // PHASAR_UTILS_MAYBEUNIQUEPTR_H_ diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp new file mode 100644 index 0000000000..070ff79d19 --- /dev/null +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp @@ -0,0 +1,658 @@ +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/Utils/LLVMShorthands.h" + +#include "llvm/Demangle/Demangle.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" + +namespace psr { +LLVMPathConstraints::LLVMPathConstraints(z3::context *Z3Ctx, + bool IgnoreDebugInstructions) + : Z3Ctx(Z3Ctx), IgnoreDebugInstructions(IgnoreDebugInstructions) { + if (!Z3Ctx) { + this->Z3Ctx = std::make_unique(); + } + Z3_set_ast_print_mode(getContext(), + Z3_ast_print_mode::Z3_PRINT_SMTLIB2_COMPLIANT); +} + +auto LLVMPathConstraints::internalGetConstraintAndVariablesFromEdge( + const llvm::Instruction *From, const llvm::Instruction *To) + -> std::optional { + LLVMBasedCFG CF(IgnoreDebugInstructions); + const auto *BI = llvm::dyn_cast(From); + if (!BI || !BI->isConditional()) { + return std::nullopt; + } + + if (IgnoreDebugInstructions) { + while (const auto *Prev = To->getPrevNonDebugInstruction(false)) { + To = Prev; + } + } else { + while (const auto *Prev = To->getPrevNode()) { + To = Prev; + } + } + + if (CF.isBranchTarget(From, To)) { + return handleCondBrInst(BI, To); + } + + return std::nullopt; +} + +std::optional +LLVMPathConstraints::getConstraintFromEdge(const llvm::Instruction *From, + const llvm::Instruction *To) { + if (auto CV = internalGetConstraintAndVariablesFromEdge(From, To)) { + return CV->Constraint; + } + + return std::nullopt; +} + +auto LLVMPathConstraints::getConstraintAndVariablesFromEdge( + const llvm::Instruction *From, const llvm::Instruction *To) + -> std::optional { + auto CV = internalGetConstraintAndVariablesFromEdge(From, To); + if (CV) { + /// Deduplicate the Variables vector + std::sort(CV->Variables.begin(), CV->Variables.end()); + CV->Variables.erase(std::unique(CV->Variables.begin(), CV->Variables.end()), + CV->Variables.end()); + } + + return CV; +} + +// void LLVMPathConstraints::getConstraintsInPath( +// llvm::ArrayRef Path, +// llvm::SmallVectorImpl &Dest) { +// LLVMBasedCFG CF(IgnoreDebugInstructions); +// for (size_t Idx = 0; Idx < Path.size(); ++Idx) { +// const llvm::Instruction *I = Path[Idx]; +// // handle non-loop flows and collect branch conditions +// const auto *BI = llvm::dyn_cast(I); +// if (!BI || !BI->isConditional()) { +// continue; +// } + +// // llvm::errs() << "Conditional branch on path: " << *BI << '\n'; +// if (Idx + 1 == Path.size()) { +// // llvm::errs() << "> skip: last\n"; +// continue; +// } + +// if (CF.isBranchTarget(I, Path[Idx + 1])) { +// // llvm::errs() << "> add to solver\n"; +// Dest.push_back(handleCondBrInst(BI, Path[Idx + 1]).Constraint); +// } +// // else { +// // llvm::errs() << "> skip: no target: " << *Path[Idx + 1] << '\n'; +// // } +// } +// } + +auto LLVMPathConstraints::handlePhiInstruction(const llvm::PHINode *Phi) + -> ConstraintAndVariables { + auto Search = Z3Expr.find(Phi); + if (Search != Z3Expr.end()) { + return Search->second; + } + const auto *Ty = Phi->getType(); + auto TyConstraints = [&]() { + std::string Name = "PHI"; + if (const auto *IntTy = llvm::dyn_cast(Ty)) { + auto NumBits = IntTy->getBitWidth(); + // case of bool + if (NumBits == 1) { + return Z3Ctx->bool_const(Name.c_str()); + } + // other integers + return Z3Ctx->int_const(Name.c_str()); + } + // case of float types + if (Ty->isFloatTy() || Ty->isDoubleTy()) { + return Z3Ctx->real_const(Name.c_str()); + } + if (Ty->isPointerTy()) { + /// Treat pointers as integers... + return Z3Ctx->bv_const(Name.c_str(), 64); + } + llvm::report_fatal_error("unhandled type of PHI node!"); + }(); + ConstraintAndVariables CAV{Z3Ctx->bool_val(true), {}}; + for (const auto &Incoming : Phi->incoming_values()) { + if (const auto *ConstInt = llvm::dyn_cast(Incoming)) { + if (ConstInt->isOne()) { + CAV.Constraint = CAV.Constraint || Z3Ctx->bool_val(true); + } else if (ConstInt->isZero()) { + CAV.Constraint = CAV.Constraint || Z3Ctx->bool_val(false); + } else { + CAV.Constraint = CAV.Constraint || TyConstraints; + } + } else if (const auto *Load = llvm::dyn_cast(Incoming)) { + auto Ret = getLoadInstAsZ3(Load); + CAV.Constraint = CAV.Constraint || Ret.Constraint; + CAV.Variables.append(Ret.Variables.begin(), Ret.Variables.end()); + } else if (const auto *Call = llvm::dyn_cast(Incoming)) { + auto Ret = getFunctionCallAsZ3(Call); + CAV.Constraint = CAV.Constraint || Ret.Constraint; + CAV.Variables.append(Ret.Variables.begin(), Ret.Variables.end()); + } else if (const auto *Cmp = llvm::dyn_cast(Incoming)) { + auto Ret = handleCmpInst(Cmp); + CAV.Constraint = CAV.Constraint || Ret.Constraint; + CAV.Variables.append(Ret.Variables.begin(), Ret.Variables.end()); + } else { + llvm::outs() << "unhanled phi value: " << *Incoming << '\n'; + llvm::outs().flush(); + llvm::report_fatal_error("unhanled incoming value in PHI node!"); + } + } + return Z3Expr.try_emplace(Phi, CAV).first->second; +} + +auto LLVMPathConstraints::handleCondBrInst(const llvm::BranchInst *Br, + const llvm::Instruction *Succ) + -> ConstraintAndVariables { + // llvm::outs() << "handleCondBrInst\n"; + auto Search = Z3Expr.find(Br); + if (Search != Z3Expr.end()) { + return Search->second; + } + const auto *Cond = Br->getCondition(); + // yes, the true label is indeed operand 2 + const auto *IfTrue = llvm::dyn_cast(Br->getOperand(2)); + const auto *IfFalse = llvm::dyn_cast(Br->getOperand(1)); + + auto GetFirstInst = [IgnoreDebugInstructions{IgnoreDebugInstructions}]( + const llvm::BasicBlock *BB) { + const auto *Ret = &BB->front(); + if (IgnoreDebugInstructions && llvm::isa(Ret)) { + Ret = Ret->getNextNonDebugInstruction(false); + } + return Ret; + }; + + if (const auto *Cmp = llvm::dyn_cast(Cond)) { + if (IfTrue && GetFirstInst(IfTrue) == Succ) { + return handleCmpInst(Cmp); + } + if (IfFalse && GetFirstInst(IfFalse) == Succ) { + auto Ret = handleCmpInst(Cmp); + Ret.Constraint = !Ret.Constraint; + return Ret; + } + } + if (const auto *BinOp = llvm::dyn_cast(Cond)) { + if (IfTrue && GetFirstInst(IfTrue) == Succ) { + return handleBinaryOperator(BinOp); + } + if (IfFalse && GetFirstInst(IfFalse) == Succ) { + auto Ret = handleBinaryOperator(BinOp); + Ret.Constraint = !Ret.Constraint; + return Ret; + } + } + if (const auto *CallSite = llvm::dyn_cast(Cond)) { + if (IfTrue && GetFirstInst(IfTrue) == Succ) { + return getFunctionCallAsZ3(CallSite); + } + if (IfFalse && GetFirstInst(IfFalse) == Succ) { + auto Ret = getFunctionCallAsZ3(CallSite); + Ret.Constraint = !Ret.Constraint; + return Ret; + } + } + // Dirty HACK + if (const auto *Trunc = llvm::dyn_cast(Cond)) { + if (Trunc->getDestTy()->isIntegerTy(1)) { + if (const auto *FromLoad = + llvm::dyn_cast(Trunc->getOperand(0))) { + auto Ret = getLoadInstAsZ3(FromLoad); + Ret.Constraint = (Ret.Constraint % 2 == 1); + return Ret; + } + } + } + if (const auto *Phi = llvm::dyn_cast(Cond)) { + return handlePhiInstruction(Phi); + } + llvm::report_fatal_error( + llvm::StringRef("unhandled conditional branch instruction: '") + + llvmIRToString(Br) + "'!\n"); +} + +auto LLVMPathConstraints::handleCmpInst(const llvm::CmpInst *Cmp) + -> ConstraintAndVariables { + // llvm::outs() << "handleCmpInst\n"; + auto Search = Z3Expr.find(Cmp); + if (Search != Z3Expr.end()) { + return Search->second; + } + const auto *Lhs = Cmp->getOperand(0); + const auto *Rhs = Cmp->getOperand(1); + + auto HandleOperand = [this](const llvm::Value *Op) { + if (const auto *Cast = llvm::dyn_cast(Op)) { + Op = Cast->getOperand(0); + } + + if (const auto *ConstData = llvm::dyn_cast(Op)) { + return getLiteralAsZ3(ConstData); + } + if (const auto *Load = llvm::dyn_cast(Op)) { + if (const auto *Alloca = + llvm::dyn_cast(Load->getPointerOperand())) { + return getAllocaInstAsZ3(Alloca); + } + return getLoadInstAsZ3(Load); + } + if (const auto *BinOpLhs = llvm::dyn_cast(Op)) { + return handleBinaryOperator(BinOpLhs); + } + if (const auto *CallSite = llvm::dyn_cast(Op)) { + return getFunctionCallAsZ3(CallSite); + } + if (const auto *Gep = llvm::dyn_cast(Op)) { + return getGEPInstAsZ3(Gep); + } + llvm::report_fatal_error("unhandled operand: " + + llvm::Twine(llvmIRToString(Op))); + }; + + auto LhsZ3Expr = HandleOperand(Lhs); + auto RhsZ3Expr = HandleOperand(Rhs); + LhsZ3Expr.Variables.append(RhsZ3Expr.Variables); + + switch (Cmp->getPredicate()) { + // Opcode U L G E Intuitive operation + case llvm::CmpInst::Predicate::FCMP_FALSE: ///< 0 0 0 0 Always false + ///< (always folded) + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_OEQ: ///< 0 0 0 1 True if ordered and + ///< equal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_OGT: ///< 0 0 1 0 True if ordered and + ///< greater than + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_OGE: ///< 0 0 1 1 True if ordered and + ///< greater than or equal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_OLT: ///< 0 1 0 0 True if ordered and + ///< less than + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_OLE: ///< 0 1 0 1 True if ordered and + ///< less than or equal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_ONE: ///< 0 1 1 0 True if ordered and + ///< operands are unequal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_ORD: ///< 0 1 1 1 True if ordered (no + ///< nans) + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_UNO: ///< 1 0 0 0 True if unordered: + ///< isnan(X) | isnan(Y) + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_UEQ: ///< 1 0 0 1 True if unordered or + ///< equal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_UGT: ///< 1 0 1 0 True if unordered or + ///< greater than + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_UGE: ///< 1 0 1 1 True if unordered, + ///< greater than, or equal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_ULT: ///< 1 1 0 0 True if unordered or + ///< less than + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_ULE: ///< 1 1 0 1 True if unordered, + ///< less than, or equal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_UNE: ///< 1 1 1 0 True if unordered or + ///< not equal + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::FCMP_TRUE: ///< 1 1 1 1 Always true (always + ///< folded) + llvm::report_fatal_error("unhandled predicate!"); + break; + case llvm::CmpInst::Predicate::ICMP_EQ: ///< equal + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint == RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_NE: ///< not equal + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint != RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_UGT: ///< unsigned greater than + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint > RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_UGE: ///< unsigned greater or equal + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint >= RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_ULT: ///< unsigned less than + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint < RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_ULE: ///< unsigned less or equal + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint <= RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_SGT: ///< signed greater than + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint > RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_SGE: ///< signed greater or equal + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint >= RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_SLT: ///< signed less than + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint < RhsZ3Expr.Constraint; + break; + case llvm::CmpInst::Predicate::ICMP_SLE: ///< signed less or equal + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint < RhsZ3Expr.Constraint; + break; + default: + llvm::report_fatal_error("unhandled predicate!"); + break; + } + + return LhsZ3Expr; +} + +auto LLVMPathConstraints::handleBinaryOperator( + const llvm::BinaryOperator *BinOp) -> ConstraintAndVariables { + auto Search = Z3Expr.find(BinOp); + if (Search != Z3Expr.end()) { + return Search->second; + } + const auto *Lhs = BinOp->getOperand(0); + const auto *Rhs = BinOp->getOperand(1); + + auto HandleOperand = [this](const llvm::Value *Op) { + if (const auto *Cast = llvm::dyn_cast(Op)) { + Op = Cast->getOperand(0); + } + + if (const auto *ConstData = llvm::dyn_cast(Op)) { + return getLiteralAsZ3(ConstData); + } + if (const auto *Load = llvm::dyn_cast(Op)) { + if (const auto *Alloca = + llvm::dyn_cast(Load->getPointerOperand())) { + return getAllocaInstAsZ3(Alloca); + } + return getLoadInstAsZ3(Load); + } + if (const auto *BinOpLhs = llvm::dyn_cast(Op)) { + return handleBinaryOperator(BinOpLhs); + } + if (const auto *CallSite = llvm::dyn_cast(Op)) { + return getFunctionCallAsZ3(CallSite); + } + llvm::report_fatal_error("unhandled operand: " + + llvm::Twine(llvmIRToString(Op))); + }; + + auto LhsZ3Expr = HandleOperand(Lhs); + auto RhsZ3Expr = HandleOperand(Rhs); + LhsZ3Expr.Variables.append(RhsZ3Expr.Variables); + + /// TODO: Once we have bitvectors, we must distinguish between signed and + /// unsigned div/rem operations! + + switch (BinOp->getOpcode()) { + case llvm::Instruction::BinaryOps::Add: + case llvm::Instruction::BinaryOps::FAdd: + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint + RhsZ3Expr.Constraint; + break; + case llvm::Instruction::BinaryOps::Sub: + case llvm::Instruction::BinaryOps::FSub: + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint - RhsZ3Expr.Constraint; + break; + case llvm::Instruction::BinaryOps::Mul: + case llvm::Instruction::BinaryOps::FMul: + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint * RhsZ3Expr.Constraint; + break; + case llvm::Instruction::BinaryOps::UDiv: + case llvm::Instruction::BinaryOps::SDiv: + case llvm::Instruction::BinaryOps::FDiv: + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint / RhsZ3Expr.Constraint; + break; + case llvm::Instruction::BinaryOps::URem: + case llvm::Instruction::BinaryOps::SRem: + case llvm::Instruction::BinaryOps::FRem: + LhsZ3Expr.Constraint = z3::rem(LhsZ3Expr.Constraint, RhsZ3Expr.Constraint); + break; + case llvm::Instruction::BinaryOps::Shl: // Shift left (logical) + LhsZ3Expr.Constraint = z3::shl(LhsZ3Expr.Constraint, RhsZ3Expr.Constraint); + break; + case llvm::Instruction::BinaryOps::LShr: // Shift right (logical) + LhsZ3Expr.Constraint = z3::lshr(LhsZ3Expr.Constraint, RhsZ3Expr.Constraint); + break; + case llvm::Instruction::BinaryOps::AShr: // Shift right (arithmetic) + LhsZ3Expr.Constraint = z3::ashr(LhsZ3Expr.Constraint, RhsZ3Expr.Constraint); + break; + case llvm::Instruction::BinaryOps::And: + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint & RhsZ3Expr.Constraint; + break; + case llvm::Instruction::BinaryOps::Or: + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint | RhsZ3Expr.Constraint; + break; + case llvm::Instruction::BinaryOps::Xor: + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint ^ RhsZ3Expr.Constraint; + break; + default: + llvm::report_fatal_error("unhandled binary opcode!"); + break; + } + + return Z3Expr.try_emplace(BinOp, LhsZ3Expr).first->second; +} + +static llvm::DILocalVariable *getDILocalVariable(const llvm::AllocaInst *A) { + const llvm::Function *Fun = A->getParent()->getParent(); + // Search for llvm.dbg.declare + for (const auto &BB : *Fun) { + for (const auto &I : BB) { + if (const auto *Dbg = llvm::dyn_cast(&I)) { + // found. is it for an AllocaInst? + if (auto *DbgAI = llvm::dyn_cast(Dbg->getAddress())) { + // is it for our AllocaInst? + if (DbgAI == A) { + if (llvm::DILocalVariable *VarMD = Dbg->getVariable()) { + return VarMD; + } + } + } + } + } + } + return nullptr; +} + +static llvm::StringRef getVarName(const llvm::AllocaInst *A) { + auto *VarMD = getDILocalVariable(A); + if (VarMD) { + return VarMD->getName(); + } + if (A->hasName()) { + return A->getName(); + } + return ""; +} + +auto LLVMPathConstraints::getAllocaInstAsZ3(const llvm::AllocaInst *Alloca) + -> ConstraintAndVariables { + auto Search = Z3Expr.find(Alloca); + if (Search != Z3Expr.end()) { + return Search->second; + } + std::string Name = getVarName(Alloca).str(); + const auto *Ty = Alloca->getAllocatedType(); + + if (const auto *IntTy = llvm::dyn_cast(Ty)) { + auto NumBits = IntTy->getBitWidth(); + // case of bool + if (NumBits == 1) { + auto BoolConst = Z3Ctx->bool_const(Name.c_str()); + return Z3Expr + .try_emplace(Alloca, ConstraintAndVariables{BoolConst, {Alloca}}) + .first->second; + } + // other integers + auto IntConst = Z3Ctx->int_const(Name.c_str()); + return Z3Expr + .try_emplace(Alloca, ConstraintAndVariables{IntConst, {Alloca}}) + .first->second; + } + // case of float types + if (Ty->isFloatTy() || Ty->isDoubleTy()) { + auto RealConst = Z3Ctx->real_const(Name.c_str()); + return Z3Expr + .try_emplace(Alloca, ConstraintAndVariables{RealConst, {Alloca}}) + .first->second; + } + if (Ty->isPointerTy()) { + /// Treat pointers as integers... + return Z3Expr + .try_emplace( + Alloca, + ConstraintAndVariables{Z3Ctx->bv_const(Name.c_str(), 64), {Alloca}}) + .first->second; + } + llvm::report_fatal_error( + "unsupported type: " + llvm::Twine(llvmTypeToString(Ty)) + " at " + + llvmIRToString(Alloca) + " in function " + + Alloca->getFunction()->getName().str()); +} + +auto LLVMPathConstraints::getLoadInstAsZ3(const llvm::LoadInst *Load) + -> ConstraintAndVariables { + auto Search = Z3Expr.find(Load); + if (Search != Z3Expr.end()) { + return Search->second; + } + if (const auto *Alloca = + llvm::dyn_cast(Load->getPointerOperand())) { + return getAllocaInstAsZ3(Alloca); + } + // do not follow GEP instructions + if (const auto *GEP = + llvm::dyn_cast(Load->getPointerOperand())) { + return getGEPInstAsZ3(GEP); + } + // track down alloca or GEP + llvm::SmallVector Worklist = {Load}; + while (!Worklist.empty()) { + const auto *WorkV = Worklist.pop_back_val(); + // llvm::outs() << "Load-Val: " << *WorkV << '\n'; + if (const auto *Alloca = llvm::dyn_cast(WorkV)) { + return getAllocaInstAsZ3(Alloca); + } + if (const auto *GEP = llvm::dyn_cast(WorkV)) { + return getGEPInstAsZ3(GEP); + } + if (const auto *Inst = llvm::dyn_cast(WorkV)) { + Worklist.append(Inst->op_begin(), Inst->op_end()); + } + } + llvm::report_fatal_error("unsupported load!"); +} + +auto LLVMPathConstraints::getGEPInstAsZ3(const llvm::GetElementPtrInst *GEP) + -> ConstraintAndVariables { + std::string Name = + (GEP->hasName()) ? GEP->getName().str() : "gep" + psr::getMetaDataID(GEP); + + /// TODO: Unify different GEPs of same memory locations + const auto *Ty = GEP->getResultElementType(); + if (const auto *IntTy = llvm::dyn_cast(Ty)) { + auto NumBits = IntTy->getBitWidth(); + // case of bool + if (NumBits == 1) { + auto BoolConst = Z3Ctx->bool_const(Name.c_str()); + return Z3Expr.try_emplace(GEP, ConstraintAndVariables{BoolConst, {GEP}}) + .first->second; + } + // other integers + auto IntConst = Z3Ctx->int_const(Name.c_str()); + // also add value constraints to the solver + // FIXME + // if (isSignedInteger(GEP)) { + // auto Range = IntConst >= std::numeric_limits::min() && + // IntConst <= std::numeric_limits::max(); + // Z3Solver.add(Range); + // } else if (isUnsignedInteger(GEP)) { + // Z3 only supports plain 'int' + // Z3Solver.add(Range); + // } + return Z3Expr.try_emplace(GEP, ConstraintAndVariables{IntConst, {GEP}}) + .first->second; + } + // case of float types + if (Ty->isFloatTy() || Ty->isDoubleTy()) { + auto RealConst = Z3Ctx->real_const(Name.c_str()); + return Z3Expr.try_emplace(GEP, ConstraintAndVariables{RealConst, {GEP}}) + .first->second; + } + // some other pointer, we can treat those as integers + if (const auto *PointerTy = + llvm::dyn_cast(GEP->getPointerOperandType())) { + auto PointerConst = Z3Ctx->bv_const(Name.c_str(), 64); + return Z3Expr.try_emplace(GEP, ConstraintAndVariables{PointerConst, {GEP}}) + .first->second; + } + llvm::report_fatal_error("unsupported GEP type!"); +} + +auto LLVMPathConstraints::getLiteralAsZ3(const llvm::Value *V) + -> ConstraintAndVariables { + if (const auto *CI = llvm::dyn_cast(V)) { + return {Z3Ctx->int_val(CI->getSExtValue()), {}}; + } + if (const auto *CF = llvm::dyn_cast(V)) { + return {Z3Ctx->fpa_val(CF->getValue().convertToDouble()), {}}; + } + if (llvm::isa(V)) { + return {Z3Ctx->bv_val(0, 64), {}}; + } + llvm::report_fatal_error("unhandled literal!"); +} + +auto LLVMPathConstraints::getFunctionCallAsZ3(const llvm::CallBase *CallSite) + -> ConstraintAndVariables { + if (const auto *Callee = CallSite->getCalledFunction()) { + if (Callee->hasName()) { + auto DemangledName = llvm::demangle(Callee->getName().str()); + const auto *ReturnTy = Callee->getReturnType(); + if (ReturnTy->isFloatingPointTy()) { + return {Z3Ctx->real_const(DemangledName.c_str()), {Callee}}; + } + if (ReturnTy->isIntegerTy()) { + // case of bool + if (ReturnTy->getIntegerBitWidth() == 1) { + return {Z3Ctx->bool_const(DemangledName.c_str()), {Callee}}; + } + return {Z3Ctx->int_const(DemangledName.c_str()), {Callee}}; + } + if (ReturnTy->isPointerTy()) { + return {Z3Ctx->bv_const(DemangledName.c_str(), 64), {Callee}}; + } + } + } + llvm::report_fatal_error("unhandled function call!"); +} + +} // namespace psr \ No newline at end of file diff --git a/lib/Utils/LLVMShorthands.cpp b/lib/Utils/LLVMShorthands.cpp index b8c794647f..adb4b67b0b 100644 --- a/lib/Utils/LLVMShorthands.cpp +++ b/lib/Utils/LLVMShorthands.cpp @@ -165,6 +165,19 @@ std::string llvmIRToString(const llvm::Value *V) { return IRBuffer; } +std::string llvmTypeToString(const llvm::Type *T) { + // WARNING: Expensive function, cause is the T->print(RSO) + // (20ms on a medium size code (phasar without debug) + // 80ms on a huge size code (clang without debug), + // can be multiplied by times 3 to 5 if passes are enabled) + std::string IRBuffer; + llvm::raw_string_ostream RSO(IRBuffer); + T->print(RSO); + RSO.flush(); + boost::trim_left(IRBuffer); + return IRBuffer; +} + std::string llvmIRToStableString(const llvm::Value *V) { if (!V) { return ""; From cada9f1df3127e7e392a5a46e37e31b8da51a8c4 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 Aug 2022 12:15:53 +0200 Subject: [PATCH 10/65] Add unittest for PathTracking (C/C++ test files are still missing) and resolve a lot of compilation errors --- .../PathSensitivity/ExplodedSuperGraph.h | 8 +- .../PathSensitivity/PathSensitivityConfig.h | 24 +- .../PathSensitivityManagerBase.h | 25 +- .../PathSensitivityManagerMixin.h | 33 +- .../Z3BasedPathSensitivityConfig.h | 3 +- .../Z3BasedPathSensitvityManager.h | 71 +- include/phasar/Utils/DFAMinimizer.h | 2 +- include/phasar/Utils/DebugOutput.h | 6 +- include/phasar/Utils/MaybeUniquePtr.h | 63 +- .../Z3BasedPathSensitivityManager.cpp | 14 + .../PhasarLLVM/DataFlowSolver/CMakeLists.txt | 2 + .../PathSensitivity/CMakeLists.txt | 7 + .../PathSensitivity/PathTracingTest.cpp | 639 ++++++++++++++++++ 13 files changed, 802 insertions(+), 95 deletions(-) create mode 100644 unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt create mode 100644 unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h index 17113bd909..40b63a90c0 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h @@ -132,12 +132,12 @@ template class ExplodedSuperGraph { for (const auto &Nod : NodeOwner) { OS << intptr_t(&Nod) << "[label=\""; - OS.write_escaped(DPrinter.DtoString(Nod.value)) << "\"];\n"; + OS.write_escaped(DPrinter.DtoString(Nod.Value)) << "\"];\n"; - OS << intptr_t(&Nod) << "->" << intptr_t(Nod.predecessor) + OS << intptr_t(&Nod) << "->" << intptr_t(Nod.Predecessor) << R"([style="bold" label=")"; - OS.write_escaped(NPrinter.NtoString(Nod.source)) << "\"];\n"; - for (auto *NB : Nod.neighbors) { + OS.write_escaped(NPrinter.NtoString(Nod.Source)) << "\"];\n"; + for (auto *NB : Nod.Neighbors) { OS << intptr_t(&Nod) << "->" << intptr_t(NB) << "[color=\"red\"];\n"; } } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h index 53ecbbfeda..19ed92ebc6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h @@ -14,40 +14,44 @@ #include namespace psr { -struct PathSensitivityConfig { + +template struct PathSensitivityConfigBase { size_t DAGSizeThreshold = SIZE_MAX; size_t DAGDepthThreshold = SIZE_MAX; size_t NumPathsThreshold = SIZE_MAX; bool MinimizeDAG = true; - [[nodiscard]] PathSensitivityConfig + [[nodiscard]] DerivedConfig withDAGSizeThreshold(size_t MaxDAGSize) const noexcept { - auto Ret = *this; + auto Ret = *static_cast(this); Ret.DAGSizeThreshold = MaxDAGSize; return Ret; } - [[nodiscard]] PathSensitivityConfig + [[nodiscard]] DerivedConfig withDAGDepthThreshold(size_t MaxDAGDepth) const noexcept { - auto Ret = *this; + auto Ret = *static_cast(this); Ret.DAGDepthThreshold = MaxDAGDepth; return Ret; } - [[nodiscard]] PathSensitivityConfig + [[nodiscard]] DerivedConfig withNumPathsThreshold(size_t MaxNumPaths) const noexcept { - auto Ret = *this; + auto Ret = *static_cast(this); Ret.NumPathsThreshold = MaxNumPaths; return Ret; } - [[nodiscard]] PathSensitivityConfig - withMinimizeDAG(bool DoMinimize) const noexcept { - auto Ret = *this; + [[nodiscard]] DerivedConfig withMinimizeDAG(bool DoMinimize) const noexcept { + auto Ret = *static_cast(this); Ret.MinimizeDAG = DoMinimize; return Ret; } }; + +struct PathSensitivityConfig + : PathSensitivityConfigBase {}; + } // namespace psr #endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h index e3d648b64b..59dc1e9fd2 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h @@ -17,6 +17,10 @@ #include "llvm/ADT/SmallVector.h" namespace psr { + +template +class PathSensitivityManagerMixin; + template class PathSensitivityManagerBase { public: using n_t = N; @@ -24,13 +28,16 @@ template class PathSensitivityManagerBase { static_assert(std::is_integral_v::vertex_t>); + template + friend class PathSensitivityManagerMixin; + protected: using graph_traits_t = GraphTraits; using vertex_t = typename graph_traits_t::vertex_t; private: - bool assertIsDAG(const graph_type &Dag) { - llvm::BitVector Visited(Dag.size()); + bool assertIsDAG(const graph_type &Dag) const { + llvm::BitVector Visited(graph_traits_t::size(Dag)); llvm::DenseSet CurrPath; CurrPath.reserve(graph_traits_t::size(Dag)); @@ -60,11 +67,17 @@ template class PathSensitivityManagerBase { return true; }; - return doAssertIsDAG(doAssertIsDAG, Dag.Root); + for (auto Rt : graph_traits_t::roots(Dag)) { + if (!doAssertIsDAG(doAssertIsDAG, Rt)) { + return false; + } + } + + return true; } graph_type reverseDAG(graph_type &&Dag, const llvm::IntEqClasses &Equiv, - size_t MaxDepth = SIZE_MAX) { + size_t MaxDepth = SIZE_MAX) const { struct ReverseDAGContext { llvm::SmallVector Cache; @@ -128,7 +141,9 @@ template class PathSensitivityManagerBase { return Rev; }; - buildReverseDag(buildReverseDag, Dag.Root); + for (auto Rt : graph_traits_t::roots(Dag)) { + buildReverseDag(buildReverseDag, Rt); + } return Ret; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index d24fe870e3..009bc6b18f 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -23,8 +23,8 @@ class PathSensitivityManagerMixin { using n_t = typename AnalysisDomainTy::n_t; using d_t = typename AnalysisDomainTy::d_t; - static ExplodedSuperGraph & - assertNotNull(ExplodedSuperGraph *ESG) noexcept { + static const ExplodedSuperGraph & + assertNotNull(const ExplodedSuperGraph *ESG) noexcept { assert(ESG != nullptr && "The exploded supergraph passed to the " "pathSensitivityManager must not be nullptr!"); return *ESG; @@ -87,12 +87,10 @@ class PathSensitivityManagerMixin { }; bool pathsToImplLAInvoke(vertex_t Ret, Node *Vtx, PathsToContext &Ctx, - graph_type &RetDag, bool AutoSkipZero) { + graph_type &RetDag) const { // NOLINTNEXTLINE(readability-identifier-naming) - auto reachedEnd = [this, AutoSkipZero](Node *Vtx) { - return !Vtx || (AutoSkipZero && Vtx->Value == ESG.getZeroValue()); - }; + auto reachedEnd = [](Node *Vtx) { return !Vtx; }; do { graph_traits_t::node(RetDag, Ret).push_back(Vtx->Source); @@ -110,8 +108,8 @@ class PathSensitivityManagerMixin { scope_exit PopRet = [&Ctx] { Ctx.CurrPath.pop_back(); }; // NOLINTNEXTLINE(readability-identifier-naming) - auto traverseNext = [&Ctx, this, Ret, &RetDag, AutoSkipZero](Node *Nxt) { - auto Succ = pathsToImplLA(Nxt, Ctx, RetDag, AutoSkipZero); + auto traverseNext = [&Ctx, this, Ret, &RetDag](Node *Nxt) { + auto Succ = pathsToImplLA(Nxt, Ctx, RetDag); if (Succ != graph_traits_t::Invalid && !Ctx.CurrPath.contains(Succ)) { graph_traits_t::addEdge(RetDag, Ret, Succ); } @@ -128,8 +126,8 @@ class PathSensitivityManagerMixin { return graph_traits_t::outDegree(RetDag, Ret) != 0; } - vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, graph_type &RetDag, - bool AutoSkipZero) { + vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, + graph_type &RetDag) const { /// Idea: Treat the graph as firstChild-nextSibling notation and always /// traverse with one predecessor lookAhead @@ -138,11 +136,12 @@ class PathSensitivityManagerMixin { return It->second; } - auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); + auto Ret = + graph_traits_t::addNode(RetDag, typename graph_traits_t::value_type()); // auto Ret = RetDag.addNode(); It->second = Ret; - if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag, AutoSkipZero)) { + if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag)) { /// NOTE: Don't erase Vtx from Cache to guarantee termination Ctx.Cache[Vtx] = graph_traits_t::Invalid; @@ -164,24 +163,24 @@ class PathSensitivityManagerMixin { return Ret; } - vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag, - bool AutoSkipZero) { + vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag) const { assert(Vtx->Source != QueryInst); - auto Ret = graph_traits_t::addNode(RetDag, graph_traits_t::value_type()); + auto Ret = + graph_traits_t::addNode(RetDag, typename graph_traits_t::value_type()); graph_traits_t::node(RetDag, Ret).push_back(QueryInst); // RetDag.PartialPath[Ret].push_back(QueryInst); PathsToContext Ctx; for (auto *NB : Vtx->Neighbors) { - auto NBNode = pathsToImplLA(NB, Ctx, RetDag, AutoSkipZero); + auto NBNode = pathsToImplLA(NB, Ctx, RetDag); if (NBNode != graph_traits_t::Invalid) { graph_traits_t::addEdge(RetDag, Ret, NBNode); // Succs.push_back(NBNode); } } - auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag, AutoSkipZero); + auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag); if (VtxNode != graph_traits_t::Invalid) { graph_traits_t::addEdge(RetDag, Ret, VtxNode); // Succs.push_back(VtxNode); diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h index de573d10b6..fc7a79ec28 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h @@ -17,7 +17,8 @@ #include namespace psr { -struct Z3BasedPathSensitivityConfig : PathSensitivityConfig { +struct Z3BasedPathSensitivityConfig + : PathSensitivityConfigBase { std::optional AdditionalConstraint; [[nodiscard]] Z3BasedPathSensitivityConfig diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h index a0c8f490fd..a53ff1c213 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -15,11 +15,15 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" #include "phasar/Utils/GraphTraits.h" - #include "phasar/Utils/Logger.h" -#include "z3++.h" +#include "phasar/Utils/MaybeUniquePtr.h" + #include "llvm/Support/ErrorHandling.h" +#include "z3++.h" + +#include +#include #include namespace llvm { @@ -47,18 +51,7 @@ class Z3BasedPathSensitivityManagerBase const Z3BasedPathSensitivityConfig &Config, LLVMPathConstraints &LPC) const; - void deduplicatePaths(FlowPathSequence &Paths) { - /// Some kind of lexical sort for being able to deduplicate the paths easily - std::sort(Paths.begin(), Paths.end(), - [](const FlowPath &LHS, const FlowPath &RHS) { - return LHS.size() < RHS.size() || - (LHS.size() == RHS.size() && - std::lexicographical_compare(LHS.begin(), LHS.end(), - RHS.begin(), RHS.end())); - }); - - Paths.erase(std::unique(Paths.begin(), Paths.end()), Paths.end()); - } + static void deduplicatePaths(FlowPathSequence &Paths); }; template ::graph_type; using MaybeFlowPathSeq = std::variant, z3::expr>; - Z3BasedPathSensitivityManager( - const ExplodedSuperGraph *ESG) noexcept - : mixin_t(ESG) {} + explicit Z3BasedPathSensitivityManager( + const ExplodedSuperGraph *ESG, + Z3BasedPathSensitivityConfig Config, LLVMPathConstraints *LPC = nullptr) + : mixin_t(ESG), Config(std::move(Config)), LPC(LPC) { + if (!LPC) { + this->LPC = std::make_unique(); + } + } + + FlowPathSequence pathsTo(n_t Inst, d_t Fact) const { + if (Config.DAGSizeThreshold != SIZE_MAX) { + PHASAR_LOG_LEVEL( + WARNING, + "Attempting to compute FlowPaths without conditionally " + "falling back to constraint collection, but a DAGSizeThreshold " + "is specified. It will be ignored here. To make use of it, " + "please call the pathsOrConstraintTo function instead!"); + } - FlowPathSequence pathsTo(n_t Inst, d_t Fact, - const Z3BasedPathSensitivityConfig &Config, - LLVMPathConstraints &LPC) const { graph_type Dag = this->pathsDagTo(Inst, std::move(Fact)); vertex_t Leaf = [&Dag] { @@ -98,7 +103,7 @@ class Z3BasedPathSensitivityManager llvm_unreachable("Expect the DAG to have a leaf node!"); }(); - z3::expr Constraint = filterOutUnreachableNodes(Dag, Leaf, Config, LPC); + z3::expr Constraint = filterOutUnreachableNodes(Dag, Leaf, Config, *LPC); if (Constraint.is_false()) { PHASAR_LOG_LEVEL_CAT(INFO, "PathSensitivityManager", @@ -106,17 +111,17 @@ class Z3BasedPathSensitivityManager return FlowPathSequence(); } - if (graph_traits_t::size(Dag) > Config.DAGSizeThreshold) { - PHASAR_LOG_LEVEL_CAT( - INFO, "PathSensitivityManager", - "Note: The DAG for query @ " - << getMetaDataID(Inst) - << " is too large. Don't collect the precise paths " - "here"); - return Constraint; - } + // if (graph_traits_t::size(Dag) > Config.DAGSizeThreshold) { + // PHASAR_LOG_LEVEL_CAT( + // INFO, "PathSensitivityManager", + // "Note: The DAG for query @ " + // << getMetaDataID(Inst) + // << " is too large. Don't collect the precise paths " + // "here"); + // return Constraint; + // } - auto Ret = filterAndFlattenRevDag(Dag, Leaf, Inst, Config, LPC); + auto Ret = filterAndFlattenRevDag(Dag, Leaf, Inst, Config, *LPC); deduplicatePaths(Ret); @@ -142,6 +147,10 @@ class Z3BasedPathSensitivityManager return Ret; } + +private: + Z3BasedPathSensitivityConfig Config{}; + MaybeUniquePtr LPC{}; }; } // namespace psr diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 7443fef26a..b2bcd7bd92 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -28,7 +28,7 @@ template using vertex_t = typename traits_t::vertex_t; using edge_t = typename traits_t::edge_t; - auto DagSize = G.size(); + auto DagSize = traits_t::size(G); llvm::SmallVector> WorkList; WorkList.reserve(DagSize); diff --git a/include/phasar/Utils/DebugOutput.h b/include/phasar/Utils/DebugOutput.h index 1ca162f342..1ab0621279 100644 --- a/include/phasar/Utils/DebugOutput.h +++ b/include/phasar/Utils/DebugOutput.h @@ -98,9 +98,9 @@ template struct PrettyPrinter { }; template -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const PrettyPrinter &P) { - OS << P; +std::ostream &operator<<(std::ostream &OS, const PrettyPrinter &P) { + llvm::raw_os_ostream ROS(OS); + ROS << P; return OS; } diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index 6715b61844..8f9b7440ec 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -17,24 +17,51 @@ namespace psr { -/// A smart-pointer, similar to std::unique_ptr, that can optionally own an -/// object. -template class MaybeUniquePtr { +namespace detail { +template class MaybeUniquePtrBase { +protected: struct PointerBoolPairFallback { T *Pointer = nullptr; bool Flag = false; /// Compatibility with llvm::PointerIntPair: - [[nodiscard]] T *getPointer() const noexcept { return Pointer; } - [[nodiscard]] bool getInt() const noexcept { return Flag; } - void setInt(bool Flag) noexcept { this->Flag = Flag; } + [[nodiscard]] constexpr T *getPointer() const noexcept { return Pointer; } + [[nodiscard]] constexpr bool getInt() const noexcept { return Flag; } + constexpr void setInt(bool Flag) noexcept { this->Flag = Flag; } }; + std::conditional_t<(alignof(T) > 1), llvm::PointerIntPair, + PointerBoolPairFallback> + Data{}; + + constexpr MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + constexpr MaybeUniquePtrBase() noexcept = default; +}; + +template class MaybeUniquePtrBase { +protected: + llvm::PointerIntPair Data{}; + + constexpr MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + constexpr MaybeUniquePtrBase() noexcept = default; +}; +} // namespace detail + +/// A smart-pointer, similar to std::unique_ptr, that can optionally own an +/// object. +/// +/// \tparam T The pointee type +/// \tparam RequireAlignment If true, the datastructure only works if alignof(T) +/// > 1 holds. Enables incomplete T types +template +class MaybeUniquePtr : detail::MaybeUniquePtrBase { + using detail::MaybeUniquePtrBase::Data; + public: constexpr MaybeUniquePtr() noexcept = default; constexpr MaybeUniquePtr(T *Pointer, bool Owns = false) noexcept - : Data{Pointer, Owns} {} + : detail::MaybeUniquePtrBase(Pointer, Owns) {} constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} @@ -43,9 +70,9 @@ template class MaybeUniquePtr { constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} - constexpr MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept : Data(Other.Data) { - Other.Data = {}; - } + constexpr MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept + : detail::MaybeUniquePtrBase( + std::exchange(Other.Data, {})) {} constexpr void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other, Data); @@ -91,16 +118,11 @@ template class MaybeUniquePtr { } } - [[nodiscard]] constexpr T *get() noexcept { return Data.getPointer(); } - [[nodiscard]] constexpr const T *get() const noexcept { - return Data.getPointer(); - } + [[nodiscard]] constexpr T *get() const noexcept { return Data.getPointer(); } - [[nodiscard]] constexpr T *operator->() noexcept { return get(); } - [[nodiscard]] constexpr const T *operator->() const noexcept { return get(); } + [[nodiscard]] constexpr T *operator->() const noexcept { return get(); } - [[nodiscard]] constexpr T &operator*() noexcept { return *get(); } - [[nodiscard]] constexpr const T &operator*() const noexcept { return *get(); } + [[nodiscard]] constexpr T &operator*() const noexcept { return *get(); } constexpr T *release() noexcept { Data.setInt(false); @@ -148,11 +170,6 @@ template class MaybeUniquePtr { constexpr explicit operator bool() const noexcept { return Data.getPointer() != nullptr; } - -private: - std::conditional_t<(alignof(T) > 1), llvm::PointerIntPair, - PointerBoolPairFallback> - Data{}; }; } // namespace psr diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp index 06df06f1b1..c1e2a91a41 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -526,4 +526,18 @@ auto Z3BasedPathSensitivityManagerBase::filterAndFlattenRevDag( return Ret; } +void Z3BasedPathSensitivityManagerBase::deduplicatePaths( + FlowPathSequence &Paths) { + /// Some kind of lexical sort for being able to deduplicate the paths easily + std::sort(Paths.begin(), Paths.end(), + [](const FlowPath &LHS, const FlowPath &RHS) { + return LHS.size() < RHS.size() || + (LHS.size() == RHS.size() && + std::lexicographical_compare(LHS.begin(), LHS.end(), + RHS.begin(), RHS.end())); + }); + + Paths.erase(std::unique(Paths.begin(), Paths.end()), Paths.end()); +} + } // namespace psr diff --git a/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt b/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt index 1f8fa8bb13..71bdea6b4e 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt @@ -1,3 +1,5 @@ add_subdirectory(IfdsIde) add_subdirectory(Mono) add_subdirectory(WPDS) +add_subdirectory(PathSensitivity) + diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt new file mode 100644 index 0000000000..731fee62b0 --- /dev/null +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt @@ -0,0 +1,7 @@ +add_phasar_unittest(PathTracingTest.cpp) + +target_link_libraries(PathTracingTest + LINK_PUBLIC + phasar_pathsensitivity + z3 +) diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp new file mode 100644 index 0000000000..79e12991c5 --- /dev/null +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp @@ -0,0 +1,639 @@ +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include + +#include "TestConfig.h" + +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" + +#include "phasar/DB/ProjectIRDB.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h" +#include "phasar/PhasarLLVM/Passes/ValueAnnotationPass.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" +#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/Utils/DebugOutput.h" +#include "phasar/Utils/LLVMShorthands.h" +#include "phasar/Utils/Logger.h" + +// ============== TEST FIXTURE ============== // +class PathTracingTest : public ::testing::Test { +protected: + const std::string PathToLlFiles = + psr::unittest::PathToLLTestFiles + "path_tracing/"; + + std::unique_ptr IRDB; + psr::LLVMPathConstraints LPC; + + void SetUp() override { psr::ValueAnnotationPass::resetValueID(); } + + std::pair + getInterestingInstFact() { + auto *Main = IRDB->getFunctionDefinition("main"); + assert(Main); + auto *LastInst = &Main->back().back(); + auto *InterestingFact = [&] { + if (auto *RetInst = llvm::dyn_cast(LastInst); + RetInst && RetInst->getReturnValue() && + !llvm::isa(RetInst->getReturnValue())) { + return RetInst->getReturnValue(); + } + + auto *Inst = LastInst->getPrevNode(); + while (Inst && !Inst->getType()->isIntegerTy()) { + Inst = Inst->getPrevNode(); + } + assert(Inst != nullptr); + return static_cast(Inst); + }(); + + return {LastInst, InterestingFact}; + } + + psr::FlowPathSequence + doAnalysis(const std::string &LlvmFilePath, bool PrintDump = false) { + auto IrFiles = {PathToLlFiles + LlvmFilePath}; + IRDB = std::make_unique(IrFiles, psr::IRDBOptions::WPA); + psr::LLVMTypeHierarchy TH(*IRDB); + psr::LLVMPointsToSet PT(*IRDB); + psr::LLVMBasedICFG ICFG(*IRDB, psr::CallGraphAnalysisType::OTF, {"main"}, + &TH, &PT, psr::Soundness::Soundy, + /*IncludeGlobals*/ false); + psr::IDELinearConstantAnalysis LCAProblem(IRDB.get(), &TH, &ICFG, &PT, + {"main"}); + psr::PathAwareIDESolver LCASolver(LCAProblem); + LCASolver.solve(); + if (PrintDump) { + // IRDB->print(); + // ICFG.print(); + // LCASolver.dumpResults(); + std::error_code EC; + llvm::raw_fd_ostream ROS(LlvmFilePath + "_explicit_esg.dot", EC); + assert(!EC); + LCASolver.getExplicitESG().printAsDot(ROS); + } + auto [LastInst, InterestingFact] = getInterestingInstFact(); + llvm::outs() << "Target instruction: " << psr::llvmIRToString(LastInst); + llvm::outs() << "\nTarget data-flow fact: " + << psr::llvmIRToString(InterestingFact) << '\n'; + + psr::Z3BasedPathSensitivityManager + PSM(&LCASolver.getExplicitESG(), {}, &LPC); + + return PSM.pathsTo(LastInst, InterestingFact); + } + + // psr::FlowPathSequence + // doTaintAnalysis(const std::string &LlvmFilePath, bool PrintDump = false) + // { + // auto IrFiles = {PathToLlFiles + LlvmFilePath}; + // IRDB = std::make_unique(IrFiles, + // psr::IRDBOptions::WPA); psr::LLVMTypeHierarchy TH(*IRDB); + // psr::LLVMPointsToSet PT(*IRDB); + // psr::LLVMBasedICFG ICFG(*IRDB, psr::CallGraphAnalysisType::OTF, + // {"main"}, + // &TH, &PT, psr::Soundness::Soundy, + // /*IncludeGlobals*/ false); + // psr::TaintConfig Config(*IRDB); + // psr::IDEExtendedTaintAnalysis<3, false> TaintProblem(IRDB.get(), &TH, + // &ICFG, + // &PT, Config, + // {"main"}); + // psr::PathAwareIDESolver Solver(TaintProblem); + // Solver.solve(); + // if (PrintDump) { + // // IRDB->print(); + // // ICFG.print(); + // // LCASolver.dumpResults(); + // std::error_code EC; + // llvm::raw_fd_ostream ROS(LlvmFilePath + "_explicit_esg.dot", EC); + // assert(!EC); + // Solver.getExplicitESG().printAsDot(ROS); + // } + // // auto &Leaks = TaintProblem.getAllLeaks(); + // // llvm::errs() << "Num Leaks: " << Leaks.size() << '\n'; + // // auto [LastInst, LeakVals] = *Leaks.begin(); + // // llvm::errs() << "Num first leaks: " << LeakVals.size() << '\n'; + // // auto [LeakVal, InterestingFact] = *LeakVals.begin(); + // // // auto [LastInst, InterestingFact] = getInterestingInstFact(); + // // // llvm::outs() << "Target instruction: " << + // // psr::llvmIRToString(LastInst); + // // // llvm::outs() << "\nTarget data-flow fact: " + // // // << psr::llvmIRToString(InterestingFact) << '\n'; + // // return Solver.pathsTo(LastInst, InterestingFact); + + // psr::Z3BasedPathSensitivityManager + // PSM( + // &Solver.getExplicitESG(), {}, &LPC); + + // for (auto [Inst, Leaks] : TaintProblem.getAllLeaks()) { + // for (auto [LeakVal, LeakFact] : Leaks) { + // [[maybe_unused]] auto _ = PSM.pathsTo(Inst, LeakFact, LPC); + // } + // } + + // return {}; + // } + + psr::FlowPathSequence + doLambdaAnalysis(const std::string &LlvmFilePath, + size_t MaxDAGDepth = SIZE_MAX) { + auto IrFiles = {PathToLlFiles + LlvmFilePath}; + IRDB = std::make_unique(IrFiles, psr::IRDBOptions::WPA); + psr::LLVMTypeHierarchy TH(*IRDB); + psr::LLVMPointsToSet PT(*IRDB); + psr::LLVMBasedICFG ICFG(*IRDB, psr::CallGraphAnalysisType::OTF, {"main"}, + &TH, &PT, psr::Soundness::Soundy, + /*IncludeGlobals*/ false); + + // psr::IFDSSolverTest Analysis(IRDB.get(), &TH, &ICFG, &PT, {"main"}, + // true); + // psr::IFDSSolver Solver(Analysis); + psr::TaintConfig Config(*IRDB, nlohmann::json{}); + psr::IDEExtendedTaintAnalysis<3, false> Analysis(IRDB.get(), &TH, &ICFG, + &PT, Config, {"main"}); + psr::PathAwareIDESolver Solver(Analysis); + Solver.solve(); + + // std::ofstream Ofs(LlvmFilePath + "_lambda_esg.dot"); + // Solver.printAsDot(Ofs); + + auto *Main = IRDB->getFunctionDefinition("main"); + assert(Main); + auto *LastInst = &Main->back().back(); + llvm::outs() << "Target instruction: " << psr::llvmIRToString(LastInst) + << '\n'; + + psr::Z3BasedPathSensitivityManager PSM( + &Solver.getExplicitESG(), + psr::Z3BasedPathSensitivityConfig().withDAGDepthThreshold(MaxDAGDepth), + &LPC); + + return PSM.pathsTo(LastInst, Analysis.getZeroValue()); + } + + void TearDown() override {} + + void comparePaths( + const psr::FlowPathSequence &AnalyzedPaths, + const std::vector> &GroundTruth) { + + auto Matches = [&AnalyzedPaths](const std::vector >) { + for (const auto &Path : AnalyzedPaths) { + if (Path.size() != GT.size()) { + continue; + } + bool Match = true; + for (size_t I = 0; I < Path.size(); ++I) { + if (std::stoul(psr::getMetaDataID(Path[I])) != GT[I]) { + Match = false; + break; + } + } + if (Match) { + return true; + } + } + + return false; + }; + + for (const auto > : GroundTruth) { + EXPECT_TRUE(Matches(GT)) + << "No match found for " << psr::PrettyPrinter{GT}; + } + } +}; // Test Fixture + +TEST_F(PathTracingTest, Handle_Inter_01) { + auto PathsVec = doAnalysis("inter_01_cpp.ll"); + comparePaths(PathsVec, {{11, 12, 13, 14, 15, 1, 2, 3, 5, 16, 17, 18}}); +} + +TEST_F(PathTracingTest, Lambda_Inter_01) { + auto PathsVec = doLambdaAnalysis("inter_01_cpp.ll"); + comparePaths(PathsVec, {{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, + 16, 17, 18}}); +} + +TEST_F(PathTracingTest, Handle_Inter_02) { + auto PathsVec = doAnalysis("inter_02_cpp.ll"); + comparePaths(PathsVec, {{17, 18, 19, 20, 21, 7, 8, 9, 10, 11, + 22, 23, 24, 1, 2, 3, 5, 25, 26, 27}}); +} + +TEST_F(PathTracingTest, Lambda_Inter_02) { + auto PathsVec = doLambdaAnalysis("inter_02_cpp.ll"); + comparePaths(PathsVec, + {{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6, 7, 8, 9, + 10, 11, 22, 23, 24, 0, 1, 2, 3, 4, 5, 25, 26, 27}}); +} + +TEST_F(PathTracingTest, Handle_Inter_03) { + auto PathsVec = doAnalysis("inter_03_cpp.ll"); + comparePaths(PathsVec, {{12, 13, 14, 15, 16, 1, 2, 3, 5, 17, 18, 19, 1, 2, 3, + 5, 20, 21, 22}}); +} + +TEST_F(PathTracingTest, Lambda_Inter_03) { + auto PathsVec = doLambdaAnalysis("inter_03_cpp.ll"); + comparePaths(PathsVec, + {{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, + 4, 5, 17, 18, 19, 0, 1, 2, 3, 4, 5, 20, 21, 22}}); +} + +TEST_F(PathTracingTest, Handle_Inter_04) { + auto PathsVec = doAnalysis("inter_04_cpp.ll"); + comparePaths(PathsVec, {{28, 29, 30, 31, 32, 1, 2, 3, 5, 33, 34, 35, 8, 11, + 16, 17, 1, 2, 3, 5, 18, 19, 20, 21, 36, 37, 38}}); +} + +TEST_F(PathTracingTest, Lambda_Inter_04) { + auto PathsVec = doLambdaAnalysis("inter_04_cpp.ll"); + comparePaths(PathsVec, + { + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, + 3, 4, 5, 33, 34, 35, 6, 7, 8, 9, 10, 11, 16, 17, + 0, 1, 2, 3, 4, 5, 18, 19, 20, 21, 36, 37, 38}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, + 1, 2, 3, 4, 5, 33, 34, 35, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 20, 21, 36, 37, 38}, + }); +} + +TEST_F(PathTracingTest, Handle_Inter_05) { + auto PathsVec = doAnalysis("inter_05_cpp.ll"); + comparePaths(PathsVec, { + {53, 54, 55, 56}, + {42, 43, 52, 55, 56}, + {34, 41, 52, 55, 56}, + }); +} + +TEST_F(PathTracingTest, Lambda_Inter_05) { + /// We have 4 branches ==> 16 paths + auto PathsVec = doLambdaAnalysis("inter_05_cpp.ll"); + comparePaths( + PathsVec, + { + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 15, 16, 17, 18, 19, 21, 39, 40, 41, 44, 45, 46, 47, 0, 1, 2, 3, + 4, 5, 6, 7, 11, 12, 13, 14, 48, 49, 50, 51, 52, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 15, 16, 17, 18, 19, 21, 39, 40, 41, 42, 43, 44, 45, 46, 47, 0, 1, + 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 48, 49, 50, 51, 52, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 15, 16, 17, 18, 19, 21, 39, 40, 41, 44, 45, 46, 47, 0, 1, 2, 3, + 4, 5, 6, 7, 11, 12, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 15, 16, 17, 18, 19, 20, 21, 39, 40, 41, 44, 45, 46, 47, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 48, 49, 50, 51, 52, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 15, 16, 17, 18, 19, 21, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, 11, 12, + 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 15, 16, 17, 18, 19, 20, 21, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 13, 14, 48, 49, 50, 51, 52, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 15, 16, 17, 18, 19, 20, 21, 39, 40, 41, 44, + 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 15, 16, 17, 18, 19, 20, 21, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + }); +} + +TEST_F(PathTracingTest, Lambda_Inter_Depth3_05) { + /// We have 4 branches ==> 16 paths + auto PathsVec = doLambdaAnalysis("inter_05_cpp.ll", /*MaxDAGDepth*/ 3); + comparePaths(PathsVec, + { + {44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 13, 14, 48, 49, 50, 51, 52, 55, 56}, + {44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, + 11, 12, 13, 14, 48, 49, 50, 51, 52, 55, 56}, + {44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, 11, + 12, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + }); +} + +TEST_F(PathTracingTest, Handle_Inter_06) { + auto PathsVec = doAnalysis("inter_06_cpp.ll", true); + comparePaths(PathsVec, {{18, 19, 20, 21, 25, 27, 2, 4, 6, 7, 28, 29, 30}, + {18, 19, 22, 26, 27, 3, 5, 6, 7, 28, 29, 30}}); +} + +TEST_F(PathTracingTest, Lambda_Inter_06) { + auto PathsVec = doLambdaAnalysis("inter_06_cpp.ll"); + comparePaths(PathsVec, + {{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 0, 1, 2, 3, 4, 5, 6, 7, 28, 29, 30}}); +} + +TEST_F(PathTracingTest, Handle_Inter_07) { + auto PathsVec = doAnalysis("inter_07_cpp.ll"); + comparePaths(PathsVec, + { + {27, 28, 29, 30, 34, 44, 46, 10, 12, 14, 15, 47, 48, 49, 50}, + {27, 28, 31, 34, 45, 46, 11, 13, 14, 15, 47, 48, 49, 50}, + {27, 28, 29, 30, 34, 44, 46, 2, 4, 6, 7, 47, 48, 49, 50}, + {27, 28, 31, 34, 45, 46, 3, 5, 6, 7, 47, 48, 49, 50}, + {27, 28, 29, 30, 34, 37, 39, 10, 12, 14, 15, 40, 41, 49, 50}, + {27, 28, 31, 34, 38, 39, 11, 13, 14, 15, 40, 41, 49, 50}, + {27, 28, 29, 30, 34, 37, 39, 2, 4, 6, 7, 40, 41, 49, 50}, + {27, 28, 31, 34, 38, 39, 3, 5, 6, 7, 40, 41, 49, 50}, + }); +} + +TEST_F(PathTracingTest, Lambda_Inter_07) { + auto PathsVec = doLambdaAnalysis("inter_07_cpp.ll"); + comparePaths(PathsVec, { + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 0, 1, 2, 3, 4, 5, 6, 7, 40, 41, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 8, 9, 10, 11, 12, 13, 14, 15, 40, 41, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 42, 43, 44, 45, 46, + 0, 1, 2, 3, 4, 5, 6, 7, 47, 48, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 42, 43, 44, 45, 46, + 8, 9, 10, 11, 12, 13, 14, 15, 47, 48, 49, 50}, + }); +} + +TEST_F(PathTracingTest, Lambda_Inter_Depth3_07) { + auto PathsVec = doLambdaAnalysis("inter_07_cpp.ll", /*MaxDAGDepth*/ 3); + comparePaths(PathsVec, { + {0, 1, 2, 3, 4, 5, 6, 7, 40, 41, 49, 50}, + {0, 1, 2, 3, 4, 5, 6, 7, 47, 48, 49, 50}, + {8, 9, 10, 11, 12, 13, 14, 15, 40, 41, 49, 50}, + {8, 9, 10, 11, 12, 13, 14, 15, 47, 48, 49, 50}, + }); +} + +TEST_F(PathTracingTest, Handle_Inter_08) { + auto PathsVec = doAnalysis("inter_08_cpp.ll", true); + /// FIXME: Handle mutable z3::exprs; As of now, we reject all paths that go + /// into a loop, because this requires the loop condiiton to hold, whereas + /// leaving the loop requires the loop condition not to hold which is + /// contradictory + comparePaths( + PathsVec, + { + {24, 29, 32, 41, 42, 74, 75, 76, 77}, + // {54, 55, 56, 57, 61, 71, 73, 26, 29, 32, + // 33, 35, 36, 40, 32, 41, 42, 74, 75, 76}, + // {54, 55, 58, 61, 72, 73, 27, 29, 32, 34, 35, 36, 40, + // 32, 41, 42, 74, 75, 76, 77}, + {2, 7, 10, 20, 21, 74, 75, 76, 77}, + // {54, 55, 56, 57, 61, 71, 73, 4, 7, 10, 11, + // 13, 14, 15, 19, 10, 20, 21, 74, 75, 76, 77}, + // {54, 55, 58, 61, 72, 73, 5, 7, 10, 12, + // 13, 14, 15, 19, 10, 20, 21, 74, 75, 76, 77}, + {24, 29, 32, 41, 42, 67, 68, 76, 77}, + // {54, 55, 56, 57, 61, 64, 66, 26, 29, 32, + // 33, 35, 36, 40, 32, 41, 42, 67, 68, 76, 77}, + // {54, 55, 58, 61, 65, 66, 27, 29, 32, 34, 35, 36, 40, 32, 41, 42, + // 67, 68, 76, 77}, + {2, 7, 10, 20, 21, 67, 68, 76, 77}, + // {54, 55, 56, 57, 61, 64, 66, 4, 7, 10, 11, + // 13, 14, 15, 19, 10, 20, 21, 67, 68, 76, 77}, + // {54, 55, 58, 61, 65, 66, 5, 7, 10, 12, + // 13, 14, 15, 19, 10, 20, 21, 67, 68, 76, 77}, + }); +} + +TEST_F(PathTracingTest, Lambda_Inter_08) { + auto PathsVec = doLambdaAnalysis("inter_08_cpp.ll"); + /// FIXME: Handle mutable z3::exprs; As of now, we reject all paths that go + /// into a loop, because this requires the loop condiiton to hold, whereas + /// leaving the loop requires the loop condition not to hold which is + /// contradictory + comparePaths(PathsVec, + { + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 20, 21, 67, 68, 76, 77}, + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 41, 42, 67, 68, 76, 77}, + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 69, 70, 71, 72, 73, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 20, 21, 74, 75, 76, 77}, + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 69, 70, 71, 72, 73, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 41, 42, 74, 75, 76, 77}, + // {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + // 57, 58, 59, + // 60, 61, 62, 63, 64, 65, 66, 22, 23, 24, 25, 26, 27, 28, + // 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 30, 31, + // 32, 41, 42, 67, 68, 76, 77}, + // {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + // 57, 58, 59, + // 60, 61, 69, 70, 71, 72, 73, 22, 23, 24, 25, 26, 27, 28, + // 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 30, 31, + // 32, 41, 42, 74, 75, 76, 77}, + // {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + // 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 0, 1, + // 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + // 15, 16, 17, 18, 19, 8, 9, 10, 20, 21, 67, 68, 76, 77}, + // {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + // 56, 57, 58, 59, 60, 61, 69, 70, 71, 72, 73, 0, 1, + // 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + // 15, 16, 17, 18, 19, 8, 9, 10, 20, 21, 74, 75, 76, 77}, + + }); +} + +TEST_F(PathTracingTest, Handle_Inter_09) { + auto PathsVec = doAnalysis("inter_09_cpp.ll", true); + /// FIXME: Same reason as Handle_Inter_08 + comparePaths( + PathsVec, + { + // {22, 2, 5, 6, 7, 8, 2, 5, 11, 12, 13, 14, 15, 9, 10, 14, 15}, + {22, 2, 5, 11, 12, 13, 14, 15, 24}, + }); +} + +TEST_F(PathTracingTest, Lambda_Inter_09) { + auto PathsVec = doLambdaAnalysis("inter_09_cpp.ll"); + /// FIXME: Same reason as Lambda_Inter_08 + comparePaths(PathsVec, { + {16, 17, 18, 19, 20, 21, 22, 0, 1, 2, + 3, 4, 5, 11, 12, 13, 14, 15, 23, 24}, + // {16, 17, 18, 19, 20, 21, 22, 0, 1, 2, 3, + // 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, + // 11, 12, 13, 14, 15, 9, 10, 14, 15, 23, 24}, + }); +} + +TEST_F(PathTracingTest, Handle_Inter_10) { + GTEST_SKIP() << "Need globals support"; + auto PathsVec = doAnalysis("inter_10_cpp.ll", true); + /// TODO: GT +} + +TEST_F(PathTracingTest, Handle_Inter_11) { + auto PathsVec = doAnalysis("inter_11_cpp.ll"); + // Note: The alias analysis is strong enough to see that Three::assignValue + // can never be called + comparePaths(PathsVec, {{25, 44, 46, 47, 48, 26}}); +} + +TEST_F(PathTracingTest, Lambda_Inter_11) { + auto PathsVec = doLambdaAnalysis("inter_11_cpp.ll"); + // Note: The alias analysis is strong enough to see that Three::assignValue + // can never be called + comparePaths(PathsVec, + {{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 27, 28, 29, 30, + 31, 35, 36, 37, 38, 39, 40, 32, 33, 34, 18, 19, 20, 21, + 22, 23, 24, 25, 41, 42, 43, 44, 45, 46, 47, 48, 26}}); +} + +TEST_F(PathTracingTest, Handle_Inter_12) { + auto PathsVec = doAnalysis("inter_12_cpp.ll"); + comparePaths(PathsVec, + {{42, 112, 114, 115, 116, 43}, {42, 82, 84, 85, 86, 43}}); +} + +TEST_F(PathTracingTest, Lambda_Inter_12) { + auto PathsVec = doLambdaAnalysis("inter_12_cpp.ll"); + comparePaths( + PathsVec, + { + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, + 47, 48, 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, + 23, 24, 25, 32, 33, 34, 52, 53, 54, 55, 56, 60, 61, + 62, 63, 64, 65, 57, 58, 59, 35, 36, 37, 38, 39, 40, + 41, 42, 109, 110, 111, 112, 113, 114, 115, 116, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, + 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 72, 73, 74, 75, 66, 67, 68, 69, 70, 87, 88, + 89, 90, 71, 76, 77, 78, 31, 32, 33, 34, 52, 53, 54, 55, 56, + 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, 36, 37, 38, 39, 40, + 41, 42, 79, 80, 81, 82, 83, 84, 85, 86, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, + 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 72, 73, 74, 75, 66, 67, 68, 69, 70, 87, 88, + 89, 90, 71, 76, 77, 78, 31, 32, 33, 34, 52, 53, 54, 55, 56, + 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, 36, 37, 38, 39, 40, + 41, 42, 109, 110, 111, 112, 113, 114, 115, 116, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, + 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 102, 103, 104, 105, 96, 97, 98, 99, 100, 87, 88, + 89, 90, 101, 106, 107, 108, 31, 32, 33, 34, 52, 53, 54, 55, 56, + 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, 36, 37, 38, 39, 40, + 41, 42, 79, 80, 81, 82, 83, 84, 85, 86, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, + 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 102, 103, 104, 105, 96, 97, 98, 99, 100, 87, 88, + 89, 90, 101, 106, 107, 108, 31, 32, 33, 34, 52, 53, 54, 55, 56, + 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, 36, 37, 38, 39, 40, + 41, 42, 109, 110, 111, 112, 113, 114, 115, 116, 43}, + }); +} + +TEST_F(PathTracingTest, Handle_Intra_01) { + auto PathsVec = doAnalysis("intra_01_cpp.ll"); + comparePaths(PathsVec, {{6, 7, 8, 9, 10, 11}}); +} + +TEST_F(PathTracingTest, Handle_Intra_02) { + auto PathsVec = doAnalysis("intra_02_cpp.ll"); + comparePaths(PathsVec, {{10, 11, 14, 15}, {12, 13, 14, 15}}); +} + +TEST_F(PathTracingTest, Handle_Intra_03) { + auto PathsVec = doAnalysis("intra_03_cpp.ll"); + comparePaths(PathsVec, {{15, 16, 19, 20}}); +} + +TEST_F(PathTracingTest, Handle_Intra_04) { + auto PathsVec = doAnalysis("intra_04_cpp.ll"); + /// FIXME: Same reason as Handle_Inter_08 + comparePaths(PathsVec, + { + // {16, 18, 21, 22, 23, 24, 25, 29, 21, 30, 33, 34}, + {16, 18, 21, 30, 33, 34}, + }); +} + +TEST_F(PathTracingTest, Handle_Intra_05) { + auto PathsVec = doAnalysis("intra_05_cpp.ll", true); + comparePaths(PathsVec, {{14, 15, 19, 20}, {17, 18, 19, 20}}); +} + +TEST_F(PathTracingTest, Handle_Intra_06) { + auto PathsVec = doAnalysis("intra_06_cpp.ll"); + comparePaths(PathsVec, {{11, 12, 15, 16}, {13, 14, 15, 16}}); +} + +TEST_F(PathTracingTest, Handle_Intra_07) { + auto PathsVec = doAnalysis("intra_07_cpp.ll", true); + /// FIXME: Same reason as Handle_Inter_08 + comparePaths( + PathsVec, + { + // {16, 17, 19, 22, 31, 34, 19, 22, 23, 24, 25, 26, 30, 22, 31, + // 34, 35, 38, 39}, + // {16, 17, 18, 19, 20, 21, 22, 31, 32, 33, 34, + // 18, 19, 20, 21, 22, 31, 32, 33, 34, 35, 38, 39}, + // {16, 17, 19, 22, 23, 24, 25, 26, 30, 22, 31, 34, 35, 38, 39}, + // {16, 17, 19, 22, 31, 34, 19, 22, 31, 34, 35, 38, 39}, + {16, 17, 19, 22, 31, 34, 35, 38, 39}, + }); +} + +TEST_F(PathTracingTest, Handle_Intra_08) { + auto PathsVec = doAnalysis("intra_08_cpp.ll"); + /// Note: we have a fallthrough from case 4 to default; Therefore, we only + /// have 3 paths + comparePaths(PathsVec, {{9, 10, 17, 18}, {11, 12, 17, 18}, {15, 16, 17, 18}}); +} + +TEST_F(PathTracingTest, Handle_Intra_09) { + auto PathsVec = doAnalysis("intra_09_cpp.ll", true); + /// FIXME: Same reason as Handle_Inter_08 + comparePaths(PathsVec, { + // {5, 11, 14, 16, 17, 18, 22, 14, 23, 24}, + // {4, 11, 14, 15, 17, 18, 22, 14, 23, 24}, + {3, 11, 14, 23, 24}, + }); +} + +TEST_F(PathTracingTest, Handle_Other_01) { + auto PathsVec = doAnalysis("other_01_cpp.ll"); + comparePaths(PathsVec, {{1, 6, 7, 8, 9, 10, 12, 13}}); +} + +// main function for the test case +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} From a332b6d396668aa95c3460be500a71d5d0bbe28e Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 Aug 2022 16:14:00 +0200 Subject: [PATCH 11/65] Make a lot of the unittests work (still not completed) --- .../IfdsIde/Solver/ESGEdgeKind.h | 22 ++ .../DataFlowSolver/IfdsIde/Solver/IDESolver.h | 27 +- .../IfdsIde/Solver/PathAwareIDESolver.h | 5 +- .../PathSensitivity/ExplodedSuperGraph.h | 22 +- .../Z3BasedPathSensitvityManager.h | 30 +- include/phasar/Utils/LLVMShorthands.h | 4 + .../Z3BasedPathSensitivityManager.cpp | 43 ++- lib/Utils/LLVMShorthands.cpp | 5 + .../path_tracing/CMakeLists.txt | 32 ++ test/llvm_test_code/path_tracing/inter_01.cpp | 8 + test/llvm_test_code/path_tracing/inter_02.cpp | 11 + test/llvm_test_code/path_tracing/inter_03.cpp | 9 + test/llvm_test_code/path_tracing/inter_04.cpp | 20 ++ test/llvm_test_code/path_tracing/inter_05.cpp | 29 ++ test/llvm_test_code/path_tracing/inter_06.cpp | 9 + test/llvm_test_code/path_tracing/inter_07.cpp | 18 ++ test/llvm_test_code/path_tracing/inter_08.cpp | 31 ++ test/llvm_test_code/path_tracing/inter_09.cpp | 11 + test/llvm_test_code/path_tracing/inter_10.cpp | 15 + test/llvm_test_code/path_tracing/inter_11.cpp | 16 + test/llvm_test_code/path_tracing/inter_12.cpp | 20 ++ test/llvm_test_code/path_tracing/intra_01.cpp | 6 + test/llvm_test_code/path_tracing/intra_02.cpp | 9 + test/llvm_test_code/path_tracing/intra_03.cpp | 10 + test/llvm_test_code/path_tracing/intra_04.cpp | 13 + test/llvm_test_code/path_tracing/intra_05.cpp | 12 + test/llvm_test_code/path_tracing/intra_06.cpp | 9 + test/llvm_test_code/path_tracing/intra_07.cpp | 15 + test/llvm_test_code/path_tracing/intra_08.cpp | 17 + test/llvm_test_code/path_tracing/intra_09.cpp | 9 + test/llvm_test_code/path_tracing/other_01.cpp | 7 + .../PathSensitivity/PathTracingTest.cpp | 294 +++++++++++------- 32 files changed, 637 insertions(+), 151 deletions(-) create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h create mode 100644 test/llvm_test_code/path_tracing/CMakeLists.txt create mode 100644 test/llvm_test_code/path_tracing/inter_01.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_02.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_03.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_04.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_05.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_06.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_07.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_08.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_09.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_10.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_11.cpp create mode 100644 test/llvm_test_code/path_tracing/inter_12.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_01.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_02.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_03.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_04.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_05.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_06.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_07.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_08.cpp create mode 100644 test/llvm_test_code/path_tracing/intra_09.cpp create mode 100644 test/llvm_test_code/path_tracing/other_01.cpp diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h new file mode 100644 index 0000000000..98652a197f --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_IFDSIDE_SOLVER_ESGEDGEKIND_H +#define PHASAR_PHASARLLVM_IFDSIDE_SOLVER_ESGEDGEKIND_H + +namespace psr { +enum class ESGEdgeKind { Normal, Call, CallToRet, SkipUnknownFn, Ret, Summary }; + +constexpr bool isInterProc(ESGEdgeKind Kind) noexcept { + return Kind == ESGEdgeKind::Call || Kind == ESGEdgeKind::Ret; +} + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_IFDSIDE_SOLVER_ESGEDGEKIND_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h index f473dffcf3..1e4a29b4a7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h @@ -42,6 +42,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNode.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JumpFunctions.h" @@ -479,14 +480,19 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, " " << IDEProblem.NtoString(ret)); }); + bool HasNoCalleeInformation = true; + // for each possible callee for (f_t SCalledProcN : Callees) { // still line 14 // check if a special summary for the called procedure exists FlowFunctionPtrType SpecialSum = CachedFlowEdgeFunctions.getSummaryFlowFunction(n, SCalledProcN); + // if a special summary is available, treat this as a normal flow // and use the summary flow and edge functions + if (SpecialSum) { + HasNoCalleeInformation = false; PHASAR_LOG_LEVEL(DEBUG, "Found and process special summary"); for (n_t ReturnSiteN : ReturnSiteNs) { container_type Res = computeSummaryFlowFunction(SpecialSum, d1, d2); @@ -494,7 +500,7 @@ class IDESolver PAMM_SEVERITY_LEVEL::Full); ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, PAMM_SEVERITY_LEVEL::Full); - saveEdges(n, ReturnSiteN, d2, Res, false); + saveEdges(n, ReturnSiteN, d2, Res, ESGEdgeKind::Summary); for (d_t d3 : Res) { EdgeFunctionPtrType SumEdgFnE = CachedFlowEdgeFunctions.getSummaryEdgeFunction(n, d2, @@ -526,7 +532,8 @@ class IDESolver } // if startPointsOf is empty, the called function is a declaration for (n_t SP : StartPointsOf) { - saveEdges(n, SP, d2, Res, true); + HasNoCalleeInformation = false; + saveEdges(n, SP, d2, Res, ESGEdgeKind::Call); // for each result node of the call-flow function for (d_t d3 : Res) { using TableCell = @@ -568,7 +575,7 @@ class IDESolver RetFunction, d3, d4, n, Container{d2}); ADD_TO_HISTOGRAM("Data-flow facts", returnedFacts.size(), 1, PAMM_SEVERITY_LEVEL::Full); - saveEdges(eP, RetSiteN, d4, ReturnedFacts, true); + saveEdges(eP, RetSiteN, d4, ReturnedFacts, ESGEdgeKind::Ret); // for each target value of the function for (d_t d5 : ReturnedFacts) { // update the caller-side summary function @@ -627,7 +634,9 @@ class IDESolver computeCallToReturnFlowFunction(CallToReturnFF, d1, d2); ADD_TO_HISTOGRAM("Data-flow facts", returnFacts.size(), 1, PAMM_SEVERITY_LEVEL::Full); - saveEdges(n, ReturnSiteN, d2, ReturnFacts, false); + saveEdges(n, ReturnSiteN, d2, ReturnFacts, + HasNoCalleeInformation ? ESGEdgeKind::SkipUnknownFn + : ESGEdgeKind::CallToRet); for (d_t d3 : ReturnFacts) { EdgeFunctionPtrType EdgeFnE = CachedFlowEdgeFunctions.getCallToRetEdgeFunction(n, d2, ReturnSiteN, @@ -668,7 +677,7 @@ class IDESolver const container_type Res = computeNormalFlowFunction(FlowFunc, d1, d2); ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, PAMM_SEVERITY_LEVEL::Full); - saveEdges(n, nPrime, d2, Res, false); + saveEdges(n, nPrime, d2, Res, ESGEdgeKind::Normal); for (d_t d3 : Res) { EdgeFunctionPtrType g = CachedFlowEdgeFunctions.getNormalEdgeFunction(n, d2, nPrime, d3); @@ -883,12 +892,12 @@ class IDESolver } virtual void saveEdges(n_t SourceNode, n_t SinkStmt, d_t SourceVal, - const container_type &DestVals, bool InterP) { + const container_type &DestVals, ESGEdgeKind Kind) { if (!SolverConfig.recordEdges()) { return; } Table> &TgtMap = - (InterP) ? ComputedInterPathEdges : ComputedIntraPathEdges; + (isInterProc(Kind)) ? ComputedInterPathEdges : ComputedIntraPathEdges; TgtMap.get(SourceNode, SinkStmt)[SourceVal].insert(DestVals.begin(), DestVals.end()); } @@ -1024,7 +1033,7 @@ class IDESolver computeReturnFlowFunction(RetFunction, d1, d2, c, Entry.second); ADD_TO_HISTOGRAM("Data-flow facts", targets.size(), 1, PAMM_SEVERITY_LEVEL::Full); - saveEdges(n, RetSiteC, d2, Targets, true); + saveEdges(n, RetSiteC, d2, Targets, ESGEdgeKind::Ret); // for each target value at the return site // line 23 for (d_t d5 : Targets) { @@ -1097,7 +1106,7 @@ class IDESolver RetFunction, d1, d2, Caller, Container{ZeroValue}); ADD_TO_HISTOGRAM("Data-flow facts", targets.size(), 1, PAMM_SEVERITY_LEVEL::Full); - saveEdges(n, RetSiteC, d2, Targets, true); + saveEdges(n, RetSiteC, d2, Targets, ESGEdgeKind::Ret); for (d_t d5 : Targets) { EdgeFunctionPtrType f5 = CachedFlowEdgeFunctions.getReturnEdgeFunction( diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h index 539dd11ab4..44bffb5085 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h @@ -1,6 +1,7 @@ #pragma once #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" #include "phasar/Utils/Logger.h" @@ -36,8 +37,8 @@ class PathAwareIDESolver : public IDESolver { private: void saveEdges(n_t Curr, n_t Succ, d_t CurrNode, - const container_type &SuccNodes, bool IsInterProc) override { - ESG.saveEdges(Curr, CurrNode, Succ, SuccNodes, IsInterProc); + const container_type &SuccNodes, ESGEdgeKind Kind) override { + ESG.saveEdges(Curr, CurrNode, Succ, SuccNodes, Kind); } ExplodedSuperGraph ESG; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h index 40b63a90c0..e86af00864 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h @@ -10,8 +10,10 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h" #include "phasar/PhasarLLVM/Utils/Printer.h" #include "phasar/Utils/LLVMIRToSrc.h" +#include "phasar/Utils/Logger.h" #include "phasar/Utils/StableVector.h" #include "phasar/Utils/Utilities.h" @@ -75,9 +77,16 @@ template class ExplodedSuperGraph { template void saveEdges(n_t Curr, d_t CurrNode, n_t Succ, const Container &SuccNodes, - bool /*IsInterProc*/) { + ESGEdgeKind Kind) { auto Pred = getNodeOrNull(Curr, std::move(CurrNode)); + + /// The Identity CTR-flow on the zero-value has no meaning at all regarding + /// path sensitivity, so skip it + bool MaySkipEdge = Kind == ESGEdgeKind::CallToRet && CurrNode == ZeroValue; for (const d_t &SuccNode : SuccNodes) { + if (MaySkipEdge && SuccNode == CurrNode) { + continue; + } saveEdge(Pred, Curr, CurrNode, Succ, SuccNode); } } @@ -215,11 +224,12 @@ template class ExplodedSuperGraph { abort(); } if (Nod == SuccVtx) { - llvm::errs() << "> saveEdge -- skip meaningless loop: (" - << NPrinter.NtoString(Curr) << ", " - << DPrinter.DtoString(CurrNode) << ") --> (" - << NPrinter.NtoString(Succ) << ", " - << DPrinter.DtoString(SuccNode) << ")\n"; + PHASAR_LOG_LEVEL_CAT(INFO, "PathSensitivityManager", + "> saveEdge -- skip meaningless loop: (" + << NPrinter.NtoString(Curr) << ", " + << DPrinter.DtoString(CurrNode) << ") --> (" + << NPrinter.NtoString(Succ) << ", " + << DPrinter.DtoString(SuccNode) << ")"); return; } Nod = Nod->Predecessor; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h index a53ff1c213..ed154f2619 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -127,21 +127,21 @@ class Z3BasedPathSensitivityManager #ifndef NDEBUG #ifdef DYNAMIC_LOG - PHASAR_LOG_LEVEL_CAT( - DEBUG, "PathSensitivityManager", - "Recorded " << Ret.size() << " valid paths:"; - std::string Str; for (const FlowPath &Path - : Ret) { - Str.clear(); - llvm::raw_string_ostream ROS(Str); - ROS << "> "; - llvm::interleaveComma(Path.Path, ROS, [&ROS](auto *Inst) { - ROS << getMetaDataID(Inst); - }); - ROS << ": " << Path.Constraint.to_string(); - ROS.flush(); - S << Str; - }) + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + "Recorded " << Ret.size() << " valid paths:"); + + std::string Str; + for (const FlowPath &Path : Ret) { + Str.clear(); + llvm::raw_string_ostream ROS(Str); + ROS << "> "; + llvm::interleaveComma(Path.Path, ROS, + [&ROS](auto *Inst) { ROS << getMetaDataID(Inst); }); + ROS << ": " << Path.Constraint.to_string(); + ROS.flush(); + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", Str); + } + #endif // DYNAMIC_LOG #endif // NDEBUG diff --git a/include/phasar/Utils/LLVMShorthands.h b/include/phasar/Utils/LLVMShorthands.h index 0ca9f59baa..861d5b1823 100644 --- a/include/phasar/Utils/LLVMShorthands.h +++ b/include/phasar/Utils/LLVMShorthands.h @@ -24,6 +24,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/ModuleSlotTracker.h" #include "llvm/IR/Value.h" +#include "llvm/Support/Compiler.h" #include "phasar/DB/ProjectIRDB.h" #include "phasar/Utils/Utilities.h" @@ -79,6 +80,9 @@ std::string llvmIRToStableString(const llvm::Value *V); */ std::string llvmIRToShortString(const llvm::Value *V); +LLVM_DUMP_METHOD void dumpIR(const llvm::Value *V); +LLVM_DUMP_METHOD void dumpIR(const llvm::Instruction *V); + /** * @brief Returns all LLVM Global Values that are used in the given LLVM * Function. diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp index c1e2a91a41..b437fa746e 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -1,6 +1,10 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h" +#include "phasar/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/Support/Casting.h" namespace psr { z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( @@ -50,9 +54,8 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( llvm::SmallVector Ys; - const auto &OutEdges = graph_traits_t::outEdges(RevDAG, Vtx); - - for (auto Iter = OutEdges.begin(), End = OutEdges.end(); Iter != End;) { + for (auto Iter = graph_traits_t::outEdges(RevDAG, Vtx).begin(); + Iter != graph_traits_t::outEdges(RevDAG, Vtx).end();) { // NOLINTNEXTLINE(readability-qualified-auto, llvm-qualified-auto) auto It = Iter++; auto Edge = *It; @@ -99,8 +102,8 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( z3::expr Ret = LPC.getContext().bool_val(false); - const auto &Roots = graph_traits_t::roots(RevDAG); - for (auto Iter = Roots.begin(), End = Roots.end(); Iter != End;) { + for (auto Iter = graph_traits_t::roots(RevDAG).begin(); + Iter != graph_traits_t::roots(RevDAG).end();) { // NOLINTNEXTLINE(readability-qualified-auto, llvm-qualified-auto) auto It = Iter++; auto Rt = *It; @@ -201,6 +204,8 @@ class CallStackPathFilter { } if (const auto *CS = llvm::dyn_cast(Prev); CS && !isDirectSuccessorOf(Inst, CS)) { + PHASAR_LOG_LEVEL_CAT(DEBUG, "CallStackPathFilter", + "Push CS: " << llvmIRToString(CS)); pushCS(CS); } else if (llvm::isa(Prev) || @@ -208,10 +213,26 @@ class CallStackPathFilter { /// Allow unbalanced returns if (!emptyCS()) { const auto *CS = popCS(); + + PHASAR_LOG_LEVEL_CAT(DEBUG, "CallStackPathFilter", + "Pop CS: " << llvmIRToString(CS) << " at exit " + << llvmIRToString(Prev) + << " and ret-site " + << llvmIRToString(Inst)); + if (!isDirectSuccessorOf(Inst, CS)) { /// Invalid return Valid = false; + + PHASAR_LOG_LEVEL_CAT(DEBUG, "CallStackPathFilter", + "> Invalid return"); + } else { + PHASAR_LOG_LEVEL_CAT(DEBUG, "CallStackPathFilter", "> Valid return"); } + } else { + PHASAR_LOG_LEVEL_CAT(DEBUG, "CallStackPathFilter", + "> Unbalanced return at exit " + << llvmIRToString(Prev)); } /// else: unbalanced return } @@ -237,11 +258,23 @@ class CallStackPathFilter { private: bool isDirectSuccessorOf(const llvm::Instruction *Succ, const llvm::Instruction *Of) { + while (const auto *Nxt = Of->getNextNode()) { if (Nxt == Succ) { return true; } Of = Nxt; + + if (Nxt->isTerminator()) { + break; + } + if (const auto *Call = llvm::dyn_cast(Nxt); + Call && Call->getCalledFunction() && + !Call->getCalledFunction()->isDeclaration()) { + /// Don't skip function calls. We might call the same fun twice in the + /// same BB, so we recognize invalid paths there as well! + return false; + } } assert(Of->isTerminator()); diff --git a/lib/Utils/LLVMShorthands.cpp b/lib/Utils/LLVMShorthands.cpp index adb4b67b0b..a5d0b6a5e3 100644 --- a/lib/Utils/LLVMShorthands.cpp +++ b/lib/Utils/LLVMShorthands.cpp @@ -225,6 +225,11 @@ std::string llvmIRToShortString(const llvm::Value *V) { return IRBuffer; } +void dumpIR(const llvm::Value *V) { llvm::errs() << llvmIRToString(V) << '\n'; } +void dumpIR(const llvm::Instruction *V) { + llvm::errs() << llvmIRToString(V) << '\n'; +} + std::vector globalValuesUsedinFunction(const llvm::Function *F) { std::vector GlobalsUsed; diff --git a/test/llvm_test_code/path_tracing/CMakeLists.txt b/test/llvm_test_code/path_tracing/CMakeLists.txt new file mode 100644 index 0000000000..3a701b4770 --- /dev/null +++ b/test/llvm_test_code/path_tracing/CMakeLists.txt @@ -0,0 +1,32 @@ +set(PATH_TRACING_FILES + inter_01.cpp + inter_02.cpp + inter_03.cpp + inter_04.cpp + inter_05.cpp + inter_06.cpp + inter_07.cpp + inter_08.cpp + inter_09.cpp + inter_10.cpp + inter_11.cpp + inter_12.cpp + intra_01.cpp + intra_02.cpp + intra_03.cpp + intra_04.cpp + intra_05.cpp + intra_06.cpp + intra_07.cpp + intra_08.cpp + intra_09.cpp + other_01.cpp +) + +foreach(TEST_SRC ${PATH_TRACING_FILES}) + generate_ll_file(FILE ${TEST_SRC}) +endforeach(TEST_SRC) + +foreach(TEST_SRC ${PATH_TRACING_FILES}) + generate_ll_file(FILE ${TEST_SRC} DEBUG) +endforeach(TEST_SRC) diff --git a/test/llvm_test_code/path_tracing/inter_01.cpp b/test/llvm_test_code/path_tracing/inter_01.cpp new file mode 100644 index 0000000000..71b0801f97 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_01.cpp @@ -0,0 +1,8 @@ +int increment(int I) { return ++I; } + +int main() { + int I = 42; + int J = I; + int K = increment(J); + return K; +} diff --git a/test/llvm_test_code/path_tracing/inter_02.cpp b/test/llvm_test_code/path_tracing/inter_02.cpp new file mode 100644 index 0000000000..2b5eedbbe5 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_02.cpp @@ -0,0 +1,11 @@ +int increment(int I) { return ++I; } + +int compute(int I) { return (I + 42) * 2; } + +int main() { + int I = 42; + int J = I; + int K = compute(J); + K = increment(K); + return K; +} diff --git a/test/llvm_test_code/path_tracing/inter_03.cpp b/test/llvm_test_code/path_tracing/inter_03.cpp new file mode 100644 index 0000000000..1208186b3f --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_03.cpp @@ -0,0 +1,9 @@ +int increment(int I) { return ++I; } + +int main() { + int I = 42; + int J = I; + int K = increment(J); + int L = increment(K); + return L; +} diff --git a/test/llvm_test_code/path_tracing/inter_04.cpp b/test/llvm_test_code/path_tracing/inter_04.cpp new file mode 100644 index 0000000000..8402d65d05 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_04.cpp @@ -0,0 +1,20 @@ +extern int someFunc(int L); + +int increment(int I) { return ++I; } + +int modify(int I) { + if (I < 90) { + return someFunc(I); + } else { + return increment(I); + } + return --I; +} + +int main() { + int I = 42; + int J = I; + int K = increment(J); + int L = modify(K); + return L; +} diff --git a/test/llvm_test_code/path_tracing/inter_05.cpp b/test/llvm_test_code/path_tracing/inter_05.cpp new file mode 100644 index 0000000000..d2ec590662 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_05.cpp @@ -0,0 +1,29 @@ +#include +#include + +int *bar(int *Foo, int I) { + if (I > 10) { + return Foo; + } + return 0; +} + +void lorem(int I) { + if (I > 10) { + } +} + +int main(int Argc, char **Argv) { + int K = 0, J = 10; + int Z = Argc; + lorem(Z); + if (K == 0) { + J = 20; + } + int *Foo = &Z; + int M = *bar(Foo, Z); + if (M < 0) { + J = 42; + } + return J; +} diff --git a/test/llvm_test_code/path_tracing/inter_06.cpp b/test/llvm_test_code/path_tracing/inter_06.cpp new file mode 100644 index 0000000000..99e8c4ecd6 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_06.cpp @@ -0,0 +1,9 @@ +int add(int A, int B) { return A + B; } + +int main(int Argc, char **Argv) { + int A = 42; + int B = A++; + int (*F)(int, int) = &add; + int C = F(A, B); + return C; +} diff --git a/test/llvm_test_code/path_tracing/inter_07.cpp b/test/llvm_test_code/path_tracing/inter_07.cpp new file mode 100644 index 0000000000..c7245ea57d --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_07.cpp @@ -0,0 +1,18 @@ +int add(int A, int B) { return A + B; } + +int sub(int A, int B) { return A - B; } + +int main(int Argc, char **Argv) { + int A = 42; + int B = A++; + int C; + if (Argc > 0) { + int (*F)(int, int) = &add; + C = F(A, B); + } else { + int (*F)(int, int) = ⊂ + C = F(A, B); + } + + return C; +} diff --git a/test/llvm_test_code/path_tracing/inter_08.cpp b/test/llvm_test_code/path_tracing/inter_08.cpp new file mode 100644 index 0000000000..cf3797a41d --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_08.cpp @@ -0,0 +1,31 @@ +int add(int A, int B) { + int C; + for (int I = 0; I < 12; I++) { + C = A + B; + } + return C; +} + +int sub(int A, int B) { + int C; + int I = 5; + while (I < 12) { + C = A + B; + I++; + } + return C; +} + +int main(int Argc, char **Argv) { + int A = 42; + int B = A++; + int C; + if (Argc > 0) { + int (*F)(int, int) = &add; + C = F(A, B); + } else { + int (*F)(int, int) = ⊂ + C = F(A, B); + } + return C; +} diff --git a/test/llvm_test_code/path_tracing/inter_09.cpp b/test/llvm_test_code/path_tracing/inter_09.cpp new file mode 100644 index 0000000000..710a21ae48 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_09.cpp @@ -0,0 +1,11 @@ +unsigned recursion(unsigned i) { + if (i > 0) { + return recursion(i - 1); + } + return i; +} + +int main(int Argc, char **Argv) { + Argc = recursion(5); + return 0; +} diff --git a/test/llvm_test_code/path_tracing/inter_10.cpp b/test/llvm_test_code/path_tracing/inter_10.cpp new file mode 100644 index 0000000000..8b8e4a33a9 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_10.cpp @@ -0,0 +1,15 @@ +#include + +int createInitialValue() { return 42; } + +int foo = createInitialValue(); + +int bar; + +__attribute__((constructor)) void myGlobalCtor() { bar = 45; } + +int main(int Argc, char **Argv) { + Argc = foo + 1; + int y = bar - 1; + return 0; +} diff --git a/test/llvm_test_code/path_tracing/inter_11.cpp b/test/llvm_test_code/path_tracing/inter_11.cpp new file mode 100644 index 0000000000..9628566c64 --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_11.cpp @@ -0,0 +1,16 @@ +struct One { + virtual int assignValue(int J) = 0; +}; + +struct Two : public One { + int assignValue(int J) override { return J + 1; } +}; + +struct Three : public One { + int assignValue(int J) override { return J + 2; } +}; + +int main(int Argc, char **Argv) { + One *O = new Two; + return O->assignValue(42); +} diff --git a/test/llvm_test_code/path_tracing/inter_12.cpp b/test/llvm_test_code/path_tracing/inter_12.cpp new file mode 100644 index 0000000000..b9fe519b0e --- /dev/null +++ b/test/llvm_test_code/path_tracing/inter_12.cpp @@ -0,0 +1,20 @@ +struct One { + virtual ~One() = default; + virtual int assignValue(int J) = 0; +}; + +struct Two : public One { + int assignValue(int J) override { return J + 1; } +}; + +struct Three : public One { + int assignValue(int J) override { return J + 2; } +}; + +int main(int Argc, char **Argv) { + One *O = new Two; + delete O; + O = new Three; + + return O->assignValue(42); +} diff --git a/test/llvm_test_code/path_tracing/intra_01.cpp b/test/llvm_test_code/path_tracing/intra_01.cpp new file mode 100644 index 0000000000..b275d50e4f --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_01.cpp @@ -0,0 +1,6 @@ +int main() { + int I = 13; + int J = 42; + int K = J + 9001; + return K; +} diff --git a/test/llvm_test_code/path_tracing/intra_02.cpp b/test/llvm_test_code/path_tracing/intra_02.cpp new file mode 100644 index 0000000000..b4411b86d3 --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_02.cpp @@ -0,0 +1,9 @@ +int main(int Argc, char **Argv) { + int I; + if (Argc > 24) { + I = 42; + } else { + I = 13; + } + return I; +} diff --git a/test/llvm_test_code/path_tracing/intra_03.cpp b/test/llvm_test_code/path_tracing/intra_03.cpp new file mode 100644 index 0000000000..c89956da1b --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_03.cpp @@ -0,0 +1,10 @@ +int main(int Argc, char **Argv) { + int I = Argc; + int J = I; + if (Argc > 1) { + J = 100; + } else { + I = 13; + } + return J; +} diff --git a/test/llvm_test_code/path_tracing/intra_04.cpp b/test/llvm_test_code/path_tracing/intra_04.cpp new file mode 100644 index 0000000000..f4cdbc7dff --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_04.cpp @@ -0,0 +1,13 @@ +int main(int Argc, char **Argv) { + int I = Argc; + int J = I; + if (Argc > 1) { + J = 100; + for (int Idx = 0; Idx < 1000; ++Idx) { + ++J; + } + } else { + I = 13; + } + return J; +} diff --git a/test/llvm_test_code/path_tracing/intra_05.cpp b/test/llvm_test_code/path_tracing/intra_05.cpp new file mode 100644 index 0000000000..a3eab5f04c --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_05.cpp @@ -0,0 +1,12 @@ +int main(int Argc, char **Argv) { + int I = 2000; + int J = 4000; + if (Argc > 1) { + I = 1; + J = 4; + } else { + I = 2; + J = 4; + } + return J; +} diff --git a/test/llvm_test_code/path_tracing/intra_06.cpp b/test/llvm_test_code/path_tracing/intra_06.cpp new file mode 100644 index 0000000000..0547c6bf28 --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_06.cpp @@ -0,0 +1,9 @@ +int main(int Argc, [[maybe_unused]] char **Argv) { + int I = 2000; + if (Argc > 1) { // NOLINT + I = 9001; + } else { + I = 9001; + } + return I; +} diff --git a/test/llvm_test_code/path_tracing/intra_07.cpp b/test/llvm_test_code/path_tracing/intra_07.cpp new file mode 100644 index 0000000000..fc69a9f550 --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_07.cpp @@ -0,0 +1,15 @@ +int main(int Argc, char **Argv) { + int I = Argc; + int J = I; + if (Argc > 1) { + J = 100; + do { + for (int Idx = 0; Idx < 1000; ++Idx) { + ++J; + } + } while (J > 150); + } else { + I = 13; + } + return J; +} diff --git a/test/llvm_test_code/path_tracing/intra_08.cpp b/test/llvm_test_code/path_tracing/intra_08.cpp new file mode 100644 index 0000000000..26e77a673b --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_08.cpp @@ -0,0 +1,17 @@ +int main(int Argc, char **Argv) { + int i; + switch (Argc) { + case 1: + i = 10; + break; + case 2: + case 3: + i = 20; + break; + case 4: + i = 30; + default: + i = -1; + } + return i; +} diff --git a/test/llvm_test_code/path_tracing/intra_09.cpp b/test/llvm_test_code/path_tracing/intra_09.cpp new file mode 100644 index 0000000000..784712af18 --- /dev/null +++ b/test/llvm_test_code/path_tracing/intra_09.cpp @@ -0,0 +1,9 @@ +int main(int Argc, char **Argv) { + int C, A, B; + int I = 5; + while (I < 12) { + C = A + B; + I++; + } + return C; +} diff --git a/test/llvm_test_code/path_tracing/other_01.cpp b/test/llvm_test_code/path_tracing/other_01.cpp new file mode 100644 index 0000000000..98f19aabe2 --- /dev/null +++ b/test/llvm_test_code/path_tracing/other_01.cpp @@ -0,0 +1,7 @@ +int main() { + int I; + int J = I; + int K = J + 13; + int L = 9001; + return K; +} diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp index 79e12991c5..6e84219ed5 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp @@ -9,6 +9,7 @@ #include "TestConfig.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -32,6 +33,7 @@ #include "phasar/Utils/DebugOutput.h" #include "phasar/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/Utilities.h" // ============== TEST FIXTURE ============== // class PathTracingTest : public ::testing::Test { @@ -43,6 +45,7 @@ class PathTracingTest : public ::testing::Test { psr::LLVMPathConstraints LPC; void SetUp() override { psr::ValueAnnotationPass::resetValueID(); } + void TearDown() override { psr::Logger::disable(); } std::pair getInterestingInstFact() { @@ -100,58 +103,6 @@ class PathTracingTest : public ::testing::Test { return PSM.pathsTo(LastInst, InterestingFact); } - // psr::FlowPathSequence - // doTaintAnalysis(const std::string &LlvmFilePath, bool PrintDump = false) - // { - // auto IrFiles = {PathToLlFiles + LlvmFilePath}; - // IRDB = std::make_unique(IrFiles, - // psr::IRDBOptions::WPA); psr::LLVMTypeHierarchy TH(*IRDB); - // psr::LLVMPointsToSet PT(*IRDB); - // psr::LLVMBasedICFG ICFG(*IRDB, psr::CallGraphAnalysisType::OTF, - // {"main"}, - // &TH, &PT, psr::Soundness::Soundy, - // /*IncludeGlobals*/ false); - // psr::TaintConfig Config(*IRDB); - // psr::IDEExtendedTaintAnalysis<3, false> TaintProblem(IRDB.get(), &TH, - // &ICFG, - // &PT, Config, - // {"main"}); - // psr::PathAwareIDESolver Solver(TaintProblem); - // Solver.solve(); - // if (PrintDump) { - // // IRDB->print(); - // // ICFG.print(); - // // LCASolver.dumpResults(); - // std::error_code EC; - // llvm::raw_fd_ostream ROS(LlvmFilePath + "_explicit_esg.dot", EC); - // assert(!EC); - // Solver.getExplicitESG().printAsDot(ROS); - // } - // // auto &Leaks = TaintProblem.getAllLeaks(); - // // llvm::errs() << "Num Leaks: " << Leaks.size() << '\n'; - // // auto [LastInst, LeakVals] = *Leaks.begin(); - // // llvm::errs() << "Num first leaks: " << LeakVals.size() << '\n'; - // // auto [LeakVal, InterestingFact] = *LeakVals.begin(); - // // // auto [LastInst, InterestingFact] = getInterestingInstFact(); - // // // llvm::outs() << "Target instruction: " << - // // psr::llvmIRToString(LastInst); - // // // llvm::outs() << "\nTarget data-flow fact: " - // // // << psr::llvmIRToString(InterestingFact) << '\n'; - // // return Solver.pathsTo(LastInst, InterestingFact); - - // psr::Z3BasedPathSensitivityManager - // PSM( - // &Solver.getExplicitESG(), {}, &LPC); - - // for (auto [Inst, Leaks] : TaintProblem.getAllLeaks()) { - // for (auto [LeakVal, LeakFact] : Leaks) { - // [[maybe_unused]] auto _ = PSM.pathsTo(Inst, LeakFact, LPC); - // } - // } - - // return {}; - // } - psr::FlowPathSequence doLambdaAnalysis(const std::string &LlvmFilePath, size_t MaxDAGDepth = SIZE_MAX) { @@ -163,24 +114,23 @@ class PathTracingTest : public ::testing::Test { &TH, &PT, psr::Soundness::Soundy, /*IncludeGlobals*/ false); - // psr::IFDSSolverTest Analysis(IRDB.get(), &TH, &ICFG, &PT, {"main"}, - // true); - // psr::IFDSSolver Solver(Analysis); psr::TaintConfig Config(*IRDB, nlohmann::json{}); psr::IDEExtendedTaintAnalysis<3, false> Analysis(IRDB.get(), &TH, &ICFG, &PT, Config, {"main"}); psr::PathAwareIDESolver Solver(Analysis); Solver.solve(); - // std::ofstream Ofs(LlvmFilePath + "_lambda_esg.dot"); - // Solver.printAsDot(Ofs); - auto *Main = IRDB->getFunctionDefinition("main"); assert(Main); auto *LastInst = &Main->back().back(); llvm::outs() << "Target instruction: " << psr::llvmIRToString(LastInst) << '\n'; + std::error_code EC; + llvm::raw_fd_ostream ROS(LlvmFilePath + "_explicit_esg.dot", EC); + assert(!EC); + Solver.getExplicitESG().printAsDot(ROS); + psr::Z3BasedPathSensitivityManager PSM( &Solver.getExplicitESG(), psr::Z3BasedPathSensitivityConfig().withDAGDepthThreshold(MaxDAGDepth), @@ -189,14 +139,15 @@ class PathTracingTest : public ::testing::Test { return PSM.pathsTo(LastInst, Analysis.getZeroValue()); } - void TearDown() override {} - void comparePaths( const psr::FlowPathSequence &AnalyzedPaths, const std::vector> &GroundTruth) { - - auto Matches = [&AnalyzedPaths](const std::vector >) { + std::set MatchingIndices; + auto Matches = [&AnalyzedPaths, + &MatchingIndices](const std::vector >) { + size_t Idx = 0; for (const auto &Path : AnalyzedPaths) { + psr::scope_exit IncIdx = [&Idx] { ++Idx; }; if (Path.size() != GT.size()) { continue; } @@ -208,6 +159,7 @@ class PathTracingTest : public ::testing::Test { } } if (Match) { + MatchingIndices.insert(Idx); return true; } } @@ -219,12 +171,31 @@ class PathTracingTest : public ::testing::Test { EXPECT_TRUE(Matches(GT)) << "No match found for " << psr::PrettyPrinter{GT}; } + + EXPECT_EQ(MatchingIndices.size(), AnalyzedPaths.size()); + + if (MatchingIndices.size() != AnalyzedPaths.size()) { + for (size_t I = 0; I < AnalyzedPaths.size(); ++I) { + if (MatchingIndices.count(I)) { + continue; + } + + llvm::errs() << "> PATH NOT IN GT: " + << psr::PrettyPrinter{llvm::map_range( + AnalyzedPaths[I], + [](const auto *Inst) { + return psr::getMetaDataID(Inst); + })} + << '\n'; + } + } } }; // Test Fixture TEST_F(PathTracingTest, Handle_Inter_01) { auto PathsVec = doAnalysis("inter_01_cpp.ll"); - comparePaths(PathsVec, {{11, 12, 13, 14, 15, 1, 2, 3, 5, 16, 17, 18}}); + comparePaths(PathsVec, {{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 5, + 16, 17, 18}}); } TEST_F(PathTracingTest, Lambda_Inter_01) { @@ -235,8 +206,9 @@ TEST_F(PathTracingTest, Lambda_Inter_01) { TEST_F(PathTracingTest, Handle_Inter_02) { auto PathsVec = doAnalysis("inter_02_cpp.ll"); - comparePaths(PathsVec, {{17, 18, 19, 20, 21, 7, 8, 9, 10, 11, - 22, 23, 24, 1, 2, 3, 5, 25, 26, 27}}); + comparePaths(PathsVec, + {{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6, 7, 8, 9, + 10, 11, 22, 23, 24, 0, 1, 2, 3, 5, 25, 26, 27}}); } TEST_F(PathTracingTest, Lambda_Inter_02) { @@ -247,9 +219,13 @@ TEST_F(PathTracingTest, Lambda_Inter_02) { } TEST_F(PathTracingTest, Handle_Inter_03) { - auto PathsVec = doAnalysis("inter_03_cpp.ll"); - comparePaths(PathsVec, {{12, 13, 14, 15, 16, 1, 2, 3, 5, 17, 18, 19, 1, 2, 3, - 5, 20, 21, 22}}); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "CallStackPathFilter"); + auto PathsVec = doAnalysis("inter_03_cpp.ll", true); + comparePaths(PathsVec, {{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, + 3, 5, 17, 18, 19, 0, 1, 2, 3, 5, 20, 21, 22}}); } TEST_F(PathTracingTest, Lambda_Inter_03) { @@ -261,11 +237,14 @@ TEST_F(PathTracingTest, Lambda_Inter_03) { TEST_F(PathTracingTest, Handle_Inter_04) { auto PathsVec = doAnalysis("inter_04_cpp.ll"); - comparePaths(PathsVec, {{28, 29, 30, 31, 32, 1, 2, 3, 5, 33, 34, 35, 8, 11, - 16, 17, 1, 2, 3, 5, 18, 19, 20, 21, 36, 37, 38}}); + comparePaths(PathsVec, {{22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, + 1, 2, 3, 5, 33, 34, 35, 6, 8, 11, 16, 17, + 0, 1, 2, 3, 5, 18, 19, 20, 21, 36, 37, 38}}); } TEST_F(PathTracingTest, Lambda_Inter_04) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_04_cpp.ll"); comparePaths(PathsVec, { @@ -279,12 +258,29 @@ TEST_F(PathTracingTest, Lambda_Inter_04) { } TEST_F(PathTracingTest, Handle_Inter_05) { - auto PathsVec = doAnalysis("inter_05_cpp.ll"); - comparePaths(PathsVec, { - {53, 54, 55, 56}, - {42, 43, 52, 55, 56}, - {34, 41, 52, 55, 56}, - }); + /// NOTE: We are generating from zero a few times, so without AutoSkipZero we + /// get a lot of paths here + auto PathsVec = doAnalysis("inter_05_cpp.ll", true); + comparePaths( + PathsVec, + {{22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 15, 16, 17, 18, 19, 21, 39, 40, 41, 44, 45, 46, 47, 0, 1, 2, 3, + 4, 5, 6, 7, 11, 12, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 15, + 16, 17, 18, 19, 21, 39, 40, 41, 42, 43, 44, 45, 46, 47, 0, 1, 2, 3, + 4, 5, 6, 7, 11, 12, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 15, + 16, 17, 18, 19, 20, 21, 39, 40, 41, 44, 45, 46, 47, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 15, 16, 17, 18, 19, 20, 21, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 13, 14, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 41, 44, 52, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 15, 16, 17, 18, 19, 21, 39, 40, 41, 42, 43, 44, 52, 55, 56}, + {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 15, 16, 17, 18, 19, 20, 21, 39, 40, 41, 42, 43, 44, 52, 55, 56}}); } TEST_F(PathTracingTest, Lambda_Inter_05) { @@ -325,6 +321,8 @@ TEST_F(PathTracingTest, Lambda_Inter_05) { } TEST_F(PathTracingTest, Lambda_Inter_Depth3_05) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); /// We have 4 branches ==> 16 paths auto PathsVec = doLambdaAnalysis("inter_05_cpp.ll", /*MaxDAGDepth*/ 3); comparePaths(PathsVec, @@ -341,9 +339,11 @@ TEST_F(PathTracingTest, Lambda_Inter_Depth3_05) { } TEST_F(PathTracingTest, Handle_Inter_06) { - auto PathsVec = doAnalysis("inter_06_cpp.ll", true); - comparePaths(PathsVec, {{18, 19, 20, 21, 25, 27, 2, 4, 6, 7, 28, 29, 30}, - {18, 19, 22, 26, 27, 3, 5, 6, 7, 28, 29, 30}}); + auto PathsVec = doAnalysis("inter_06_cpp.ll"); + comparePaths(PathsVec, {{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 25, 27, 0, 2, 4, 6, 7, 28, 29, 30}, + {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 22, 26, 27, 0, 3, 5, 6, 7, 28, 29, 30}}); } TEST_F(PathTracingTest, Lambda_Inter_06) { @@ -357,18 +357,28 @@ TEST_F(PathTracingTest, Handle_Inter_07) { auto PathsVec = doAnalysis("inter_07_cpp.ll"); comparePaths(PathsVec, { - {27, 28, 29, 30, 34, 44, 46, 10, 12, 14, 15, 47, 48, 49, 50}, - {27, 28, 31, 34, 45, 46, 11, 13, 14, 15, 47, 48, 49, 50}, - {27, 28, 29, 30, 34, 44, 46, 2, 4, 6, 7, 47, 48, 49, 50}, - {27, 28, 31, 34, 45, 46, 3, 5, 6, 7, 47, 48, 49, 50}, - {27, 28, 29, 30, 34, 37, 39, 10, 12, 14, 15, 40, 41, 49, 50}, - {27, 28, 31, 34, 38, 39, 11, 13, 14, 15, 40, 41, 49, 50}, - {27, 28, 29, 30, 34, 37, 39, 2, 4, 6, 7, 40, 41, 49, 50}, - {27, 28, 31, 34, 38, 39, 3, 5, 6, 7, 40, 41, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 34, 42, 44, 46, 8, 10, 12, 14, 15, 47, 48, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, + 34, 42, 45, 46, 8, 11, 13, 14, 15, 47, 48, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 34, 42, 44, 46, 0, 2, 4, 6, 7, 47, 48, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, + 34, 42, 45, 46, 0, 3, 5, 6, 7, 47, 48, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 34, 35, 37, 39, 8, 10, 12, 14, 15, 40, 41, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, + 34, 35, 38, 39, 8, 11, 13, 14, 15, 40, 41, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 34, 35, 37, 39, 0, 2, 4, 6, 7, 40, 41, 49, 50}, + {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, + 34, 35, 38, 39, 0, 3, 5, 6, 7, 40, 41, 49, 50}, }); } TEST_F(PathTracingTest, Lambda_Inter_07) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_07_cpp.ll"); comparePaths(PathsVec, { {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, @@ -387,6 +397,8 @@ TEST_F(PathTracingTest, Lambda_Inter_07) { } TEST_F(PathTracingTest, Lambda_Inter_Depth3_07) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_07_cpp.ll", /*MaxDAGDepth*/ 3); comparePaths(PathsVec, { {0, 1, 2, 3, 4, 5, 6, 7, 40, 41, 49, 50}, @@ -405,22 +417,30 @@ TEST_F(PathTracingTest, Handle_Inter_08) { comparePaths( PathsVec, { - {24, 29, 32, 41, 42, 74, 75, 76, 77}, + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 69, 70, 71, 72, 73, + 0, 1, 2, 7, 8, 10, 20, 21, 74, 75, 76, 77}, // {54, 55, 56, 57, 61, 71, 73, 26, 29, 32, // 33, 35, 36, 40, 32, 41, 42, 74, 75, 76}, // {54, 55, 58, 61, 72, 73, 27, 29, 32, 34, 35, 36, 40, // 32, 41, 42, 74, 75, 76, 77}, - {2, 7, 10, 20, 21, 74, 75, 76, 77}, + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 69, 70, 71, 72, 73, + 22, 23, 24, 29, 30, 32, 41, 42, 74, 75, 76, 77}, // {54, 55, 56, 57, 61, 71, 73, 4, 7, 10, 11, // 13, 14, 15, 19, 10, 20, 21, 74, 75, 76, 77}, // {54, 55, 58, 61, 72, 73, 5, 7, 10, 12, // 13, 14, 15, 19, 10, 20, 21, 74, 75, 76, 77}, - {24, 29, 32, 41, 42, 67, 68, 76, 77}, + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 22, 23, 24, 29, 30, 32, 41, 42, 67, 68, 76, 77}, // {54, 55, 56, 57, 61, 64, 66, 26, 29, 32, // 33, 35, 36, 40, 32, 41, 42, 67, 68, 76, 77}, // {54, 55, 58, 61, 65, 66, 27, 29, 32, 34, 35, 36, 40, 32, 41, 42, // 67, 68, 76, 77}, - {2, 7, 10, 20, 21, 67, 68, 76, 77}, + {43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 0, 1, 2, 7, 8, 10, 20, 21, 67, 68, 76, 77}, // {54, 55, 56, 57, 61, 64, 66, 4, 7, 10, 11, // 13, 14, 15, 19, 10, 20, 21, 67, 68, 76, 77}, // {54, 55, 58, 61, 65, 66, 5, 7, 10, 12, @@ -429,6 +449,8 @@ TEST_F(PathTracingTest, Handle_Inter_08) { } TEST_F(PathTracingTest, Lambda_Inter_08) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_08_cpp.ll"); /// FIXME: Handle mutable z3::exprs; As of now, we reject all paths that go /// into a loop, because this requires the loop condiiton to hold, whereas @@ -477,11 +499,13 @@ TEST_F(PathTracingTest, Handle_Inter_09) { PathsVec, { // {22, 2, 5, 6, 7, 8, 2, 5, 11, 12, 13, 14, 15, 9, 10, 14, 15}, - {22, 2, 5, 11, 12, 13, 14, 15, 24}, + {16, 17, 18, 19, 20, 21, 22, 0, 2, 5, 11, 12, 13, 14, 15, 23, 24}, }); } TEST_F(PathTracingTest, Lambda_Inter_09) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_09_cpp.ll"); /// FIXME: Same reason as Lambda_Inter_08 comparePaths(PathsVec, { @@ -494,6 +518,8 @@ TEST_F(PathTracingTest, Lambda_Inter_09) { } TEST_F(PathTracingTest, Handle_Inter_10) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); GTEST_SKIP() << "Need globals support"; auto PathsVec = doAnalysis("inter_10_cpp.ll", true); /// TODO: GT @@ -503,10 +529,14 @@ TEST_F(PathTracingTest, Handle_Inter_11) { auto PathsVec = doAnalysis("inter_11_cpp.ll"); // Note: The alias analysis is strong enough to see that Three::assignValue // can never be called - comparePaths(PathsVec, {{25, 44, 46, 47, 48, 26}}); + comparePaths(PathsVec, + {{16, 17, 27, 28, 29, 30, 31, 35, 36, 37, 38, 39, 40, 32, 33, + 34, 18, 19, 20, 21, 22, 23, 24, 25, 41, 44, 46, 47, 48, 26}}); } TEST_F(PathTracingTest, Lambda_Inter_11) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_11_cpp.ll"); // Note: The alias analysis is strong enough to see that Three::assignValue // can never be called @@ -518,11 +548,17 @@ TEST_F(PathTracingTest, Lambda_Inter_11) { TEST_F(PathTracingTest, Handle_Inter_12) { auto PathsVec = doAnalysis("inter_12_cpp.ll"); - comparePaths(PathsVec, - {{42, 112, 114, 115, 116, 43}, {42, 82, 84, 85, 86, 43}}); + comparePaths( + PathsVec, + {{33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, + 59, 35, 36, 37, 38, 39, 40, 41, 42, 79, 82, 84, 85, 86, 43}, + {33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, + 59, 35, 36, 37, 38, 39, 40, 41, 42, 109, 112, 114, 115, 116, 43}}); } TEST_F(PathTracingTest, Lambda_Inter_12) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_12_cpp.ll"); comparePaths( PathsVec, @@ -556,46 +592,64 @@ TEST_F(PathTracingTest, Lambda_Inter_12) { 89, 90, 101, 106, 107, 108, 31, 32, 33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, 36, 37, 38, 39, 40, 41, 42, 109, 110, 111, 112, 113, 114, 115, 116, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, 60, + 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 32, 33, 34, + 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, 36, + 37, 38, 39, 40, 41, 42, 79, 80, 81, 82, 83, 84, 85, 86, 43}, }); } TEST_F(PathTracingTest, Handle_Intra_01) { auto PathsVec = doAnalysis("intra_01_cpp.ll"); - comparePaths(PathsVec, {{6, 7, 8, 9, 10, 11}}); + comparePaths(PathsVec, {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}); } TEST_F(PathTracingTest, Handle_Intra_02) { auto PathsVec = doAnalysis("intra_02_cpp.ll"); - comparePaths(PathsVec, {{10, 11, 14, 15}, {12, 13, 14, 15}}); + comparePaths(PathsVec, {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15}}); } TEST_F(PathTracingTest, Handle_Intra_03) { auto PathsVec = doAnalysis("intra_03_cpp.ll"); - comparePaths(PathsVec, {{15, 16, 19, 20}}); + comparePaths(PathsVec, {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 19, 20}}); } TEST_F(PathTracingTest, Handle_Intra_04) { + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doAnalysis("intra_04_cpp.ll"); /// FIXME: Same reason as Handle_Inter_08 comparePaths(PathsVec, { - // {16, 18, 21, 22, 23, 24, 25, 29, 21, 30, 33, 34}, - {16, 18, 21, 30, 33, 34}, + // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + // 18, 21, 22, 23, 24, 25, 29, 21, 30, 33, 34}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 18, 19, 21, 30, 33, 34}, }); } TEST_F(PathTracingTest, Handle_Intra_05) { - auto PathsVec = doAnalysis("intra_05_cpp.ll", true); - comparePaths(PathsVec, {{14, 15, 19, 20}, {17, 18, 19, 20}}); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + auto PathsVec = doAnalysis("intra_05_cpp.ll"); + comparePaths( + PathsVec, + {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 19, 20}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 17, 18, 19, 20}}); } TEST_F(PathTracingTest, Handle_Intra_06) { auto PathsVec = doAnalysis("intra_06_cpp.ll"); - comparePaths(PathsVec, {{11, 12, 15, 16}, {13, 14, 15, 16}}); + comparePaths(PathsVec, {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16}}); } TEST_F(PathTracingTest, Handle_Intra_07) { - auto PathsVec = doAnalysis("intra_07_cpp.ll", true); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + auto PathsVec = doAnalysis("intra_07_cpp.ll"); /// FIXME: Same reason as Handle_Inter_08 comparePaths( PathsVec, @@ -606,30 +660,42 @@ TEST_F(PathTracingTest, Handle_Intra_07) { // 18, 19, 20, 21, 22, 31, 32, 33, 34, 35, 38, 39}, // {16, 17, 19, 22, 23, 24, 25, 26, 30, 22, 31, 34, 35, 38, 39}, // {16, 17, 19, 22, 31, 34, 19, 22, 31, 34, 35, 38, 39}, - {16, 17, 19, 22, 31, 34, 35, 38, 39}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 22, 31, 32, 34, 35, 38, 39}, }); } TEST_F(PathTracingTest, Handle_Intra_08) { + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doAnalysis("intra_08_cpp.ll"); - /// Note: we have a fallthrough from case 4 to default; Therefore, we only + /// NOTE: we have a fallthrough from case 4 to default; Therefore, we only /// have 3 paths - comparePaths(PathsVec, {{9, 10, 17, 18}, {11, 12, 17, 18}, {15, 16, 17, 18}}); + /// UPDATE: Despite the fallthrough, clang-14 now generates 4 distinct + /// switch-cases, where the ID13 one just branches into the default case. So, + /// we now have 4 cases! + comparePaths(PathsVec, {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 17, 18}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 17, 18}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 17, 18}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 13, 14, 15, 16, 17, 18}}); } TEST_F(PathTracingTest, Handle_Intra_09) { - auto PathsVec = doAnalysis("intra_09_cpp.ll", true); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + auto PathsVec = doAnalysis("intra_09_cpp.ll"); /// FIXME: Same reason as Handle_Inter_08 - comparePaths(PathsVec, { - // {5, 11, 14, 16, 17, 18, 22, 14, 23, 24}, - // {4, 11, 14, 15, 17, 18, 22, 14, 23, 24}, - {3, 11, 14, 23, 24}, - }); + comparePaths(PathsVec, + { + // {0, 1, 2, 5, 11, 14, 16, 17, 18, 22, 14, 23, 24}, + // {0, 1, 2, 4, 11, 14, 15, 17, 18, 22, 14, 23, 24}, + {0, 1, 2, 3, 11, 12, 14, 23, 24}, + }); } TEST_F(PathTracingTest, Handle_Other_01) { auto PathsVec = doAnalysis("other_01_cpp.ll"); - comparePaths(PathsVec, {{1, 6, 7, 8, 9, 10, 12, 13}}); + comparePaths(PathsVec, {{0, 1, 6, 7, 8, 9, 10, 12, 13}}); } // main function for the test case From 21d4cba09bda1a4672bfc508edeec5033b661faf Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 Aug 2022 16:54:53 +0200 Subject: [PATCH 12/65] Fix Config propagation --- .../PathSensitivityManagerBase.h | 70 ++++++++++++++++++- .../PathSensitivityManagerMixin.h | 10 +-- .../Z3BasedPathSensitvityManager.h | 29 +++++++- include/phasar/Utils/GraphTraits.h | 23 +++--- 4 files changed, 118 insertions(+), 14 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h index 59dc1e9fd2..66e9333fde 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h @@ -11,6 +11,7 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H #include "phasar/Utils/AdjacencyList.h" +#include "phasar/Utils/Logger.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/IntEqClasses.h" @@ -76,8 +77,68 @@ template class PathSensitivityManagerBase { return true; } + graph_type reverseDAG(graph_type &&Dag, size_t MaxDepth) const { + struct ReverseDAGContext { + llvm::BitVector Visited; + size_t CurrDepth = 0; + size_t MaxDepth = 0; + } Ctx; + + Ctx.Visited.resize(graph_traits_t::size(Dag)); + Ctx.MaxDepth = MaxDepth; + + graph_type Ret{}; + if constexpr (is_reservable_graph_trait_v) { + graph_traits_t::reserve(Ret, graph_traits_t::size(Dag)); + } + + // NOLINTNEXTLINE(readability-identifier-naming) + auto buildReverseDag = [&Ctx, &Ret, &Dag](auto &buildReverseDag, + vertex_t Vtx) { + if (Ctx.Visited.test(Vtx)) { + return Vtx; + } + + Ctx.Visited.set(Vtx); + + auto Rev = graph_traits_t::addNode( + Ret, std::move(graph_traits_t::node(Dag, Vtx))); + + if (Ctx.CurrDepth >= Ctx.MaxDepth) { + graph_traits_t::addRoot(Ret, Rev); + return Rev; + } + + ++Ctx.CurrDepth; + scope_exit DecreaseDepth = [&Ctx] { --Ctx.CurrDepth; }; + + for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { + /// NOTE: Depending on the depth of SuccRev, we can still get DAGs + /// deeper than MaxDepth! + /// However, this is not considered harmful as of now - the DAG still + /// does not exceed a particular program-slice which size is fixed + auto SuccRev = + buildReverseDag(buildReverseDag, graph_traits_t::target(Succ)); + graph_traits_t::addEdge(Ret, SuccRev, + graph_traits_t::withEdgeTarget(Succ, Rev)); + } + + if (graph_traits_t::outDegree(Dag, Vtx) == 0) { + graph_traits_t::addRoot(Ret, Rev); + } + + return Rev; + }; + + for (auto Rt : graph_traits_t::roots(Dag)) { + buildReverseDag(buildReverseDag, Rt); + } + + return Ret; + } + graph_type reverseDAG(graph_type &&Dag, const llvm::IntEqClasses &Equiv, - size_t MaxDepth = SIZE_MAX) const { + size_t MaxDepth) const { struct ReverseDAGContext { llvm::SmallVector Cache; @@ -113,10 +174,17 @@ template class PathSensitivityManagerBase { Ctx.Cache[Eq] = Rev; if (Ctx.CurrDepth >= Ctx.MaxDepth) { + // PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + // "Reached MaxDepth: " << Ctx.CurrDepth); graph_traits_t::addRoot(Ret, Rev); // Ret.Roots.push_back(Rev); return Rev; } + // else { + // PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + // "Have not reached MaxDepth: " + // << Ctx.CurrDepth << " vs " << Ctx.MaxDepth); + // } ++Ctx.CurrDepth; scope_exit DecreaseDepth = [&Ctx] { --Ctx.CurrDepth; }; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index 009bc6b18f..8d0fdc941a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -40,9 +40,10 @@ class PathSensitivityManagerMixin { } public: + template [[nodiscard]] GraphType pathsDagTo(n_t Inst, d_t Fact, - const PathSensitivityConfig &Config = {}) const { + const PathSensitivityConfigBase &Config) const { auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); if (!Nod) { @@ -66,10 +67,11 @@ class PathSensitivityManagerMixin { if (Config.MinimizeDAG) { auto Equiv = minimizeGraph(Dag); - Dag = - static_cast(this)->reverseDAG(std::move(Dag), Equiv); + Dag = static_cast(this)->reverseDAG( + std::move(Dag), Equiv, Config.DAGDepthThreshold); } else { - Dag = reverseGraph(std::move(Dag)); + Dag = static_cast(this)->reverseDAG( + std::move(Dag), Config.DAGDepthThreshold); } return Dag; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h index ed154f2619..1db808ceb2 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -15,15 +15,20 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" #include "phasar/Utils/GraphTraits.h" +#include "phasar/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/MaybeUniquePtr.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include "z3++.h" #include #include +#include #include namespace llvm { @@ -92,7 +97,29 @@ class Z3BasedPathSensitivityManager "please call the pathsOrConstraintTo function instead!"); } - graph_type Dag = this->pathsDagTo(Inst, std::move(Fact)); + graph_type Dag = this->pathsDagTo(Inst, std::move(Fact), Config); + + PHASAR_LOG_LEVEL_CAT( + DEBUG, "PathSensitivityManager", + "PathsTo with MaxDAGDepth: " << Config.DAGDepthThreshold); + +#ifndef NDEBUG + { + std::error_code EC; + llvm::raw_fd_stream ROS("dag-" + psr::getMetaDataID(Inst) + ".dot", EC); + printGraph(Dag, ROS, "DAG", [](llvm::ArrayRef PartialPath) { + std::string Buf; + llvm::raw_string_ostream ROS(Buf); + ROS << "[ "; + llvm::interleaveComma(PartialPath, ROS, [&ROS](const auto *Inst) { + ROS << psr::getMetaDataID(Inst); + }); + ROS << " ]"; + ROS.flush(); + return Buf; + }); + } +#endif vertex_t Leaf = [&Dag] { for (auto Vtx : graph_traits_t::vertices(Dag)) { diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index 337e950217..a42bc615a1 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -17,6 +17,7 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/identity.h" #include "llvm/Support/raw_ostream.h" #include @@ -169,9 +170,20 @@ std::decay_t reverseGraph(GraphTy &&G) return Ret; } -template +template struct DefaultNodeTransform { + std::string operator()(const N &Nod) const { + std::string Buf; + llvm::raw_string_ostream ROS(Buf); + ROS << Nod; + ROS.flush(); + return Buf; + } +}; + +template ::value_type>> void printGraph(const GraphTy &G, llvm::raw_ostream &OS, - llvm::StringRef Name = "") + llvm::StringRef Name = "", NodeTransform NodeToString = {}) #if __cplusplus >= 202002L requires is_graph #endif @@ -182,18 +194,13 @@ void printGraph(const GraphTy &G, llvm::raw_ostream &OS, psr::scope_exit CloseBrace = [&OS] { OS << "}\n"; }; auto Sz = traits_t::size(G); - std::string Buf; for (size_t I = 0; I < Sz; ++I) { OS << I; if constexpr (!std::is_same_v) { OS << "[label=\""; - - Buf.clear(); - llvm::raw_string_ostream ROS(Buf); - ROS << traits_t::node(G, I); - OS.write_escaped(ROS.str()); + OS.write_escaped(NodeToString(traits_t::node(G, I))); OS << "\"]"; } OS << ";\n"; From b898204309aa5837d0b4576584264af9ea731af7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 26 Aug 2022 17:05:39 +0200 Subject: [PATCH 13/65] Finally, fix all unittests --- .../PathSensitivity/PathTracingTest.cpp | 74 +++++++++++++------ 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp index 6e84219ed5..3dd6c08d81 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp @@ -243,8 +243,8 @@ TEST_F(PathTracingTest, Handle_Inter_04) { } TEST_F(PathTracingTest, Lambda_Inter_04) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_04_cpp.ll"); comparePaths(PathsVec, { @@ -321,8 +321,8 @@ TEST_F(PathTracingTest, Lambda_Inter_05) { } TEST_F(PathTracingTest, Lambda_Inter_Depth3_05) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); /// We have 4 branches ==> 16 paths auto PathsVec = doLambdaAnalysis("inter_05_cpp.ll", /*MaxDAGDepth*/ 3); comparePaths(PathsVec, @@ -377,8 +377,8 @@ TEST_F(PathTracingTest, Handle_Inter_07) { } TEST_F(PathTracingTest, Lambda_Inter_07) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_07_cpp.ll"); comparePaths(PathsVec, { {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, @@ -397,8 +397,8 @@ TEST_F(PathTracingTest, Lambda_Inter_07) { } TEST_F(PathTracingTest, Lambda_Inter_Depth3_07) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_07_cpp.ll", /*MaxDAGDepth*/ 3); comparePaths(PathsVec, { {0, 1, 2, 3, 4, 5, 6, 7, 40, 41, 49, 50}, @@ -449,8 +449,8 @@ TEST_F(PathTracingTest, Handle_Inter_08) { } TEST_F(PathTracingTest, Lambda_Inter_08) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_08_cpp.ll"); /// FIXME: Handle mutable z3::exprs; As of now, we reject all paths that go /// into a loop, because this requires the loop condiiton to hold, whereas @@ -504,8 +504,8 @@ TEST_F(PathTracingTest, Handle_Inter_09) { } TEST_F(PathTracingTest, Lambda_Inter_09) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_09_cpp.ll"); /// FIXME: Same reason as Lambda_Inter_08 comparePaths(PathsVec, { @@ -518,8 +518,8 @@ TEST_F(PathTracingTest, Lambda_Inter_09) { } TEST_F(PathTracingTest, Handle_Inter_10) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); GTEST_SKIP() << "Need globals support"; auto PathsVec = doAnalysis("inter_10_cpp.ll", true); /// TODO: GT @@ -529,14 +529,14 @@ TEST_F(PathTracingTest, Handle_Inter_11) { auto PathsVec = doAnalysis("inter_11_cpp.ll"); // Note: The alias analysis is strong enough to see that Three::assignValue // can never be called - comparePaths(PathsVec, - {{16, 17, 27, 28, 29, 30, 31, 35, 36, 37, 38, 39, 40, 32, 33, - 34, 18, 19, 20, 21, 22, 23, 24, 25, 41, 44, 46, 47, 48, 26}}); + comparePaths(PathsVec, {{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 27, 28, 29, + 30, 31, 35, 36, 37, 38, 39, 40, 32, 33, 34, 18, 19, + 20, 21, 22, 23, 24, 25, 41, 44, 46, 47, 48, 26}}); } TEST_F(PathTracingTest, Lambda_Inter_11) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_11_cpp.ll"); // Note: The alias analysis is strong enough to see that Three::assignValue // can never be called @@ -550,15 +550,41 @@ TEST_F(PathTracingTest, Handle_Inter_12) { auto PathsVec = doAnalysis("inter_12_cpp.ll"); comparePaths( PathsVec, - {{33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, + {{11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, + 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 32, + 33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, + 59, 35, 36, 37, 38, 39, 40, 41, 42, 79, 82, 84, 85, 86, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, + 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 32, + 33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, + 59, 35, 36, 37, 38, 39, 40, 41, 42, 109, 112, 114, 115, 116, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, 60, 61, + 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 72, 73, 74, 75, 66, 67, 68, 69, 70, 87, 88, 89, 90, 71, 76, 77, 78, + 31, 32, 33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, 36, 37, 38, 39, 40, 41, 42, 79, 82, 84, 85, 86, 43}, - {33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, - 59, 35, 36, 37, 38, 39, 40, 41, 42, 109, 112, 114, 115, 116, 43}}); + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, 48, 60, 61, + 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 72, 73, 74, 75, 66, 67, 68, 69, 70, 87, 88, 89, 90, 71, 76, 77, 78, + 31, 32, 33, 34, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, + 59, 35, 36, 37, 38, 39, 40, 41, 42, 109, 112, 114, 115, 116, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, + 48, 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 102, 103, 104, 105, 96, 97, 98, 99, + 100, 87, 88, 89, 90, 101, 106, 107, 108, 31, 32, 33, 34, 52, + 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, + 36, 37, 38, 39, 40, 41, 42, 79, 82, 84, 85, 86, 43}, + {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 44, 45, 46, 47, + 48, 60, 61, 62, 63, 64, 65, 49, 50, 51, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 102, 103, 104, 105, 96, 97, 98, 99, + 100, 87, 88, 89, 90, 101, 106, 107, 108, 31, 32, 33, 34, 52, + 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 57, 58, 59, 35, + 36, 37, 38, 39, 40, 41, 42, 109, 112, 114, 115, 116, 43}}); } TEST_F(PathTracingTest, Lambda_Inter_12) { - psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); auto PathsVec = doLambdaAnalysis("inter_12_cpp.ll"); comparePaths( PathsVec, From 2a286bfaea6c4face32d5829264cf9f59069b6fb Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 4 Sep 2022 15:43:33 +0200 Subject: [PATCH 14/65] minor --- include/phasar/Utils/AdjacencyList.h | 46 +++++++++++++++++----------- include/phasar/Utils/GraphTraits.h | 18 +++++------ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/include/phasar/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h index 900934ab0c..e09bb99fa5 100644 --- a/include/phasar/Utils/AdjacencyList.h +++ b/include/phasar/Utils/AdjacencyList.h @@ -36,6 +36,7 @@ template struct AdjacencyList { llvm::SmallVector Roots{}; }; +/// A simple graph implementation based on an adjacency list template struct GraphTraits> { using graph_type = AdjacencyList; @@ -45,6 +46,8 @@ struct GraphTraits> { using edge_iterator = typename llvm::ArrayRef::const_iterator; using roots_iterator = typename llvm::ArrayRef::const_iterator; + /// A vertex that is not inserted into any graph. Can be used to communicate + /// failure of certain operations static inline constexpr auto Invalid = std::numeric_limits::max(); /// Adds a new node to the graph G with node-tag Val @@ -75,8 +78,8 @@ struct GraphTraits> { /// Makes the node Vtx as root in the graph G. A node should not be registered /// as root multiple times static void addRoot(graph_type &G, vertex_t Vtx) { + assert(Vtx < G.Adj.size()); if constexpr (!std::is_same_v) { - assert(Vtx < G.Nodes.size()); assert(G.Adj.size() == G.Nodes.size()); } G.Roots.push_back(Vtx); @@ -90,10 +93,10 @@ struct GraphTraits> { return G.Roots; } - /// Adds a new edge from node From to node To in graph G. From and T should be - /// nodes inside G. Multi-edges are supported, i.e. edges are not deduplicated - /// automatically; to manualy deduplicate the edges of one source-node, call - /// dedupOutEdges() + /// Adds a new edge from node From to node To in graph G. From and To should + /// be nodes inside G. Multi-edges are supported, i.e. edges are not + /// deduplicated automatically; to manually deduplicate the edges of one + /// source-node, call dedupOutEdges() static void addEdge(graph_type &G, vertex_t From, edge_t To) { assert(From < G.Adj.size()); if constexpr (!std::is_same_v) { @@ -105,8 +108,8 @@ struct GraphTraits> { /// Gets a range of all edges outgoing from node Vtx in graph G static llvm::ArrayRef outEdges(const graph_type &G, vertex_t Vtx) noexcept { + assert(Vtx < G.Adj.size()); if constexpr (!std::is_same_v) { - assert(Vtx < G.Nodes.size()); assert(G.Adj.size() == G.Nodes.size()); } return G.Adj[Vtx]; @@ -114,8 +117,8 @@ struct GraphTraits> { /// Gets the number of edges outgoing from node Vtx in graph G static size_t outDegree(const graph_type &G, vertex_t Vtx) noexcept { + assert(Vtx < G.Adj.size()); if constexpr (!std::is_same_v) { - assert(Vtx < G.Nodes.size()); assert(G.Adj.size() == G.Nodes.size()); } return G.Adj[Vtx].size(); @@ -124,8 +127,8 @@ struct GraphTraits> { /// Deduplicates the edges outgoing from node Vtx in graph G. Deduplication is /// based on operator< and operator== of the edge_t type static void dedupOutEdges(graph_type &G, vertex_t Vtx) noexcept { + assert(Vtx < G.Adj.size()); if constexpr (!std::is_same_v) { - assert(Vtx < G.Nodes.size()); assert(G.Adj.size() == G.Nodes.size()); } auto &OutEdges = G.Adj[Vtx]; @@ -142,19 +145,16 @@ struct GraphTraits> { return G.Nodes; } /// Gets a mutable range of all nodes in graph G - template - static std::enable_if_t, - llvm::MutableArrayRef> - nodes(graph_type &G) noexcept { + template >> + static llvm::MutableArrayRef nodes(graph_type &G) noexcept { assert(G.Adj.size() == G.Nodes.size()); return G.Nodes; } /// Gets a range of all nodes in graph G template >> - static std::enable_if_t, - RepeatRangeType> - nodes(const graph_type &G) noexcept { + static RepeatRangeType nodes(const graph_type &G) noexcept { return repeat(llvm::None, G.Adj.size()); } @@ -201,7 +201,7 @@ struct GraphTraits> { } /// Gets the number of nodes in graph G that are marked as root - static size_t roots_size(const graph_type &G) noexcept { + static size_t roots_size(const graph_type &G) noexcept { // NOLINT if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); } @@ -241,7 +241,7 @@ struct GraphTraits> { } /// Copies the given edge, but replaces the target node by Tar; i.e. the - /// weight of the returned edge and the passed edge is same, but the target + /// weight of the returned edge and the parameter edge is same, but the target /// nodes may differ. template static std::enable_if_t, edge_t> @@ -254,9 +254,14 @@ struct GraphTraits> { return llvm::None; } + /// Removes the edge denoted by It outgoing from source-vertex Vtx from the + /// graph G. This function is not required by the is_graph_trait concept. + /// + /// \returns An edge_iterator directly following It that should be used to + /// continue iteration instead of std::next(It) static edge_iterator removeEdge(graph_type &G, vertex_t Vtx, edge_iterator It) noexcept { - assert(Vtx < G.Nodes.size()); + assert(Vtx < G.Adj.size()); if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); } @@ -268,6 +273,11 @@ struct GraphTraits> { return It; } + /// Removes the root denoted by It from the graph G. This function is not + /// required by the is_graph_trait concept. + /// + /// \returns A roots_iterator directly following It that should be used to + /// continue iteration instead of std::next(It) static roots_iterator removeRoot(graph_type &G, roots_iterator It) noexcept { if constexpr (!std::is_same_v) { assert(G.Adj.size() == G.Nodes.size()); diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index a42bc615a1..bac0a3135c 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -21,6 +21,7 @@ #include "llvm/Support/raw_ostream.h" #include +#include #include #include @@ -28,9 +29,8 @@ namespace psr { /// We aim to get rid of boost, so introduce a new GraphTraits class to replace /// it. -/// This GraphTraits type should be specialized for each typy that should -/// implement a "graph". All the functionality should be reflected by the -/// GraphTraits class. +/// This GraphTraits type should be specialized for each type that implements a +/// "graph". All the functionality should be reflected by the GraphTraits class. /// Once moving to C++20, we have nice type-checking using concepts template struct GraphTraits; @@ -69,8 +69,7 @@ concept is_graph_trait = requires(typename GraphTrait::graph_type &graph, } -> psr::is_iterable_over_v; { GraphTrait::vertices(cgraph) - ->psr::is_iterable_over_v; - } + } -> psr::is_iterable_over_v; { GraphTrait::node(cgraph, vtx) } -> std::convertible_to; @@ -170,8 +169,8 @@ std::decay_t reverseGraph(GraphTy &&G) return Ret; } -template struct DefaultNodeTransform { - std::string operator()(const N &Nod) const { +struct DefaultNodeTransform { + template std::string operator()(const N &Nod) const { std::string Buf; llvm::raw_string_ostream ROS(Buf); ROS << Nod; @@ -180,8 +179,7 @@ template struct DefaultNodeTransform { } }; -template ::value_type>> +template void printGraph(const GraphTy &G, llvm::raw_ostream &OS, llvm::StringRef Name = "", NodeTransform NodeToString = {}) #if __cplusplus >= 202002L @@ -200,7 +198,7 @@ void printGraph(const GraphTy &G, llvm::raw_ostream &OS, if constexpr (!std::is_same_v) { OS << "[label=\""; - OS.write_escaped(NodeToString(traits_t::node(G, I))); + OS.write_escaped(std::invoke(NodeToString, traits_t::node(G, I))); OS << "\"]"; } OS << ";\n"; From a9642e2caa1df952df99c9d47b287c870d691fc3 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 6 Sep 2022 18:00:48 +0200 Subject: [PATCH 15/65] redirect z3 submodule --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 840e0ac563..c97fd9d160 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,5 +14,5 @@ url = https://github.com/pboettch/json-schema-validator.git [submodule "external/z3"] path = external/z3 - url = https://github.com/Z3Prover/z3.git - branch = z3-4.11.0 + url = https://github.com/fabianbs96/z3 + branch = LLVMCompatibleZ3 From 848ba9b08cd1324c2559fde21b8c5386b1ad46b6 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 6 Sep 2022 18:11:54 +0200 Subject: [PATCH 16/65] Checkout the right z3 branch --- external/z3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/z3 b/external/z3 index 19da3c7086..2b6a237162 160000 --- a/external/z3 +++ b/external/z3 @@ -1 +1 @@ -Subproject commit 19da3c7086dcf5cd0c78a82db9f99f5ef295b8ff +Subproject commit 2b6a2371620f0ac9d992075733e2152a6d78299e From 71891e6f8cf9c86b114e50264d845a2579875c29 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 12 Sep 2022 19:03:03 +0200 Subject: [PATCH 17/65] bump z3 --- external/z3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/z3 b/external/z3 index 2b6a237162..02d0c8667f 160000 --- a/external/z3 +++ b/external/z3 @@ -1 +1 @@ -Subproject commit 2b6a2371620f0ac9d992075733e2152a6d78299e +Subproject commit 02d0c8667fb4366280574daf443a8dbf90516d08 From c70b7efbc226da0e88099a045c65bba85d48d6c5 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 13 Sep 2022 10:40:48 +0200 Subject: [PATCH 18/65] add bulk dag-generation (not tested yet) --- .clang-tidy | 2 +- .../IfdsIde/Solver/PathAwareIDESolver.h | 14 ++++- .../PathSensitivityManagerMixin.h | 52 ++++++++++++++----- .../Z3BasedPathSensitvityManager.h | 21 ++++---- .../phasar/PhasarLLVM/Utils/BinaryDomain.h | 10 +--- lib/PhasarLLVM/Utils/BinaryDomain.cpp | 10 +--- .../PathSensitivity/PathTracingTest.cpp | 36 ++++++------- utils/install-llvm.sh | 2 +- 8 files changed, 87 insertions(+), 60 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 57a4a45300..289764cbbf 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -31,7 +31,7 @@ Checks: '-*, -modernize-use-trailing-return-type, -modernize-pass-by-value, performance-*, - clang-analyzer-*, + clang-analyzer-* ' FormatStyle: LLVM diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h index 44bffb5085..3f09cd2743 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h @@ -1,4 +1,14 @@ -#pragma once +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h" @@ -49,3 +59,5 @@ PathAwareIDESolver(ProblemTy &) -> PathAwareIDESolver; } // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index 8d0fdc941a..b1c67aa06d 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -10,11 +10,17 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" #include "phasar/Utils/GraphTraits.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" + #include namespace psr { @@ -40,21 +46,26 @@ class PathSensitivityManagerMixin { } public: - template + template [[nodiscard]] GraphType - pathsDagTo(n_t Inst, d_t Fact, - const PathSensitivityConfigBase &Config) const { - auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); + pathsDagToAll(n_t Inst, FactsRangeTy FactsRange, + const PathSensitivityConfigBase &Config) const { + graph_type Dag; - if (!Nod) { - llvm::report_fatal_error( - "Invalid Instruction-FlowFact pair. Only use those pairs that are " - "part of the IDE analysis results!"); - } + for (const d_t &Fact : FactsRange) { + auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); - graph_type Dag; - auto Rt = pathsToImpl(Inst, Nod, Dag); - graph_traits_t::addRoot(Dag, Rt); + if (!Nod) { + llvm::report_fatal_error( + "Invalid Instruction-FlowFact pair. Only use those pairs that are " + "part of the IDE analysis results!"); + } + + auto Rt = pathsToImpl(Inst, Nod, Dag); + if (Rt != GraphTraits::Invalid) { + graph_traits_t::addRoot(Dag, Rt); + } + } #ifndef NDEBUG if (!static_cast(this)->assertIsDAG(Dag)) { @@ -77,6 +88,23 @@ class PathSensitivityManagerMixin { return Dag; } + template + [[nodiscard]] GraphType + pathsDagTo(n_t Inst, const SolverResults &SR, + const PathSensitivityConfigBase &Config) const { + auto Res = SR.resultsAt(Inst); + auto FactsRange = llvm::make_first_range(Res); + return pathsDagToAll(std::move(Inst), FactsRange, Config); + } + + template + [[nodiscard]] GraphType + pathsDagTo(n_t Inst, d_t Fact, + const PathSensitivityConfigBase &Config) const { + + return pathsDagToAll(std::move(Inst), llvm::ArrayRef(&Fact, 1), Config); + } + private: using Node = typename ExplodedSuperGraph::Node; using graph_type = GraphType; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h index 1db808ceb2..e5e74c6a02 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -15,6 +15,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" #include "phasar/Utils/GraphTraits.h" +#include "phasar/Utils/LLVMIRToSrc.h" #include "phasar/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/MaybeUniquePtr.h" @@ -27,6 +28,7 @@ #include "z3++.h" #include +#include #include #include #include @@ -106,7 +108,14 @@ class Z3BasedPathSensitivityManager #ifndef NDEBUG { std::error_code EC; - llvm::raw_fd_stream ROS("dag-" + psr::getMetaDataID(Inst) + ".dot", EC); + llvm::raw_fd_stream ROS( + "dag-" + + std::filesystem::path(psr::getFilePathFromIR(Inst)) + .filename() + .string() + + "-" + psr::getMetaDataID(Inst) + ".dot", + EC); + assert(!EC); printGraph(Dag, ROS, "DAG", [](llvm::ArrayRef PartialPath) { std::string Buf; llvm::raw_string_ostream ROS(Buf); @@ -138,16 +147,6 @@ class Z3BasedPathSensitivityManager return FlowPathSequence(); } - // if (graph_traits_t::size(Dag) > Config.DAGSizeThreshold) { - // PHASAR_LOG_LEVEL_CAT( - // INFO, "PathSensitivityManager", - // "Note: The DAG for query @ " - // << getMetaDataID(Inst) - // << " is too large. Don't collect the precise paths " - // "here"); - // return Constraint; - // } - auto Ret = filterAndFlattenRevDag(Dag, Leaf, Inst, Config, *LPC); deduplicatePaths(Ret); diff --git a/include/phasar/PhasarLLVM/Utils/BinaryDomain.h b/include/phasar/PhasarLLVM/Utils/BinaryDomain.h index 41a419d657..f90d115c28 100644 --- a/include/phasar/PhasarLLVM/Utils/BinaryDomain.h +++ b/include/phasar/PhasarLLVM/Utils/BinaryDomain.h @@ -17,21 +17,15 @@ #ifndef PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ #define PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ -#include - namespace llvm { class raw_ostream; -} +} // namespace llvm namespace psr { enum class BinaryDomain { BOTTOM = 0, TOP = 1 }; -extern const std::map StringToBinaryDomain; - -extern const std::map BinaryDomainToString; - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const BinaryDomain &B); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, BinaryDomain B); } // namespace psr diff --git a/lib/PhasarLLVM/Utils/BinaryDomain.cpp b/lib/PhasarLLVM/Utils/BinaryDomain.cpp index d17aabccc1..aca8bf7ca9 100644 --- a/lib/PhasarLLVM/Utils/BinaryDomain.cpp +++ b/lib/PhasarLLVM/Utils/BinaryDomain.cpp @@ -22,13 +22,7 @@ using namespace std; namespace psr { -const map StringToBinaryDomain = { - {"BOTTOM", BinaryDomain::BOTTOM}, {"TOP", BinaryDomain::TOP}}; - -const map BinaryDomainToString = { - {BinaryDomain::BOTTOM, "BOTTOM"}, {BinaryDomain::TOP, "TOP"}}; - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const BinaryDomain &B) { - return OS << BinaryDomainToString.at(B); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, BinaryDomain B) { + return OS << (B == BinaryDomain::BOTTOM ? "BOTTOM" : "TOP"); } } // namespace psr diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp index 3dd6c08d81..ba42dd3ced 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp @@ -1,21 +1,3 @@ -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include - -#include "TestConfig.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/raw_ostream.h" - #include "phasar/DB/ProjectIRDB.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h" @@ -35,6 +17,24 @@ #include "phasar/Utils/Logger.h" #include "phasar/Utils/Utilities.h" +#include "gtest/gtest.h" + +#include "TestConfig.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include + // ============== TEST FIXTURE ============== // class PathTracingTest : public ::testing::Test { protected: diff --git a/utils/install-llvm.sh b/utils/install-llvm.sh index ebb0c6f82e..654a662c82 100755 --- a/utils/install-llvm.sh +++ b/utils/install-llvm.sh @@ -50,7 +50,7 @@ safe_cd "${build_dir}"/llvm-project/ git checkout "${llvm_release}" mkdir -p build safe_cd build -cmake -G "Ninja" -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;libcxx;libcxxabi;libunwind;lld;compiler-rt;debuginfo-tests' -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_RTTI=ON -DLLVM_LINK_LLVM_DYLIB=ON -DLLVM_ENABLE_DUMP=ON -DLLVM_BUILD_EXAMPLES=Off -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_BUILD_TESTS=Off -DLLVM_INCLUDE_TESTS=Off -DPYTHON_EXECUTABLE="$(which python3)" ../llvm +cmake -G "Ninja" -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;libcxx;libcxxabi;libunwind;lld;compiler-rt' -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_RTTI=ON -DLLVM_LINK_LLVM_DYLIB=ON -DLLVM_ENABLE_DUMP=ON -DLLVM_BUILD_EXAMPLES=Off -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_BUILD_TESTS=Off -DLLVM_INCLUDE_TESTS=Off -DPYTHON_EXECUTABLE="$(which python3)" ../llvm cmake --build . echo "Installing LLVM to ${dest_dir}" From 25bdbb7013b207cacdef3f374db687cfa3e7d819 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 19 Sep 2022 09:05:31 +0200 Subject: [PATCH 19/65] Some more fixes --- external/z3 | 2 +- lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/external/z3 b/external/z3 index 02d0c8667f..2b6a237162 160000 --- a/external/z3 +++ b/external/z3 @@ -1 +1 @@ -Subproject commit 02d0c8667fb4366280574daf443a8dbf90516d08 +Subproject commit 2b6a2371620f0ac9d992075733e2152a6d78299e diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt index bef004d7b0..e24004fc56 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt @@ -2,6 +2,7 @@ file(GLOB_RECURSE PATHSENSITIVITY_SRC *.h *.cpp) set(PHASAR_LINK_LIBS phasar_config + phasar_controlflow phasar_utils phasar_phasarllvm_utils phasar_pointer @@ -25,7 +26,6 @@ else() ) endif() - set_target_properties(phasar_pathsensitivity PROPERTIES LINKER_LANGUAGE CXX From 38508663620232e568c6540b198d821e695fb295 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 19 Sep 2022 09:45:11 +0200 Subject: [PATCH 20/65] Add filters to PSM --- .../PathSensitivityManagerMixin.h | 86 ++++++++++--------- .../PathSensitivity/PathTracingFilter.h | 51 +++++++++++ 2 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index b1c67aa06d..7d102c5452 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -14,11 +14,13 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h" #include "phasar/Utils/GraphTraits.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include @@ -29,6 +31,16 @@ class PathSensitivityManagerMixin { using n_t = typename AnalysisDomainTy::n_t; using d_t = typename AnalysisDomainTy::d_t; + using Node = typename ExplodedSuperGraph::Node; + using graph_type = GraphType; + using graph_traits_t = GraphTraits; + using vertex_t = typename graph_traits_t::vertex_t; + + struct PathsToContext { + llvm::DenseMap Cache; + llvm::SetVector> CurrPath; + }; + static const ExplodedSuperGraph & assertNotNull(const ExplodedSuperGraph *ESG) noexcept { assert(ESG != nullptr && "The exploded supergraph passed to the " @@ -46,11 +58,14 @@ class PathSensitivityManagerMixin { } public: - template + template [[nodiscard]] GraphType pathsDagToAll(n_t Inst, FactsRangeTy FactsRange, - const PathSensitivityConfigBase &Config) const { + const PathSensitivityConfigBase &Config, + const Filter &PFilter = {}) const { graph_type Dag; + PathsToContext Ctx; for (const d_t &Fact : FactsRange) { auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); @@ -61,7 +76,12 @@ class PathSensitivityManagerMixin { "part of the IDE analysis results!"); } - auto Rt = pathsToImpl(Inst, Nod, Dag); + /// NOTE: We don't need to check that Nod has not been processed yet, + /// because in the ESG construction we only merge nodes with the same flow + /// fact. Here, the flow fact for each node differs (assuming FactsRage + /// does not contain duplicates) + + auto Rt = pathsToImpl(Inst, Nod, Dag, Ctx, PFilter); if (Rt != GraphTraits::Invalid) { graph_traits_t::addRoot(Dag, Rt); } @@ -106,30 +126,23 @@ class PathSensitivityManagerMixin { } private: - using Node = typename ExplodedSuperGraph::Node; - using graph_type = GraphType; - using graph_traits_t = GraphTraits; - using vertex_t = typename graph_traits_t::vertex_t; - - struct PathsToContext { - llvm::DenseMap Cache; - llvm::SetVector> CurrPath; - }; - + template bool pathsToImplLAInvoke(vertex_t Ret, Node *Vtx, PathsToContext &Ctx, - graph_type &RetDag) const { - - // NOLINTNEXTLINE(readability-identifier-naming) - auto reachedEnd = [](Node *Vtx) { return !Vtx; }; + graph_type &RetDag, const Filter &PFilter) const { do { graph_traits_t::node(RetDag, Ret).push_back(Vtx->Source); - Vtx = Vtx->Predecessor; - } while (!reachedEnd(Vtx) && Vtx->Neighbors.empty()); - if (reachedEnd(Vtx)) { - return true; - } + if (!Vtx->Predecessor || PFilter.HasReachedEnd(Vtx, Vtx->Predecessor)) { + return true; + } + + if (PFilter.IsErrorneousTransition(Vtx, Vtx->Predecessor)) { + return false; + } + + Vtx = Vtx->Predecessor; + } while (Vtx->Neighbors.empty()); if (!Ctx.CurrPath.insert(Ret)) { PHASAR_LOG_LEVEL(ERROR, "Node " << Ret << " already on path"); @@ -138,8 +151,8 @@ class PathSensitivityManagerMixin { scope_exit PopRet = [&Ctx] { Ctx.CurrPath.pop_back(); }; // NOLINTNEXTLINE(readability-identifier-naming) - auto traverseNext = [&Ctx, this, Ret, &RetDag](Node *Nxt) { - auto Succ = pathsToImplLA(Nxt, Ctx, RetDag); + auto traverseNext = [&Ctx, this, Ret, &RetDag, &PFilter](Node *Nxt) { + auto Succ = pathsToImplLA(Nxt, Ctx, RetDag, PFilter); if (Succ != graph_traits_t::Invalid && !Ctx.CurrPath.contains(Succ)) { graph_traits_t::addEdge(RetDag, Ret, Succ); } @@ -156,8 +169,9 @@ class PathSensitivityManagerMixin { return graph_traits_t::outDegree(RetDag, Ret) != 0; } - vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, - graph_type &RetDag) const { + template + vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, graph_type &RetDag, + const Filter &PFilter) const { /// Idea: Treat the graph as firstChild-nextSibling notation and always /// traverse with one predecessor lookAhead @@ -171,7 +185,7 @@ class PathSensitivityManagerMixin { // auto Ret = RetDag.addNode(); It->second = Ret; - if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag)) { + if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag, PFilter)) { /// NOTE: Don't erase Vtx from Cache to guarantee termination Ctx.Cache[Vtx] = graph_traits_t::Invalid; @@ -193,36 +207,28 @@ class PathSensitivityManagerMixin { return Ret; } - vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag) const { + template + vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag, + PathsToContext &Ctx, const Filter &PFilter) const { assert(Vtx->Source != QueryInst); auto Ret = graph_traits_t::addNode(RetDag, typename graph_traits_t::value_type()); graph_traits_t::node(RetDag, Ret).push_back(QueryInst); - // RetDag.PartialPath[Ret].push_back(QueryInst); - - PathsToContext Ctx; for (auto *NB : Vtx->Neighbors) { - auto NBNode = pathsToImplLA(NB, Ctx, RetDag); + auto NBNode = pathsToImplLA(NB, Ctx, RetDag, PFilter); if (NBNode != graph_traits_t::Invalid) { graph_traits_t::addEdge(RetDag, Ret, NBNode); - // Succs.push_back(NBNode); } } - auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag); + auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag, PFilter); if (VtxNode != graph_traits_t::Invalid) { graph_traits_t::addEdge(RetDag, Ret, VtxNode); - // Succs.push_back(VtxNode); } graph_traits_t::dedupOutEdges(RetDag, Ret); - /// Deduplicate the successors relation - // std::sort(Succs.begin(), Succs.end()); - // Succs.erase(std::unique(Succs.begin(), Succs.end()), Succs.end()); - - // RetDag.Successors[Ret] = std::move(Succs); return Ret; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h new file mode 100644 index 0000000000..a982f3b0df --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHTRACINGFILTER_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHTRACINGFILTER_H + +#include + +namespace psr { +template struct PathTracingFilter { + using end_filter_t = EndFilter; + using err_filter_t = ErrFilter; + EndFilter HasReachedEnd; + ErrFilter IsErrorneousTransition; +}; + +namespace detail { +struct False2 { + template + constexpr bool operator()(T && /*First*/, U && /*Second*/) const noexcept { + return false; + } +}; +} // namespace detail + +using DefaultPathTracingFilter = + PathTracingFilter; + +template +struct is_pathtracingfilter_for : std::false_type {}; +template +struct is_pathtracingfilter_for< + F, Node, + std::enable_if_t && + std::is_invocable_r_v>> + : std::true_type {}; + +template +constexpr static bool is_pathtracingfilter_for_v = + is_pathtracingfilter_for::value; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHTRACINGFILTER_H From d4de03269fad101ffa2b3ba5d633fecc3dd756d5 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 19 Sep 2022 10:08:28 +0200 Subject: [PATCH 21/65] Better integrate filter into PSM --- .../PathSensitivityManagerMixin.h | 60 ++++++++++++++----- .../PathSensitivity/PathTracingFilter.h | 17 +++--- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index 7d102c5452..e52ba37ccd 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -58,8 +58,10 @@ class PathSensitivityManagerMixin { } public: - template + template < + typename FactsRangeTy, typename ConfigTy, + typename Filter = DefaultPathTracingFilter, + typename = std::enable_if_t>> [[nodiscard]] GraphType pathsDagToAll(n_t Inst, FactsRangeTy FactsRange, const PathSensitivityConfigBase &Config, @@ -108,40 +110,58 @@ class PathSensitivityManagerMixin { return Dag; } - template + template < + typename ConfigTy, typename L, typename Filter = DefaultPathTracingFilter, + typename = std::enable_if_t>> [[nodiscard]] GraphType pathsDagTo(n_t Inst, const SolverResults &SR, - const PathSensitivityConfigBase &Config) const { + const PathSensitivityConfigBase &Config, + const Filter &PFilter = {}) const { auto Res = SR.resultsAt(Inst); auto FactsRange = llvm::make_first_range(Res); - return pathsDagToAll(std::move(Inst), FactsRange, Config); + return pathsDagToAll(std::move(Inst), FactsRange, Config, PFilter); } - template + template < + typename ConfigTy, typename Filter = DefaultPathTracingFilter, + typename = std::enable_if_t>> [[nodiscard]] GraphType pathsDagTo(n_t Inst, d_t Fact, - const PathSensitivityConfigBase &Config) const { + const PathSensitivityConfigBase &Config, + const Filter &PFilter = {}) const { - return pathsDagToAll(std::move(Inst), llvm::ArrayRef(&Fact, 1), Config); + return pathsDagToAll(std::move(Inst), llvm::ArrayRef(&Fact, 1), Config, + PFilter); } private: template bool pathsToImplLAInvoke(vertex_t Ret, Node *Vtx, PathsToContext &Ctx, graph_type &RetDag, const Filter &PFilter) const { + Node *Prev; + bool IsEnd = false; + bool IsError = false; do { + Prev = Vtx; graph_traits_t::node(RetDag, Ret).push_back(Vtx->Source); - if (!Vtx->Predecessor || PFilter.HasReachedEnd(Vtx, Vtx->Predecessor)) { + if (!Vtx->Predecessor) { return true; } - if (PFilter.IsErrorneousTransition(Vtx, Vtx->Predecessor)) { - return false; + Vtx = Vtx->Predecessor; + + if (PFilter.HasReachedEnd(Prev, Vtx)) { + IsEnd = true; + break; + } + + if (PFilter.IsErrorneousTransition(Prev, Vtx)) { + IsError = true; + break; } - Vtx = Vtx->Predecessor; } while (Vtx->Neighbors.empty()); if (!Ctx.CurrPath.insert(Ret)) { @@ -158,15 +178,25 @@ class PathSensitivityManagerMixin { } }; + if (!IsEnd && !IsError) { + traverseNext(Vtx); + } + for (auto Nxt : Vtx->Neighbors) { + assert(Nxt != nullptr); + if (PFilter.IsErrorneousTransition(Prev, Nxt)) { + continue; + } + if (PFilter.HasReachedEnd(Prev, Nxt)) { + IsEnd = true; + continue; + } traverseNext(Nxt); } - traverseNext(Vtx); - graph_traits_t::dedupOutEdges(RetDag, Ret); - return graph_traits_t::outDegree(RetDag, Ret) != 0; + return IsEnd || graph_traits_t::outDegree(RetDag, Ret) != 0; } template diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h index a982f3b0df..bcdf91e8d5 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h @@ -16,8 +16,9 @@ namespace psr { template struct PathTracingFilter { using end_filter_t = EndFilter; using err_filter_t = ErrFilter; - EndFilter HasReachedEnd; - ErrFilter IsErrorneousTransition; + + [[no_unique_address]] end_filter_t HasReachedEnd; + [[no_unique_address]] err_filter_t IsErrorneousTransition; }; namespace detail { @@ -34,13 +35,13 @@ using DefaultPathTracingFilter = template struct is_pathtracingfilter_for : std::false_type {}; -template + +template struct is_pathtracingfilter_for< - F, Node, - std::enable_if_t && - std::is_invocable_r_v>> + PathTracingFilter, Node, + std::enable_if_t< + std::is_invocable_r_v && + std::is_invocable_r_v>> : std::true_type {}; template From d90415ddc8a364f1f7ba918be7b1b64f5f8ba3e4 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 19 Sep 2022 11:44:35 +0200 Subject: [PATCH 22/65] minor --- .../PathSensitivity/ExplodedSuperGraph.h | 33 +-------- .../PathSensitivityManagerMixin.h | 9 +-- include/phasar/Utils/StableVector.h | 69 +++++++++---------- 3 files changed, 35 insertions(+), 76 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h index e86af00864..ad92a102ff 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h @@ -54,7 +54,7 @@ template class ExplodedSuperGraph { d_t Value{}; n_t Source{}; Node *Predecessor = nullptr; - llvm::TinyPtrVector Neighbors; + llvm::TinyPtrVector Neighbors{}; }; explicit ExplodedSuperGraph( @@ -101,37 +101,6 @@ template class ExplodedSuperGraph { [[nodiscard]] size_t size() const noexcept { return NodeOwner.size(); } - // LLVM_DUMP_METHOD void dump() const { node_owner.dump(llvm::errs()); } - - void validate(Node *Vtx) const noexcept { - - // NOLINTNEXTLINE(readability-identifier-naming) - auto toHexString = [](void *ptr) { - std::string Ret(2 + 2 * sizeof(void *), '\0'); - Ret.resize(snprintf(Ret.data(), Ret.size() + 1, "%p", ptr)); - return Ret; - }; - - if (!NodeOwner.member(Vtx)) { - llvm::report_fatal_error(llvm::StringRef("Vtx ") + toHexString(Vtx) + - " is no member of the NodeOwner!"); - } - - for (auto *NB : Vtx->Neighbors) { - if (!NodeOwner.member(NB)) { - llvm::report_fatal_error(llvm::StringRef("NB ") + toHexString(Vtx) + - " of Vtx " + toHexString(Vtx) + - " is no member of the NodeOwner!"); - } - } - - if (Vtx->Predecessor && !NodeOwner.member(Vtx->Predecessor)) { - llvm::report_fatal_error( - llvm::StringRef("Pred ") + toHexString(Vtx->Predecessor) + - " of Vtx " + toHexString(Vtx) + " is no member of the NodeOwner!"); - } - } - /// Printing: void printAsDot(llvm::raw_ostream &OS) const { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index e52ba37ccd..ea2d34c6e6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -217,6 +217,7 @@ class PathSensitivityManagerMixin { if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag, PFilter)) { /// NOTE: Don't erase Vtx from Cache to guarantee termination + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) -- fp Ctx.Cache[Vtx] = graph_traits_t::Invalid; if (Ctx.CurrPath.contains(Ret) || !graph_traits_t::pop(RetDag, Ret)) { @@ -224,14 +225,6 @@ class PathSensitivityManagerMixin { graph_traits_t::node(RetDag, Ret).clear(); } - // if (RetDag.isLast(Ret) && !Ctx.CurrPath.contains(Ret)) { - // /// Assume, Ret is not referenced by any other node - // RetDag.pop(); - // } else { - // PHASAR_LOG_LEVEL(WARNING, << "Cannot remove invalid path at: " << - // Ret); RetDag.PartialPath[Ret].clear(); - // } - return graph_traits_t::Invalid; } return Ret; diff --git a/include/phasar/Utils/StableVector.h b/include/phasar/Utils/StableVector.h index 31b740924e..5487865112 100644 --- a/include/phasar/Utils/StableVector.h +++ b/include/phasar/Utils/StableVector.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "llvm/ADT/SmallVector.h" #include "llvm/Support/MathExtras.h" @@ -152,20 +153,21 @@ class StableVector { using allocator_type = typename std::allocator_traits::template rebind_alloc; - StableVector(const allocator_type &Alloc = allocator_type()) noexcept( + StableVector() noexcept( + std::is_nothrow_default_constructible_v) = default; + + StableVector(const allocator_type &Alloc) noexcept( std::is_nothrow_copy_constructible_v) : Alloc(Alloc) {} StableVector(StableVector &&Other) noexcept - : Blocks(std::move(Other.Blocks)), Start(Other.Start), Pos(Other.Pos), - End(Other.End), Size(Other.Size), BlockIdx(Other.BlockIdx), - Alloc(std::move(Other.Alloc)) { - Other.Start = nullptr; - Other.Pos = nullptr; - Other.End = nullptr; - Other.Size = 0; - Other.BlockIdx = 0; - } + : Blocks(std::move(Other.Blocks)), + Start(std::exchange(Other.Start, nullptr)), + Pos(std::exchange(Other.Pos, nullptr)), + End(std::exchange(Other.End, nullptr)), + Size(std::exchange(Other.Size, 0)), + BlockIdx(std::exchange(Other.BlockIdx, 0)), + Alloc(std::move(Other.Alloc)) {} explicit StableVector(const StableVector &Other) : Size(Other.Size), BlockIdx(Other.BlockIdx), @@ -199,33 +201,36 @@ class StableVector { Pos = Blck + (Other.Pos - Other.Start); } - friend void swap(StableVector &LHS, StableVector &RHS) noexcept { - std::swap(LHS.Blocks, RHS.Blocks); - std::swap(LHS.Start, RHS.Start); - std::swap(LHS.Pos, RHS.Pos); - std::swap(LHS.End, RHS.End); - std::swap(LHS.Size, RHS.Size); - std::swap(LHS.BlockIdx, RHS.BlockIdx); + void swap(StableVector &Other) noexcept { + std::swap(Blocks, Other.Blocks); + std::swap(Start, Other.Start); + std::swap(Pos, Other.Pos); + std::swap(End, Other.End); + std::swap(Size, Other.Size); + std::swap(BlockIdx, Other.BlockIdx); if constexpr (std::allocator_traits< allocator_type>::propagate_on_container_swap::value) { - std::swap(LHS.Alloc, RHS.Alloc); + std::swap(Alloc, Other.Alloc); } else { - assert(LHS.Alloc == RHS.Alloc && + assert(Alloc == Other.Alloc && "Do not swap two StableVectors with incompatible " "allocators that do not propagate on swap!"); } } - void swap(StableVector &Other) noexcept { swap(*this, Other); } + friend void swap(StableVector &LHS, StableVector &RHS) noexcept { + LHS.swap(RHS); + } StableVector &operator=(StableVector Other) noexcept { - swap(*this, Other); + swap(Other); return *this; } StableVector &operator=(StableVector &&Other) noexcept { - swap(*this, Other); + auto Cpy = std::move(Other); + swap(Cpy); return *this; } @@ -458,24 +463,16 @@ class StableVector { size_t Total = InitialCapacity; for (size_t I = 0; I < LHS.BlockIdx; ++I) { - for (T *LIt = LHS.Blocks[I], *RIt = RHS.Blocks[I], *LEnd = LIt + Cap; - LIt != LEnd; ++LIt, ++RIt) { - if (*LIt != *RIt) { - return false; - } + auto LIt = LHS.Blocks[I]; + if (!std::equal(LIt, LIt + Cap, RHS.Blocks[I])) { + return false; } Cap = Total; Total <<= 1; } - for (T *LIt = LHS.Start, *RIt = RHS.Start, *LEnd = LHS.Pos; LIt != LEnd; - ++LIt, ++RIt) { - if (*LIt != *RIt) { - return false; - } - } - return true; + return std::equal(LHS.Start, LHS.Pos, RHS.Start); } [[nodiscard]] friend bool operator!=(const StableVector &LHS, @@ -538,13 +535,13 @@ class StableVector { // return Blocks[LogIdx][Offset]; } - llvm::SmallVector Blocks; + llvm::SmallVector Blocks{}; T *Start = nullptr; T *Pos = nullptr; T *End = nullptr; size_t Size = 0; size_t BlockIdx = 0; - [[no_unique_address]] allocator_type Alloc; + [[no_unique_address]] allocator_type Alloc{}; }; // NOLINTEND(readability-identifier-naming) From cc649e4afde4c8613fc731834b41a3d2a7d38689 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 27 Sep 2022 15:32:04 +0200 Subject: [PATCH 23/65] Improve on reverseDAG --- .../PathSensitivityManagerBase.h | 178 ++++++------------ .../PathSensitivityManagerMixin.h | 10 +- include/phasar/Utils/GraphTraits.h | 2 +- include/phasar/Utils/Utilities.h | 29 ++- .../PathSensitivityManagerBase.cpp | 5 + 5 files changed, 92 insertions(+), 132 deletions(-) create mode 100644 lib/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.cpp diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h index 66e9333fde..7765e3b2bd 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h @@ -12,11 +12,16 @@ #include "phasar/Utils/AdjacencyList.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/Utilities.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/IntEqClasses.h" #include "llvm/ADT/SmallVector.h" +namespace llvm { +class Instruction; +} // namespace llvm + namespace psr { template @@ -37,7 +42,7 @@ template class PathSensitivityManagerBase { using vertex_t = typename graph_traits_t::vertex_t; private: - bool assertIsDAG(const graph_type &Dag) const { + [[nodiscard]] bool assertIsDAG(const graph_type &Dag) const { llvm::BitVector Visited(graph_traits_t::size(Dag)); llvm::DenseSet CurrPath; CurrPath.reserve(graph_traits_t::size(Dag)); @@ -77,145 +82,78 @@ template class PathSensitivityManagerBase { return true; } - graph_type reverseDAG(graph_type &&Dag, size_t MaxDepth) const { - struct ReverseDAGContext { - llvm::BitVector Visited; - size_t CurrDepth = 0; - size_t MaxDepth = 0; - } Ctx; - - Ctx.Visited.resize(graph_traits_t::size(Dag)); - Ctx.MaxDepth = MaxDepth; - + template + [[nodiscard]] static graph_type + reverseDAG(graph_type &&Dag, const VertexTransform &Equiv, size_t EquivSize, + size_t MaxDepth) { graph_type Ret{}; - if constexpr (is_reservable_graph_trait_v) { - graph_traits_t::reserve(Ret, graph_traits_t::size(Dag)); + if constexpr (psr::is_reservable_graph_trait_v) { + graph_traits_t::reserve(Ret, EquivSize); } - // NOLINTNEXTLINE(readability-identifier-naming) - auto buildReverseDag = [&Ctx, &Ret, &Dag](auto &buildReverseDag, - vertex_t Vtx) { - if (Ctx.Visited.test(Vtx)) { - return Vtx; - } - - Ctx.Visited.set(Vtx); - - auto Rev = graph_traits_t::addNode( - Ret, std::move(graph_traits_t::node(Dag, Vtx))); - - if (Ctx.CurrDepth >= Ctx.MaxDepth) { - graph_traits_t::addRoot(Ret, Rev); - return Rev; - } - - ++Ctx.CurrDepth; - scope_exit DecreaseDepth = [&Ctx] { --Ctx.CurrDepth; }; + llvm::SmallVector Cache; + Cache.resize(EquivSize, graph_traits_t::Invalid); - for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { - /// NOTE: Depending on the depth of SuccRev, we can still get DAGs - /// deeper than MaxDepth! - /// However, this is not considered harmful as of now - the DAG still - /// does not exceed a particular program-slice which size is fixed - auto SuccRev = - buildReverseDag(buildReverseDag, graph_traits_t::target(Succ)); - graph_traits_t::addEdge(Ret, SuccRev, - graph_traits_t::withEdgeTarget(Succ, Rev)); - } + llvm::SmallVector> WL1, WL2; - if (graph_traits_t::outDegree(Dag, Vtx) == 0) { - graph_traits_t::addRoot(Ret, Rev); - } - - return Rev; - }; + auto *WLConsume = &WL1; + auto *WLInsert = &WL2; for (auto Rt : graph_traits_t::roots(Dag)) { - buildReverseDag(buildReverseDag, Rt); - } - - return Ret; - } - - graph_type reverseDAG(graph_type &&Dag, const llvm::IntEqClasses &Equiv, - size_t MaxDepth) const { - - struct ReverseDAGContext { - llvm::SmallVector Cache; - size_t CurrDepth = 0; - size_t MaxDepth = 0; - } Ctx; - - Ctx.Cache.resize(Equiv.getNumClasses(), graph_traits_t::Invalid); - Ctx.MaxDepth = MaxDepth; - - graph_type Ret{}; - // Ret.Dag = &Dag; - // Ret.Leaf = Equiv[Dag.Root]; - if constexpr (is_reservable_graph_trait_v) { - graph_traits_t::reserve(Ret, Equiv.getNumClasses()); - } - // Ret.Adj.reserve(Equiv.getNumClasses()); - // Ret.Rev2Vtx.reserve(Equiv.getNumClasses()); - - // NOLINTNEXTLINE(readability-identifier-naming) - auto buildReverseDag = [&Ctx, &Ret, &Equiv, &Dag](auto &buildReverseDag, - vertex_t Vtx) { - auto Eq = Equiv[Vtx]; - if (Ctx.Cache[Eq] != graph_traits_t::Invalid) { - return Ctx.Cache[Eq]; + auto Eq = std::invoke(Equiv, Rt); + if (Cache[Eq] == graph_traits_t::Invalid) { + Cache[Eq] = graph_traits_t::addNode( + Ret, std::move(graph_traits_t::node(Dag, Rt))); + WLConsume->emplace_back(Rt, Cache[Eq]); } + } - // typename ReverseDAG::vertex_t Rev = Ret.size(); - // Ret.Rev2Vtx.push_back(Vtx); - // Ret.Adj.emplace_back(); - auto Rev = graph_traits_t::addNode( - Ret, std::move(graph_traits_t::node(Dag, Vtx))); - Ctx.Cache[Eq] = Rev; - - if (Ctx.CurrDepth >= Ctx.MaxDepth) { - // PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", - // "Reached MaxDepth: " << Ctx.CurrDepth); - graph_traits_t::addRoot(Ret, Rev); - // Ret.Roots.push_back(Rev); - return Rev; - } - // else { - // PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", - // "Have not reached MaxDepth: " - // << Ctx.CurrDepth << " vs " << Ctx.MaxDepth); - // } + size_t Depth = 0; - ++Ctx.CurrDepth; - scope_exit DecreaseDepth = [&Ctx] { --Ctx.CurrDepth; }; + while (!WLConsume->empty() && Depth < MaxDepth) { + for (auto [Vtx, Rev] : *WLConsume) { - for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { - /// NOTE: Depending on the depth of SuccRev, we can still get DAGs - /// deeper than MaxDepth! - /// However, this is not considered harmful as of now - the DAG still - /// does not exceed a particular program-slice which size is fixed - auto SuccRev = - buildReverseDag(buildReverseDag, graph_traits_t::target(Succ)); - graph_traits_t::addEdge(Ret, SuccRev, - graph_traits_t::withEdgeTarget(Succ, Rev)); - // Ret.Adj[SuccRev].push_back(Rev); - } + for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { + auto SuccVtx = graph_traits_t::target(Succ); + auto Eq = std::invoke(Equiv, SuccVtx); + if (Cache[Eq] == graph_traits_t::Invalid) { + Cache[Eq] = graph_traits_t::addNode( + Ret, std::move(graph_traits_t::node(Dag, SuccVtx))); + WLInsert->emplace_back(SuccVtx, Cache[Eq]); + } - if (graph_traits_t::outDegree(Dag, Vtx) == 0) { - graph_traits_t::addRoot(Ret, Rev); - // Ret.Roots.push_back(Rev); + auto SuccRev = Cache[Eq]; + graph_traits_t::addEdge(Ret, SuccRev, + graph_traits_t::withEdgeTarget(Succ, Rev)); + } + if (graph_traits_t::outDegree(Dag, Vtx) == 0) { + graph_traits_t::addRoot(Ret, Rev); + } } + WLConsume->clear(); - return Rev; - }; + std::swap(WLConsume, WLInsert); + ++Depth; + } - for (auto Rt : graph_traits_t::roots(Dag)) { - buildReverseDag(buildReverseDag, Rt); + for (auto [Rt, RtRev] : *WLConsume) { + // All nodes that were cut off because they are at depth MaxDepth must + // become roots + graph_traits_t::addRoot(Ret, RtRev); } return Ret; } + + [[nodiscard]] static graph_type reverseDAG(graph_type &&Dag, + size_t MaxDepth) { + auto Sz = graph_traits_t::size(Dag); + return reverseDAG(std::move(Dag), identity{}, Sz, MaxDepth); + } }; + +extern template class PathSensitivityManagerBase; + } // namespace psr #endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index ea2d34c6e6..1d1d13c2b7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -100,11 +100,13 @@ class PathSensitivityManagerMixin { if (Config.MinimizeDAG) { auto Equiv = minimizeGraph(Dag); - Dag = static_cast(this)->reverseDAG( - std::move(Dag), Equiv, Config.DAGDepthThreshold); + Dag = Derived::reverseDAG( + std::move(Dag), [&Equiv](vertex_t Vtx) { return Equiv[Vtx]; }, + Equiv.getNumClasses(), Config.DAGDepthThreshold); + } else if (Config.DAGDepthThreshold != SIZE_MAX) { + Dag = Derived::reverseDAG(std::move(Dag), Config.DAGDepthThreshold); } else { - Dag = static_cast(this)->reverseDAG( - std::move(Dag), Config.DAGDepthThreshold); + Dag = reverseGraph(std::move(Dag)); } return Dag; diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index bac0a3135c..be00b4b84f 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -155,7 +155,7 @@ std::decay_t reverseGraph(GraphTy &&G) } for (auto &Nod : traits_t::nodes(G)) { - traits_t::addNode(Ret, forward_from(Nod)); + traits_t::addNode(Ret, forward_like(Nod)); } for (auto I : traits_t::vertices(G)) { for (auto Child : traits_t::outEdges(G, I)) { diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 1296e019ef..6d5b93a36f 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -259,17 +259,32 @@ auto remove_by_index(Container &Cont, const Indices &Idx) { return remove_by_index(begin(Cont), end(Cont), begin(Idx), end(Idx)); } -/// Similar to std::forward, but takes the info, which of lvalue or rvalue -/// reference to return from Fwd -template -constexpr decltype(auto) forward_from(T &Val) noexcept { // NOLINT - if constexpr (std::is_lvalue_reference_v) { - return static_cast(Val); +/// See https://en.cppreference.com/w/cpp/utility/forward_like +template +[[nodiscard]] constexpr auto &&forward_like(U &&X) noexcept { // NOLINT + // NOLINTNEXTLINE + constexpr bool is_adding_const = std::is_const_v>; + if constexpr (std::is_lvalue_reference_v) { + if constexpr (is_adding_const) { + return std::as_const(X); + } else { + return static_cast(X); + } } else { - return static_cast(Val); + if constexpr (is_adding_const) { + return std::move(std::as_const(X)); + } else { + return std::move(X); // NOLINT + } } } +struct identity { + template decltype(auto) operator()(T &&Val) const noexcept { + return std::forward(Val); + } +}; + } // namespace psr #endif diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.cpp new file mode 100644 index 0000000000..527d876f7f --- /dev/null +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.cpp @@ -0,0 +1,5 @@ +#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" + +namespace psr { +template class PathSensitivityManagerBase; +} // namespace psr From 2b5de395c14ef39352003a370cc164d4ae398c74 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 28 Sep 2022 15:22:12 +0200 Subject: [PATCH 24/65] minor improvements in reverseDAG --- .../PathSensitivityManagerBase.h | 64 ++++++++++++++----- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h index 7765e3b2bd..c9a1dee0da 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h @@ -86,40 +86,70 @@ template class PathSensitivityManagerBase { [[nodiscard]] static graph_type reverseDAG(graph_type &&Dag, const VertexTransform &Equiv, size_t EquivSize, size_t MaxDepth) { + using graph_traits_t = psr::GraphTraits; + using vertex_t = typename graph_traits_t::vertex_t; graph_type Ret{}; if constexpr (psr::is_reservable_graph_trait_v) { graph_traits_t::reserve(Ret, EquivSize); } - llvm::SmallVector Cache; - Cache.resize(EquivSize, graph_traits_t::Invalid); + // Allocate a buffer for the temporary data needed. + // We need: + // - A cache of vertex_t + // - One worklist WLConsume of pair where we read from + // - One worklist WLInsert of same type where we insert to + + // We iterate over the graph in levels. Each level corresponds to the + // distance from a root node. We always have all nodes from a level inside a + // worklist + // -- The level we are processing is in WLConsume, the next level in + // WLInsert. This way, we can stop the process, when we have reached the + // MaxDepth + + auto NumBytes = + (sizeof(vertex_t) + 2 * sizeof(std::pair)) * + EquivSize; + + // For performance reasons, we wish to allocate the buffer on the stack, if + // it is small enough + static constexpr size_t MaxNumBytesInStackBuf = 8192; + + auto *Buf = NumBytes <= MaxNumBytesInStackBuf ? alloca(NumBytes) + : new char[NumBytes]; + std::unique_ptr Owner; + if (NumBytes > MaxNumBytesInStackBuf) { + Owner.reset((char *)Buf); + } - llvm::SmallVector> WL1, WL2; + auto Cache = (vertex_t *)Buf; + std::uninitialized_fill_n(Cache, EquivSize, graph_traits_t::Invalid); - auto *WLConsume = &WL1; - auto *WLInsert = &WL2; + auto *WLConsumeBegin = + (std::pair *)((vertex_t *)Buf + EquivSize); + auto *WLConsumeEnd = WLConsumeBegin; + auto *WLInsertBegin = WLConsumeBegin + EquivSize; + auto *WLInsertEnd = WLInsertBegin; for (auto Rt : graph_traits_t::roots(Dag)) { - auto Eq = std::invoke(Equiv, Rt); + size_t Eq = std::invoke(Equiv, Rt); if (Cache[Eq] == graph_traits_t::Invalid) { - Cache[Eq] = graph_traits_t::addNode( - Ret, std::move(graph_traits_t::node(Dag, Rt))); - WLConsume->emplace_back(Rt, Cache[Eq]); + Cache[Eq] = graph_traits_t::addNode(Ret, graph_traits_t::node(Dag, Rt)); + *WLConsumeEnd++ = {Rt, Cache[Eq]}; } } size_t Depth = 0; - while (!WLConsume->empty() && Depth < MaxDepth) { - for (auto [Vtx, Rev] : *WLConsume) { + while (WLConsumeBegin != WLConsumeEnd && Depth < MaxDepth) { + for (auto [Vtx, Rev] : llvm::make_range(WLConsumeBegin, WLConsumeEnd)) { for (auto Succ : graph_traits_t::outEdges(Dag, Vtx)) { auto SuccVtx = graph_traits_t::target(Succ); - auto Eq = std::invoke(Equiv, SuccVtx); + size_t Eq = std::invoke(Equiv, SuccVtx); if (Cache[Eq] == graph_traits_t::Invalid) { Cache[Eq] = graph_traits_t::addNode( - Ret, std::move(graph_traits_t::node(Dag, SuccVtx))); - WLInsert->emplace_back(SuccVtx, Cache[Eq]); + Ret, graph_traits_t::node(Dag, SuccVtx)); + *WLInsertEnd++ = {SuccVtx, Cache[Eq]}; } auto SuccRev = Cache[Eq]; @@ -130,13 +160,13 @@ template class PathSensitivityManagerBase { graph_traits_t::addRoot(Ret, Rev); } } - WLConsume->clear(); - std::swap(WLConsume, WLInsert); + std::swap(WLConsumeBegin, WLInsertBegin); + WLConsumeEnd = std::exchange(WLInsertEnd, WLInsertBegin); ++Depth; } - for (auto [Rt, RtRev] : *WLConsume) { + for (auto [Rt, RtRev] : llvm::make_range(WLConsumeBegin, WLConsumeEnd)) { // All nodes that were cut off because they are at depth MaxDepth must // become roots graph_traits_t::addRoot(Ret, RtRev); From 86b135baf552b41481dd79e1ebe870c9c841feb3 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 27 Oct 2022 17:26:45 +0200 Subject: [PATCH 25/65] Bump z3 --- external/z3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/z3 b/external/z3 index 2b6a237162..02d0c8667f 160000 --- a/external/z3 +++ b/external/z3 @@ -1 +1 @@ -Subproject commit 2b6a2371620f0ac9d992075733e2152a6d78299e +Subproject commit 02d0c8667fb4366280574daf443a8dbf90516d08 From eb16d3665d7e5590c509845e5042e7f481173841 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 27 Oct 2022 17:37:27 +0200 Subject: [PATCH 26/65] Fix depdendency issue with utils->config --- include/phasar/Utils/Logger.h | 2 ++ include/phasar/Utils/PAMM.h | 7 +++++-- lib/Config/CMakeLists.txt | 4 ++++ lib/Utils/CMakeLists.txt | 4 +--- lib/Utils/PAMM.cpp | 19 ++++++++----------- unittests/Utils/PAMMTest.cpp | 3 ++- 6 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index 07a40291ff..fce730ebdc 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -149,6 +149,8 @@ class Logger final { #else #define IF_LOG_ENABLED_BOOL(condition, computation) ((void)0) +#define IF_LOG_ENABLED(computation) \ + {} #define PHASAR_LOG(computation) ((void)0) #define PHASAR_LOG_CAT(cat, message) ((void)0) #define PHASAR_LOG_LEVEL_CAT(level, cat, message) ((void)0) diff --git a/include/phasar/Utils/PAMM.h b/include/phasar/Utils/PAMM.h index 8a730e0a93..37d0430b7f 100644 --- a/include/phasar/Utils/PAMM.h +++ b/include/phasar/Utils/PAMM.h @@ -17,6 +17,8 @@ #ifndef PHASAR_UTILS_PAMM_H_ #define PHASAR_UTILS_PAMM_H_ +#include "boost/program_options/variables_map.hpp" + #include // high_resolution_clock::time_point, milliseconds #include // set #include // string @@ -25,7 +27,7 @@ namespace llvm { class raw_ostream; -} +} // namespace llvm namespace psr { @@ -188,7 +190,8 @@ class PAMM { /// \brief Exports the measured data to JSON - associated macro: /// EXPORT_MEASURED_DATA(PATH). /// \param OutputPath to exported JSON file. - void exportMeasuredData(std::string OutputPath); + void exportMeasuredData(std::string OutputPath, + boost::program_options::variables_map &VarMap); }; } // namespace psr diff --git a/lib/Config/CMakeLists.txt b/lib/Config/CMakeLists.txt index faf5945e62..f337f28a24 100644 --- a/lib/Config/CMakeLists.txt +++ b/lib/Config/CMakeLists.txt @@ -4,6 +4,10 @@ set(LLVM_LINK_COMPONENTS Support ) +set(PHASAR_LINK_LIBS + phasar_utils +) + if(BUILD_SHARED_LIBS) add_phasar_library(phasar_config SHARED diff --git a/lib/Utils/CMakeLists.txt b/lib/Utils/CMakeLists.txt index eed0a9452c..1ab2cfcf64 100644 --- a/lib/Utils/CMakeLists.txt +++ b/lib/Utils/CMakeLists.txt @@ -6,9 +6,7 @@ if(PHASAR_ENABLE_PAMM STREQUAL "Off" AND NOT PHASAR_BUILD_UNITTESTS) list(REMOVE_ITEM UTILS_SRC ${pamm_src}) endif() -set(PHASAR_LINK_LIBS - phasar_config -) + set(LLVM_LINK_COMPONENTS Core diff --git a/lib/Utils/PAMM.cpp b/lib/Utils/PAMM.cpp index 4abc09553a..8d26f5c96f 100644 --- a/lib/Utils/PAMM.cpp +++ b/lib/Utils/PAMM.cpp @@ -24,7 +24,6 @@ #include "nlohmann/json.hpp" -#include "phasar/Config/Configuration.h" #include "phasar/Utils/PAMM.h" using namespace psr; @@ -274,7 +273,8 @@ void PAMM::printMeasuredData(llvm::raw_ostream &Os) { Os << "\n----- END OF EVALUATION DATA -----\n\n"; } -void PAMM::exportMeasuredData(std::string OutputPath) { +void PAMM::exportMeasuredData(std::string OutputPath, + boost::program_options::variables_map &VarMap) { // json file for holding all data json JsonData; @@ -313,18 +313,15 @@ void PAMM::exportMeasuredData(std::string OutputPath) { // add analysis/project/source file information if available json JInfo; - if (PhasarConfig::VariablesMap().count("project-id")) { - JInfo["Project-ID"] = - PhasarConfig::VariablesMap()["project-id"].as(); + if (VarMap.count("project-id")) { + JInfo["Project-ID"] = VarMap["project-id"].as(); } - if (PhasarConfig::VariablesMap().count("module")) { - JInfo["Module(s)"] = - PhasarConfig::VariablesMap()["module"].as>(); + if (VarMap.count("module")) { + JInfo["Module(s)"] = VarMap["module"].as>(); } - if (PhasarConfig::VariablesMap().count("data-flow-analysis")) { + if (VarMap.count("data-flow-analysis")) { JInfo["Data-flow analysis"] = - PhasarConfig::VariablesMap()["data-flow-analysis"] - .as>(); + VarMap["data-flow-analysis"].as>(); } if (!JInfo.is_null()) { JsonData["Info"] = JInfo; diff --git a/unittests/Utils/PAMMTest.cpp b/unittests/Utils/PAMMTest.cpp index 69180f3339..b51cacca21 100644 --- a/unittests/Utils/PAMMTest.cpp +++ b/unittests/Utils/PAMMTest.cpp @@ -1,4 +1,5 @@ #include "phasar/Utils/PAMM.h" +#include "phasar/Config/Configuration.h" #include "gtest/gtest.h" #include @@ -100,7 +101,7 @@ TEST_F(PAMMTest, HandleJSONOutput) { Pamm.addToHistogram("Test-Set", "2"); Pamm.incCounter("setOpCount", 9); Pamm.stopTimer("timer3"); - Pamm.exportMeasuredData("HandleJSONOutputTest"); + Pamm.exportMeasuredData("HandleJSONOutputTest", PhasarConfig::VariablesMap()); } TEST_F(PAMMTest, DISABLED_PerformanceTimerBasic) { From aaca44f9fba2632dbe51678159afc14a500847ce Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 27 Oct 2022 18:07:40 +0200 Subject: [PATCH 27/65] Fix bugs indiced by reverse merging from development + bump z3 --- external/z3 | 2 +- .../DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h | 2 +- .../PathSensitivity/Z3BasedPathSensitvityManager.h | 4 ++-- .../DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp | 2 +- .../PathSensitivity/Z3BasedPathSensitivityManager.cpp | 2 +- .../DataFlowSolver/PathSensitivity/PathTracingTest.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/external/z3 b/external/z3 index 02d0c8667f..7b64f84b10 160000 --- a/external/z3 +++ b/external/z3 @@ -1 +1 @@ -Subproject commit 02d0c8667fb4366280574daf443a8dbf90516d08 +Subproject commit 7b64f84b10ffb7ac9b5b3ddf5acac53859d0777c diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h index ad92a102ff..e293bdc37a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h @@ -11,8 +11,8 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/Printer.h" -#include "phasar/Utils/LLVMIRToSrc.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/StableVector.h" #include "phasar/Utils/Utilities.h" diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h index e5e74c6a02..adfb1fd65a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -14,9 +14,9 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/GraphTraits.h" -#include "phasar/Utils/LLVMIRToSrc.h" -#include "phasar/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/MaybeUniquePtr.h" diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp index 070ff79d19..f8fad9c502 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp @@ -1,6 +1,6 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" -#include "phasar/Utils/LLVMShorthands.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "llvm/Demangle/Demangle.h" #include "llvm/IR/Instructions.h" diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp index b437fa746e..7dc8ffcaee 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -1,6 +1,6 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h" -#include "phasar/Utils/LLVMShorthands.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp index ba42dd3ced..65330387e9 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp @@ -12,8 +12,8 @@ #include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" #include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/DebugOutput.h" -#include "phasar/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/Utilities.h" From e6556c185ca39efec395fbaa1f8c0465ad475b2b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 27 Oct 2022 18:54:30 +0200 Subject: [PATCH 28/65] Make Z3 optional --- CMakeLists.txt | 62 ++++++++++--------- .../Problems/IDEInstInteractionAnalysis.h | 2 +- lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt | 1 + .../PathSensitivity/CMakeLists.txt | 15 ++++- .../PhasarLLVM/DataFlowSolver/CMakeLists.txt | 1 + .../PathSensitivity/CMakeLists.txt | 14 +++-- 6 files changed, 59 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cc2de5a2e..c71e83024f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,8 @@ option(PHASAR_BUILD_UNITTESTS "Build all tests (default is ON)" ON) option(PHASAR_BUILD_OPENSSL_TS_UNITTESTS "Build OPENSSL typestate tests (require OpenSSL, default is OFF)" OFF) +option(PHASAR_USE_Z3 "Build the phasar_pathsensitivity library with Z3 support for constraint solving (default is ON as long as we are building out of tree)" ON) + option(PHASAR_BUILD_IR "Build IR test code (default is ON)" ON) option(PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD "Run clang-tidy during build (default is OFF)" OFF) @@ -151,6 +153,8 @@ include_directories(external/json/single_include/) if(PHASAR_IN_TREE) set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json_schema_validator) + + set (PHASAR_USE_Z3 OFF) endif() set(nlohmann_json_DIR ${PHASAR_SRC_DIR}/external/json/single_include/) @@ -192,35 +196,37 @@ endif() add_definitions(${LLVM_DEFINITIONS}) # Z3 Solver -if(NOT Z3_FOUND) - # Z3 does not compile with '-Werror', so disable it for Z3's build - # string(REPLACE "-Werror" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - - # Do not pass DebugSan to z3 as it is unable to handle it - if(CMAKE_BUILD_TYPE STREQUAL "DebugSan") - set(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3 ON) - set(CMAKE_BUILD_TYPE "Debug") - endif() - - # Convince z3 to install its library along with phasar libs - # To avoid possible side effects we only change CMAKE_INSTALL_LIBDIR - # for including z3 (here) and restore it afterwards - set(ORIGINAL_CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) - set(CMAKE_INSTALL_LIBDIR ${PHASAR_INSTALL_LIBDIR}) - add_subdirectory(external/z3/) - set(CMAKE_INSTALL_LIBDIR ${ORIGINAL_CMAKE_INSTALL_LIBDIR}) - - if(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3) - set(CMAKE_BUILD_TYPE "DebugSan") +if(PHASAR_USE_Z3) + if(NOT Z3_FOUND) + # Z3 does not compile with '-Werror', so disable it for Z3's build + # string(REPLACE "-Werror" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + + # Do not pass DebugSan to z3 as it is unable to handle it + if(CMAKE_BUILD_TYPE STREQUAL "DebugSan") + set(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3 ON) + set(CMAKE_BUILD_TYPE "Debug") + endif() + + # Convince z3 to install its library along with phasar libs + # To avoid possible side effects we only change CMAKE_INSTALL_LIBDIR + # for including z3 (here) and restore it afterwards + set(ORIGINAL_CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) + set(CMAKE_INSTALL_LIBDIR ${PHASAR_INSTALL_LIBDIR}) + add_subdirectory(external/z3/) + set(CMAKE_INSTALL_LIBDIR ${ORIGINAL_CMAKE_INSTALL_LIBDIR}) + + if(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3) + set(CMAKE_BUILD_TYPE "DebugSan") + endif() + + include_directories(external/z3/src/) + include_directories(external/z3/src/api/) + include_directories(external/z3/src/api/c++/) + link_directories(${Z3_BINARY_DIR}) + + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") endif() - - include_directories(external/z3/src/) - include_directories(external/z3/src/api/) - include_directories(external/z3/src/api/c++/) - link_directories(${Z3_BINARY_DIR}) - - # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") -endif() +endif(PHASAR_USE_Z3) if(NOT PHASAR_IN_TREE) find_library(LLVM_LIBRARY NAMES LLVM PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h index b7efa87244..61d2a73e19 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -1729,7 +1729,7 @@ class IDEInstInteractionAnalysisT // at some point. Therefore, we only care for the variables and their // associated values and ignore at which point a variable may holds as a // data-flow fact. - const auto *Variable = Result.getColumnKey(); + const auto &Variable = Result.getColumnKey(); const auto &Value = Result.getValue(); // skip result entry if variable is not in the set of all variables if (Variables.find(Variable) == Variables.end()) { diff --git a/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt b/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt index 509a22b31b..3af5da4864 100644 --- a/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlowSolver/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(IfdsIde) add_subdirectory(Mono) +add_subdirectory(PathSensitivity) diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt index e24004fc56..3570dbc68f 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt @@ -1,12 +1,18 @@ file(GLOB_RECURSE PATHSENSITIVITY_SRC *.h *.cpp) +if(NOT PHASAR_USE_Z3) + message("Not compiling LLVMPathConstraints.cpp since Z3 is disabled.") + get_filename_component(llvmpathconstraints_src LLVMPathConstraints.cpp ABSOLUTE) + list(REMOVE_ITEM PATHSENSITIVITY_SRC ${llvmpathconstraints_src}) +endif() + set(PHASAR_LINK_LIBS phasar_config phasar_controlflow phasar_utils phasar_phasarllvm_utils phasar_pointer - libz3 + # libz3 ) set(LLVM_LINK_COMPONENTS @@ -26,6 +32,13 @@ else() ) endif() +if(PHASAR_USE_Z3) + target_link_libraries(phasar_pathsensitivity + LINK_PUBLIC + z3 + ) +endif() + set_target_properties(phasar_pathsensitivity PROPERTIES LINKER_LANGUAGE CXX diff --git a/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt b/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt index 509a22b31b..3af5da4864 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlowSolver/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(IfdsIde) add_subdirectory(Mono) +add_subdirectory(PathSensitivity) diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt index 731fee62b0..49b5390d67 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt @@ -1,7 +1,9 @@ -add_phasar_unittest(PathTracingTest.cpp) +if(PHASAR_USE_Z3) + add_phasar_unittest(PathTracingTest.cpp) -target_link_libraries(PathTracingTest - LINK_PUBLIC - phasar_pathsensitivity - z3 -) + target_link_libraries(PathTracingTest + LINK_PUBLIC + phasar_pathsensitivity + z3 + ) +endif() From 77370dfa45e27c6a6837290412137c21bb47443b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 27 Oct 2022 19:40:00 +0200 Subject: [PATCH 29/65] Workaround weird cmake behavior --- .../PathSensitivity/CMakeLists.txt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt index 3570dbc68f..13eb50da2a 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt @@ -1,9 +1,22 @@ file(GLOB_RECURSE PATHSENSITIVITY_SRC *.h *.cpp) if(NOT PHASAR_USE_Z3) - message("Not compiling LLVMPathConstraints.cpp since Z3 is disabled.") - get_filename_component(llvmpathconstraints_src LLVMPathConstraints.cpp ABSOLUTE) - list(REMOVE_ITEM PATHSENSITIVITY_SRC ${llvmpathconstraints_src}) +message("Not compiling LLVMPathConstraints.cpp since Z3 is disabled.") +# get_filename_component(LLVMPathConstraints_src LLVMPathConstraints.cpp ABSOLUTE) +# list(REMOVE_ITEM PATHSENSITIVITY_SRC ${LLVMPathConstraints_src}) + + +get_filename_component(Z3BasedPathSensitvityManager_src Z3BasedPathSensitvityManager.cpp ABSOLUTE) +# message("Not compiling ${Z3BasedPathSensitvityManager_src} since Z3 is disabled.") +# list(REMOVE_ITEM PATHSENSITIVITY_SRC ${Z3BasedPathSensitvityManager_src}) + +# TODO: For whatever reason the list REMOVE_ITEM does not work... + +set(PATHSENSITIVITY_SRC + PathSensitivityManagerBase.cpp +) + +message("Remaining PathSensitivity targets to build: ${PATHSENSITIVITY_SRC}") endif() set(PHASAR_LINK_LIBS From 55086159e08a957db9e3a028398f2c578b9943ac Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 28 Oct 2022 09:19:43 +0200 Subject: [PATCH 30/65] Fix seeds in exploded supergraph --- .../Problems/IDEInstInteractionAnalysis.h | 2 +- .../IfdsIde/Solver/PathAwareIDESolver.h | 3 ++- .../PathSensitivity/ExplodedSuperGraph.h | 19 ++++++++++++--- .../PathSensitivityManagerMixin.h | 22 ++++++++++++++++- .../PathSensitivity/CMakeLists.txt | 24 +++++++++---------- 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h index 61d2a73e19..76ad7aa8cb 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -1579,7 +1579,7 @@ class IDEInstInteractionAnalysisT } void printDataFlowFact(llvm::raw_ostream &OS, d_t FlowFact) const override { - OS << llvmIRToString(FlowFact); + OS << FlowFact; } void printFunction(llvm::raw_ostream &OS, f_t Fun) const override { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h index 3f09cd2743..6b959b72d9 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h @@ -48,7 +48,8 @@ class PathAwareIDESolver : public IDESolver { private: void saveEdges(n_t Curr, n_t Succ, d_t CurrNode, const container_type &SuccNodes, ESGEdgeKind Kind) override { - ESG.saveEdges(Curr, CurrNode, Succ, SuccNodes, Kind); + ESG.saveEdges(std::move(Curr), std::move(CurrNode), std::move(Succ), + SuccNodes, Kind); } ExplodedSuperGraph ESG; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h index e293bdc37a..6954a7a926 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h @@ -36,6 +36,7 @@ #include #include #include +#include namespace psr { @@ -152,10 +153,22 @@ template class ExplodedSuperGraph { auto &SuccVtx = FlowFactVertexMap[std::make_pair(Succ, SuccNode)]; // NOLINTNEXTLINE(readability-identifier-naming) - auto makeNode = [this, Pred, Curr, - SuccNode{std::move(SuccNode)}]() mutable { + auto makeNode = [this, Pred, Curr, Succ, &CurrNode, &SuccNode]() mutable { auto Ret = &NodeOwner.emplace_back(); - Ret->Value = std::move(SuccNode); + Ret->Value = SuccNode; + + if (!Pred) { + // llvm::errs() << "> No Pred at edge " << NPrinter.NtoString(Curr) << + // ", " + // << DPrinter.DtoString(CurrNode) << ") --> (" + // << NPrinter.NtoString(Succ) << ", " + // << DPrinter.DtoString(SuccNode) << ")\n"; + + // For the seeds: Just that the FlowFactVertexMap is filled at that + // position... + FlowFactVertexMap[std::make_pair(Curr, CurrNode)] = Ret; + } + Ret->Predecessor = Pred; Ret->Source = Curr; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index 1d1d13c2b7..7b2045f3b8 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -15,6 +15,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/GraphTraits.h" #include "llvm/ADT/ArrayRef.h" @@ -22,7 +23,10 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" +#include +#include #include namespace psr { @@ -73,6 +77,23 @@ class PathSensitivityManagerMixin { auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); if (!Nod) { + + llvm::errs() << "At Inst " << llvmIRToString(Inst) << "; Fact: " << Fact + << '\n'; + llvm::errs(); + + { + std::error_code EC; + llvm::raw_fd_ostream ROS("explicitesg-err.dot", EC); + ESG.printAsDot(ROS); + } + + llvm::errs() + << "> ESG written to " + << std::filesystem::canonical("explicitesg-err.dot").string() + << '\n'; + llvm::errs().flush(); + llvm::report_fatal_error( "Invalid Instruction-FlowFact pair. Only use those pairs that are " "part of the IDE analysis results!"); @@ -235,7 +256,6 @@ class PathSensitivityManagerMixin { template vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag, PathsToContext &Ctx, const Filter &PFilter) const { - assert(Vtx->Source != QueryInst); auto Ret = graph_traits_t::addNode(RetDag, typename graph_traits_t::value_type()); diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt index 13eb50da2a..1269fbe78a 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt @@ -1,22 +1,20 @@ file(GLOB_RECURSE PATHSENSITIVITY_SRC *.h *.cpp) if(NOT PHASAR_USE_Z3) -message("Not compiling LLVMPathConstraints.cpp since Z3 is disabled.") -# get_filename_component(LLVMPathConstraints_src LLVMPathConstraints.cpp ABSOLUTE) -# list(REMOVE_ITEM PATHSENSITIVITY_SRC ${LLVMPathConstraints_src}) + message("Not compiling LLVMPathConstraints.cpp since Z3 is disabled.") + # get_filename_component(LLVMPathConstraints_src LLVMPathConstraints.cpp ABSOLUTE) + # list(REMOVE_ITEM PATHSENSITIVITY_SRC ${LLVMPathConstraints_src}) + + get_filename_component(Z3BasedPathSensitvityManager_src Z3BasedPathSensitvityManager.cpp ABSOLUTE) + # message("Not compiling ${Z3BasedPathSensitvityManager_src} since Z3 is disabled.") + # list(REMOVE_ITEM PATHSENSITIVITY_SRC ${Z3BasedPathSensitvityManager_src}) -get_filename_component(Z3BasedPathSensitvityManager_src Z3BasedPathSensitvityManager.cpp ABSOLUTE) -# message("Not compiling ${Z3BasedPathSensitvityManager_src} since Z3 is disabled.") -# list(REMOVE_ITEM PATHSENSITIVITY_SRC ${Z3BasedPathSensitvityManager_src}) - -# TODO: For whatever reason the list REMOVE_ITEM does not work... - -set(PATHSENSITIVITY_SRC - PathSensitivityManagerBase.cpp -) + set(PATHSENSITIVITY_SRC + PathSensitivityManagerBase.cpp + ) -message("Remaining PathSensitivity targets to build: ${PATHSENSITIVITY_SRC}") + message("Remaining PathSensitivity targets to build: ${PATHSENSITIVITY_SRC}") endif() set(PHASAR_LINK_LIBS From 82792d9300734915c6c2668110c0a53f343e507f Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 23 Nov 2022 15:15:04 +0100 Subject: [PATCH 31/65] Add forward minimize graph --- include/phasar/Utils/DFAMinimizer.h | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index b2bcd7bd92..904751c38f 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -12,11 +12,65 @@ #include "phasar/Utils/GraphTraits.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/Utilities.h" #include "llvm/ADT/IntEqClasses.h" +#include "llvm/ADT/SmallVector.h" namespace psr { +template +[[nodiscard]] std::decay_t +createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) +#if __cplusplus >= 202002L + requires is_graph +#endif +{ + using traits_t = GraphTraits; + using vertex_t = typename traits_t::vertex_t; + + std::decay_t Ret; + + llvm::SmallVector, 0> Cache(Eq.getNumClasses(), + traits_t::Invalid); + + if constexpr (is_reservable_graph_trait_v) { + traits_t::reserve(Ret, Eq.getNumClasses()); + } + + for (auto Rt : traits_t::roots(G)) { + size_t EqVtx = Eq[Rt]; + if (Cache[EqVtx] != traits_t::Invalid) { + continue; + } + auto EqRt = + traits_t::addNode(Ret, forward_like(traits_t::node(G, Rt))); + + Cache[EqVtx] = {Rt, EqRt}; + traits_t::addRoot(G, EqRt); + } + for (auto Vtx : traits_t::vertices(G)) { + size_t EqVtx = Eq[Vtx]; + if (Cache[EqVtx] != traits_t::Invalid) { + continue; + } + Cache[EqVtx] = {Vtx, traits_t::addNode(Ret, forward_like( + traits_t::node(G, Vtx)))}; + } + + for (auto [Vtx, EqVtx] : Cache) { + assert(Vtx != traits_t::Invalid); + assert(EqVtx != traits_t::Invalid); + for (auto Succ : traits_t::outEdges(G, Vtx)) { + auto EqSucc = Eq[traits_t::target(Succ)]; + traits_t::addEdge(Ret, EqVtx, traits_t::withEdgeTarget(Succ, EqSucc)); + } + traits_t::dedupOutEdges(Ret, EqVtx); + } + + return Ret; +} + template [[nodiscard]] llvm::IntEqClasses minimizeGraph(const GraphTy &G) #if __cplusplus >= 202002L From a9fb9dac565bbbda59e88f5f1f5b3bbc0b0567f0 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 23 Nov 2022 15:39:26 +0100 Subject: [PATCH 32/65] Add one Test for forward minimize DAG --- include/phasar/Utils/DFAMinimizer.h | 10 +++--- .../PathSensitivity/PathTracingTest.cpp | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 904751c38f..43eae1a941 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -31,8 +31,8 @@ createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) std::decay_t Ret; - llvm::SmallVector, 0> Cache(Eq.getNumClasses(), - traits_t::Invalid); + llvm::SmallVector, 0> Cache( + Eq.getNumClasses(), {traits_t::Invalid, traits_t::Invalid}); if constexpr (is_reservable_graph_trait_v) { traits_t::reserve(Ret, Eq.getNumClasses()); @@ -40,18 +40,18 @@ createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) for (auto Rt : traits_t::roots(G)) { size_t EqVtx = Eq[Rt]; - if (Cache[EqVtx] != traits_t::Invalid) { + if (Cache[EqVtx].second != traits_t::Invalid) { continue; } auto EqRt = traits_t::addNode(Ret, forward_like(traits_t::node(G, Rt))); Cache[EqVtx] = {Rt, EqRt}; - traits_t::addRoot(G, EqRt); + traits_t::addRoot(Ret, EqRt); } for (auto Vtx : traits_t::vertices(G)) { size_t EqVtx = Eq[Vtx]; - if (Cache[EqVtx] != traits_t::Invalid) { + if (Cache[EqVtx].second != traits_t::Invalid) { continue; } Cache[EqVtx] = {Vtx, traits_t::addNode(Ret, forward_like( diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp index 65330387e9..8fa19fb161 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp @@ -13,7 +13,10 @@ #include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/AdjacencyList.h" +#include "phasar/Utils/DFAMinimizer.h" #include "phasar/Utils/DebugOutput.h" +#include "phasar/Utils/GraphTraits.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/Utilities.h" @@ -724,6 +727,34 @@ TEST_F(PathTracingTest, Handle_Other_01) { comparePaths(PathsVec, {{0, 1, 6, 7, 8, 9, 10, 12, 13}}); } +TEST(PathsDAGTest, ForwardMinimizeDAGTest) { + psr::AdjacencyList Graph; + using traits_t = psr::GraphTraits; + auto One = traits_t::addNode(Graph, 1); + auto Two = traits_t::addNode(Graph, 2); + auto Three = traits_t::addNode(Graph, 2); + auto Four = traits_t::addNode(Graph, 2); + + traits_t::addRoot(Graph, One); + traits_t::addEdge(Graph, One, Two); + traits_t::addEdge(Graph, One, Three); + traits_t::addEdge(Graph, One, Four); + + auto Eq = psr::minimizeGraph(Graph); + Graph = psr::createEquivalentGraphFrom(std::move(Graph), Eq); + // psr::printGraph(Graph, llvm::outs()); + // llvm::outs() << '\n'; + + EXPECT_EQ(traits_t::size(Graph), 2); + ASSERT_EQ(traits_t::roots_size(Graph), 1); + auto Rt = traits_t::roots(Graph)[0]; + EXPECT_EQ(traits_t::outDegree(Graph, Rt), 1); + EXPECT_NE(traits_t::target(traits_t::outEdges(Graph, Rt)[0]), Rt); + EXPECT_EQ(traits_t::outDegree( + Graph, traits_t::target(traits_t::outEdges(Graph, Rt)[0])), + 0); +} + // main function for the test case int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); From dc2a8d47731b098bff5e00f8e79bd5d02bb36f74 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 24 Nov 2022 11:06:39 +0100 Subject: [PATCH 33/65] Fix in createEquivalentGraphFrom --- .../PathSensitivityManagerMixin.h | 64 +++++++++++++++++-- include/phasar/Utils/DFAMinimizer.h | 3 +- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h index 7b2045f3b8..1c3e241577 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h @@ -16,6 +16,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" #include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/DFAMinimizer.h" #include "phasar/Utils/GraphTraits.h" #include "llvm/ADT/ArrayRef.h" @@ -119,17 +120,68 @@ class PathSensitivityManagerMixin { } #endif - if (Config.MinimizeDAG) { - auto Equiv = minimizeGraph(Dag); - Dag = Derived::reverseDAG( - std::move(Dag), [&Equiv](vertex_t Vtx) { return Equiv[Vtx]; }, - Equiv.getNumClasses(), Config.DAGDepthThreshold); - } else if (Config.DAGDepthThreshold != SIZE_MAX) { + if (Config.DAGDepthThreshold != SIZE_MAX) { Dag = Derived::reverseDAG(std::move(Dag), Config.DAGDepthThreshold); } else { Dag = reverseGraph(std::move(Dag)); } + if (Config.MinimizeDAG) { + // { + // std::error_code EC; + // llvm::raw_fd_ostream ROS("unminimized_graph.dot", EC); + // assert(!EC); + // printGraph(Dag, ROS, "Unminimized DAG", [](const auto &Node) { + // std::string Str; + // llvm::raw_string_ostream StrStr(Str); + // StrStr << "["; + // llvm::interleaveComma(Node, StrStr, [&StrStr](const auto *Inst) { + // StrStr << getMetaDataID(Inst); + // }); + // StrStr << "]"; + // return Str; + // }); + // } + + auto Equiv = minimizeGraph(Dag); + + // llvm::errs() << "Equiv:\n"; + // llvm::errs() << "> Size: " << Equiv.getNumClasses() << '\n'; + // for (size_t i = 0, end = Equiv.getNumClasses(); i < end; ++i) { + // llvm::errs() << "[" << i << "] = " << Equiv[i] << '\n'; + // } + + Dag = createEquivalentGraphFrom(std::move(Dag), Equiv); + // Dag = Derived::reverseDAG( + // std::move(Dag), [&Equiv](vertex_t Vtx) { return Equiv[Vtx]; }, + // Equiv.getNumClasses(), Config.DAGDepthThreshold); + +#ifndef NDEBUG + if (!static_cast(this)->assertIsDAG(Dag)) { + // { + // std::error_code EC; + // llvm::raw_fd_ostream ROS("minimized_graph.dot", EC); + // assert(!EC); + // printGraph(Dag, ROS, "Minimized DAG", [](const auto &Node) { + // std::string Str; + // llvm::raw_string_ostream StrStr(Str); + // StrStr << "["; + // llvm::interleaveComma(Node, StrStr, [&StrStr](const auto *Inst) { + // StrStr << getMetaDataID(Inst); + // }); + // StrStr << "]"; + // return Str; + // }); + // } + + llvm::report_fatal_error("Invariant violated: DAG has a circle in it!"); + } else { + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", + "The DAG indeed has no circles"); + } +#endif + } + return Dag; } diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 43eae1a941..194297004c 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -63,7 +63,8 @@ createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) assert(EqVtx != traits_t::Invalid); for (auto Succ : traits_t::outEdges(G, Vtx)) { auto EqSucc = Eq[traits_t::target(Succ)]; - traits_t::addEdge(Ret, EqVtx, traits_t::withEdgeTarget(Succ, EqSucc)); + traits_t::addEdge(Ret, EqVtx, + traits_t::withEdgeTarget(Succ, Cache[EqSucc].second)); } traits_t::dedupOutEdges(Ret, EqVtx); } From 2de55927a43683a42ec0d6ef1707eda6ea145e13 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 24 Nov 2022 14:54:22 +0100 Subject: [PATCH 34/65] Fix filterOutUnreachableNodes --- .../Z3BasedPathSensitivityManager.cpp | 24 ++++++++++++++++--- .../PathSensitivity/PathTracingTest.cpp | 4 +++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp index 7dc8ffcaee..30e30d6ea0 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp +++ b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -38,8 +38,8 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( } // NOLINTNEXTLINE(readability-identifier-naming) - auto doFilter = [&Ctx, &RevDAG, &LPC](auto &doFilter, - unsigned Vtx) -> z3::expr { + auto doFilter = [&Ctx, &RevDAG, &LPC, Leaf](auto &doFilter, + vertex_t Vtx) -> z3::expr { Ctx.Visited.set(Vtx); z3::expr X = Ctx.True; llvm::ArrayRef PartialPath = graph_traits_t::node(RevDAG, Vtx); @@ -77,6 +77,21 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( auto Sat = Ctx.Solver.check(); if (Sat == z3::check_result::unsat) { + // llvm::errs() << "> Unsat: " << Ctx.Solver.to_smt2() << '\n'; + // llvm::errs() << ">> With X: " << X.to_string() << '\n'; + // llvm::errs() << ">> With Y: " << Y.to_string() << '\n'; + // llvm::errs() << ">> With NodeConstraints[" << Adj + // << "]: " << Ctx.NodeConstraints[Adj].to_string() << + // '\n'; + // if (auto Constr = + // LPC.getConstraintFromEdge(PartialPath.front(), AdjPP.back())) + // { + // llvm::errs() << ">> With EdgeConstraint: " << Constr->to_string() + // << '\n'; + // } else { + // llvm::errs() << ">> Without EdgeConstraint\n"; + // } + Iter = graph_traits_t::removeEdge(RevDAG, Vtx, It); Ctx.Ctr++; } else { @@ -88,7 +103,7 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( } if (graph_traits_t::outDegree(RevDAG, Vtx) == 0) { - return Ctx.NodeConstraints[Vtx] = Vtx == 0 ? X : Ctx.False; + return Ctx.NodeConstraints[Vtx] = Vtx == Leaf ? X : Ctx.False; } if (Ys.empty()) { llvm_unreachable("Adj nonempty and Ys empty is unexpected"); @@ -110,6 +125,7 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( auto Res = doFilter(doFilter, Rt); Ret = Ret || Res; if (Rt != Leaf && RevDAG.Adj[Rt].empty()) { + // llvm::errs() << "> Remove root " << Rt << "\n"; Iter = graph_traits_t::removeRoot(RevDAG, It); } } @@ -517,6 +533,8 @@ auto Z3BasedPathSensitivityManagerBase::filterAndFlattenRevDag( } if (Vtx == Leaf) { + // llvm::errs() << "> Reached Leaf!\n"; + assert(!CurrPath.empty() && "Reported paths must not be empty!"); /// Reached the end diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp index 8fa19fb161..d61bc16136 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp @@ -172,7 +172,9 @@ class PathTracingTest : public ::testing::Test { for (const auto > : GroundTruth) { EXPECT_TRUE(Matches(GT)) - << "No match found for " << psr::PrettyPrinter{GT}; + << "No match found for " << psr::PrettyPrinter{GT} + << "; MatchingIndices.size() = " << MatchingIndices.size() + << "; AnalyzedPaths.size() = " << AnalyzedPaths.size(); } EXPECT_EQ(MatchingIndices.size(), AnalyzedPaths.size()); From 6a5a777baa9afe2667b07186b0188f5014538bdd Mon Sep 17 00:00:00 2001 From: Fabian Benedikt Schiebel Date: Fri, 6 Jan 2023 16:30:54 +0100 Subject: [PATCH 35/65] Fix: DFAMinimizer edge comparison --- include/phasar/Utils/DFAMinimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 194297004c..8c98a45b5d 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -141,7 +141,7 @@ template bool Eq = true; for (auto [LSucc, RSucc] : llvm::zip(traits_t::outEdges(G, LHS), traits_t::outEdges(G, RHS))) { - if (!isEquivalent(traits_t::target(LSucc), traits_t::target(RSucc))) { + if (!isEquivalent(LSucc, RSucc)) { Eq = false; break; } From a68886a44daabf4cdc0ec813f2e2a430d015911a Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 10 Jan 2023 10:24:27 +0100 Subject: [PATCH 36/65] Fix compilation on ubuntu22 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c71e83024f..da1de416da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,7 @@ if(PHASAR_USE_Z3) include_directories(external/z3/src/api/) include_directories(external/z3/src/api/c++/) link_directories(${Z3_BINARY_DIR}) + link_directories(${Z3_BINARY_DIR}/src) # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") endif() From 7d5f9ed2bde9e42ae77d5f1ab5c6e15ecb1c14f2 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 10 Jan 2023 10:31:42 +0100 Subject: [PATCH 37/65] Improve createEquivalentGraphFrom --- include/phasar/Utils/DFAMinimizer.h | 65 +++++++++++++++++------------ 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 8c98a45b5d..1509d7103b 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -15,6 +15,7 @@ #include "phasar/Utils/Utilities.h" #include "llvm/ADT/IntEqClasses.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" namespace psr { @@ -23,7 +24,7 @@ template [[nodiscard]] std::decay_t createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) #if __cplusplus >= 202002L - requires is_graph + requires is_graph #endif { using traits_t = GraphTraits; @@ -31,42 +32,52 @@ createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) std::decay_t Ret; - llvm::SmallVector, 0> Cache( - Eq.getNumClasses(), {traits_t::Invalid, traits_t::Invalid}); + llvm::SmallBitVector Handled(traits_t::size(G)); + llvm::SmallVector Eq2Vtx(Eq.getNumClasses(), traits_t::Invalid); + llvm::SmallVector WorkList; if constexpr (is_reservable_graph_trait_v) { traits_t::reserve(Ret, Eq.getNumClasses()); } for (auto Rt : traits_t::roots(G)) { - size_t EqVtx = Eq[Rt]; - if (Cache[EqVtx].second != traits_t::Invalid) { - continue; - } - auto EqRt = - traits_t::addNode(Ret, forward_like(traits_t::node(G, Rt))); + auto EqRt = Eq[Rt]; - Cache[EqVtx] = {Rt, EqRt}; - traits_t::addRoot(Ret, EqRt); - } - for (auto Vtx : traits_t::vertices(G)) { - size_t EqVtx = Eq[Vtx]; - if (Cache[EqVtx].second != traits_t::Invalid) { - continue; + if (Eq2Vtx[EqRt] == traits_t::Invalid) { + auto NwRt = + traits_t::addNode(Ret, forward_like(traits_t::node(G, Rt))); + Eq2Vtx[EqRt] = NwRt; + traits_t::addRoot(Ret, NwRt); } - Cache[EqVtx] = {Vtx, traits_t::addNode(Ret, forward_like( - traits_t::node(G, Vtx)))}; + WorkList.push_back(Rt); } - for (auto [Vtx, EqVtx] : Cache) { - assert(Vtx != traits_t::Invalid); - assert(EqVtx != traits_t::Invalid); - for (auto Succ : traits_t::outEdges(G, Vtx)) { - auto EqSucc = Eq[traits_t::target(Succ)]; - traits_t::addEdge(Ret, EqVtx, - traits_t::withEdgeTarget(Succ, Cache[EqSucc].second)); + while (!WorkList.empty()) { + auto Vtx = WorkList.pop_back_val(); + auto EqVtx = Eq[Vtx]; + + auto NwVtx = Eq2Vtx[EqVtx]; + assert(NwVtx != traits_t::Invalid); + + Handled.set(Vtx); + + for (const auto &Edge : traits_t::outEdges(G, Vtx)) { + auto Target = traits_t::target(Edge); + auto EqTarget = Eq[Target]; + if (Eq2Vtx[EqTarget] == traits_t::Invalid) { + Eq2Vtx[EqTarget] = traits_t::addNode( + Ret, forward_like(traits_t::node(G, Target))); + } + if (!Handled.test(Target)) { + WorkList.push_back(Target); + } + auto NwTarget = Eq2Vtx[EqTarget]; + traits_t::addEdge(Ret, NwVtx, traits_t::withEdgeTarget(Edge, NwTarget)); } - traits_t::dedupOutEdges(Ret, EqVtx); + } + + for (auto Vtx : traits_t::vertices(Ret)) { + traits_t::dedupOutEdges(Ret, Vtx); } return Ret; @@ -75,7 +86,7 @@ createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) template [[nodiscard]] llvm::IntEqClasses minimizeGraph(const GraphTy &G) #if __cplusplus >= 202002L - requires is_graph + requires is_graph #endif { From 96caeac689de7db5801df6e6c7312fc099594f63 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 3 Mar 2023 17:06:47 +0100 Subject: [PATCH 38/65] Resolve errors due to merging --- .gitignore | 1 + CMakeLists.txt | 2 +- .../IfdsIde/Solver/PathAwareIDESolver.h | 15 +++-- .../PathSensitivity/ExplodedSuperGraph.h | 8 ++- .../PathSensitivity/FlowPath.h | 0 .../PathSensitivity/PathSensitivityConfig.h | 0 .../PathSensitivity/PathSensitivityManager.h | 8 +-- .../PathSensitivityManagerBase.h | 0 .../PathSensitivityManagerMixin.h | 18 ++--- .../PathSensitivity/PathTracingFilter.h | 0 .../PathSensitivity/LLVMPathConstraints.h | 0 .../Z3BasedPathSensitivityConfig.h | 2 +- .../Z3BasedPathSensitvityManager.h | 11 ++-- include/phasar/Utils/MaybeUniquePtr.h | 16 ++--- .../PathSensitivity/CMakeLists.txt | 12 ++-- .../PathSensitivity/LLVMPathConstraints.cpp | 3 +- .../PathSensitivityManagerBase.cpp | 2 +- .../Z3BasedPathSensitivityManager.cpp | 5 +- .../phasasr_pathsensitivity-config.cmake | 25 ------- .../PathSensitivity/CMakeLists.txt | 2 +- .../PathSensitivity/PathTracingTest.cpp | 65 +++++++++---------- 21 files changed, 87 insertions(+), 108 deletions(-) rename include/phasar/{PhasarLLVM/DataFlowSolver => DataFlow}/PathSensitivity/ExplodedSuperGraph.h (97%) rename include/phasar/{PhasarLLVM/DataFlowSolver => DataFlow}/PathSensitivity/FlowPath.h (100%) rename include/phasar/{PhasarLLVM/DataFlowSolver => DataFlow}/PathSensitivity/PathSensitivityConfig.h (100%) rename include/phasar/{PhasarLLVM/DataFlowSolver => DataFlow}/PathSensitivity/PathSensitivityManager.h (84%) rename include/phasar/{PhasarLLVM/DataFlowSolver => DataFlow}/PathSensitivity/PathSensitivityManagerBase.h (100%) rename include/phasar/{PhasarLLVM/DataFlowSolver => DataFlow}/PathSensitivity/PathSensitivityManagerMixin.h (94%) rename include/phasar/{PhasarLLVM/DataFlowSolver => DataFlow}/PathSensitivity/PathTracingFilter.h (100%) rename include/phasar/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/LLVMPathConstraints.h (100%) rename include/phasar/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/Z3BasedPathSensitivityConfig.h (94%) rename include/phasar/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/Z3BasedPathSensitvityManager.h (93%) rename lib/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/CMakeLists.txt (80%) rename lib/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/LLVMPathConstraints.cpp (99%) rename lib/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/PathSensitivityManagerBase.cpp (54%) rename lib/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/Z3BasedPathSensitivityManager.cpp (99%) delete mode 100644 lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake rename unittests/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/CMakeLists.txt (80%) rename unittests/PhasarLLVM/{DataFlowSolver => DataFlow}/PathSensitivity/PathTracingTest.cpp (94%) diff --git a/.gitignore b/.gitignore index f175263c3d..1cc71e4737 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ bin/* # build directories for cmake build/ build_*/ +build-*/ # LLVM project llvm-project/* diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e97d9a82d..76ac820e7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ endif(BUILD_SWIFT_TESTS) option(PHASAR_BUILD_OPENSSL_TS_UNITTESTS "Build OPENSSL typestate tests (require OpenSSL, default is OFF)" OFF) -option(PHASAR_USE_Z3 "Build the phasar_pathsensitivity library with Z3 support for constraint solving (default is ON as long as we are building out of tree)" ON) +option(PHASAR_USE_Z3 "Build the phasar_llvm_pathsensitivity library with Z3 support for constraint solving (default is ON as long as we are building out of tree)" ON) option(PHASAR_BUILD_IR "Build IR test code (default is ON)" ON) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h index 6b959b72d9..cbb72d6720 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h @@ -10,27 +10,28 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h" +#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h" #include "phasar/Utils/Logger.h" namespace psr { template > class PathAwareIDESolver : public IDESolver { - using base_t = IDESolver; + using base_t = IDESolver; public: using domain_t = AnalysisDomainTy; using n_t = typename base_t::n_t; using d_t = typename base_t::d_t; + using i_t = typename base_t::i_t; using container_type = typename base_t::container_type; explicit PathAwareIDESolver( - IDETabulationProblem &Problem) - : base_t(Problem), ESG(Problem.getZeroValue(), Problem, Problem) { + IDETabulationProblem &Problem, const i_t *ICF) + : base_t(Problem, ICF), ESG(Problem.getZeroValue(), Problem, Problem) { if (Problem.getIFDSIDESolverConfig().autoAddZero()) { PHASAR_LOG_LEVEL( diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h similarity index 97% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h rename to include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index 6954a7a926..3e8c8feb12 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -10,10 +10,9 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/ESGEdgeKind.h" -#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" -#include "phasar/PhasarLLVM/Utils/Printer.h" +#include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/Printer.h" #include "phasar/Utils/StableVector.h" #include "phasar/Utils/Utilities.h" @@ -38,6 +37,9 @@ #include #include +/// TODO: Keep an eye on memory_resource here! it is still not supported on some +/// MAC systems + namespace psr { /// An explicit representation of the ExplodedSuperGraph (ESG) of an IFDS/IDE diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h b/include/phasar/DataFlow/PathSensitivity/FlowPath.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h rename to include/phasar/DataFlow/PathSensitivity/FlowPath.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h rename to include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h similarity index 84% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h rename to include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h index d21982d1f6..7f840bff43 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h @@ -10,10 +10,10 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" +#include "phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h" #include "phasar/Utils/AdjacencyList.h" #include "phasar/Utils/DFAMinimizer.h" #include "phasar/Utils/GraphTraits.h" diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h rename to include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h similarity index 94% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h rename to include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index 1c3e241577..8d785057de 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -10,12 +10,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/ExplodedSuperGraph.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/DataFlow/PathSensitivity/PathTracingFilter.h" #include "phasar/Utils/DFAMinimizer.h" #include "phasar/Utils/GraphTraits.h" @@ -79,9 +78,10 @@ class PathSensitivityManagerMixin { if (!Nod) { - llvm::errs() << "At Inst " << llvmIRToString(Inst) << "; Fact: " << Fact - << '\n'; - llvm::errs(); + // llvm::errs() << "At Inst " << llvmIRToString(Inst) << "; Fact: " << + // Fact + // << '\n'; + // llvm::errs(); { std::error_code EC; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingFilter.h rename to include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h rename to include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h similarity index 94% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h rename to include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h index fc7a79ec28..03f2ffd00a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityConfig.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" #include "z3++.h" diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h rename to include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h index adfb1fd65a..fd18841a1d 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -10,10 +10,10 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerMixin.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" +#include "phasar/DataFlow/PathSensitivity/FlowPath.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h" +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h" #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/GraphTraits.h" @@ -176,7 +176,8 @@ class Z3BasedPathSensitivityManager private: Z3BasedPathSensitivityConfig Config{}; - MaybeUniquePtr LPC{}; + /// FIXME: Not using 'mutable' here + mutable MaybeUniquePtr LPC{}; }; } // namespace psr diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index 8ede53f60d..639012ed8c 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -151,30 +151,30 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { return Data.getInt() && Data.getPointer(); } - constexpr friend bool operator==(const MaybeUniquePtr &LHS, - const MaybeUniquePtr &RHS) noexcept { + constexpr friend bool operator==(const MaybeUniquePtr &LHS, + const MaybeUniquePtr &RHS) noexcept { return LHS.Data.getPointer() == RHS.Data.getPointer(); } - constexpr friend bool operator!=(const MaybeUniquePtr &LHS, - const MaybeUniquePtr &RHS) noexcept { + constexpr friend bool operator!=(const MaybeUniquePtr &LHS, + const MaybeUniquePtr &RHS) noexcept { return !(LHS == RHS); } - constexpr friend bool operator==(const MaybeUniquePtr &LHS, + constexpr friend bool operator==(const MaybeUniquePtr &LHS, const T *RHS) noexcept { return LHS.Data.getPointer() == RHS; } - constexpr friend bool operator!=(const MaybeUniquePtr &LHS, + constexpr friend bool operator!=(const MaybeUniquePtr &LHS, const T *RHS) noexcept { return !(LHS == RHS); } constexpr friend bool operator==(const T *LHS, - const MaybeUniquePtr &RHS) noexcept { + const MaybeUniquePtr &RHS) noexcept { return LHS == RHS.Data.getPointer(); } constexpr friend bool operator!=(const T *LHS, - const MaybeUniquePtr &RHS) noexcept { + const MaybeUniquePtr &RHS) noexcept { return !(LHS == RHS); } diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt similarity index 80% rename from lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt rename to lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index 1269fbe78a..010c313485 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -20,9 +20,11 @@ endif() set(PHASAR_LINK_LIBS phasar_config phasar_controlflow + phasar_llvm_controlflow phasar_utils - phasar_phasarllvm_utils + phasar_llvm_utils phasar_pointer + phasar_llvm_pointer # libz3 ) @@ -32,25 +34,25 @@ set(LLVM_LINK_COMPONENTS ) if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_pathsensitivity + add_phasar_library(phasar_llvm_pathsensitivity SHARED ${PATHSENSITIVITY_SRC} ) else() - add_phasar_library(phasar_pathsensitivity + add_phasar_library(phasar_llvm_pathsensitivity STATIC ${PATHSENSITIVITY_SRC} ) endif() if(PHASAR_USE_Z3) - target_link_libraries(phasar_pathsensitivity + target_link_libraries(phasar_llvm_pathsensitivity LINK_PUBLIC z3 ) endif() -set_target_properties(phasar_pathsensitivity +set_target_properties(phasar_llvm_pathsensitivity PROPERTIES LINKER_LANGUAGE CXX PREFIX "lib" diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp similarity index 99% rename from lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp rename to lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp index f8fad9c502..113c35b0d8 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.cpp +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp @@ -1,4 +1,5 @@ -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h" + #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/PathSensitivityManagerBase.cpp similarity index 54% rename from lib/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.cpp rename to lib/PhasarLLVM/DataFlow/PathSensitivity/PathSensitivityManagerBase.cpp index 527d876f7f..413e95f2da 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.cpp +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/PathSensitivityManagerBase.cpp @@ -1,4 +1,4 @@ -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManagerBase.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h" namespace psr { template class PathSensitivityManagerBase; diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp similarity index 99% rename from lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp rename to lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp index 30e30d6ea0..4c952589a1 100644 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityManager.cpp +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -1,7 +1,8 @@ -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h" +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h" +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" + #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/Casting.h" diff --git a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake b/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake deleted file mode 100644 index 8b684505bb..0000000000 --- a/lib/PhasarLLVM/DataFlowSolver/PathSensitivity/phasasr_pathsensitivity-config.cmake +++ /dev/null @@ -1,25 +0,0 @@ -set(PHASAR_pathsensitivity_COMPONENT_FOUND 1) - - -list(APPEND - PHASAR_PATHSENSITIVITY_DEPS - utils -) - -foreach(dep ${PHASAR_PATHSENSITIVITY_DEPS}) - message("dsear " ${dep}) - list(APPEND - PHASAR_NEEDED_LIBS - phasar::phasar_${dep} - ) - if(NOT (${PHASAR_${dep}_COMPONENT_FOUND})) - find_package(phasar COMPONENTS ${dep}) - endif() -endforeach() - -find_package(Z3 PATHS ${phasar_DIR}/../../phasar/cmake/z3 NO_DEFAULT_PATH REQUIRED) - -list(APPEND - PHASAR_NEEDED_LIBS - phasar::phasar_pathsensitivity -) diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt similarity index 80% rename from unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt rename to unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index 49b5390d67..ac70e1b3ea 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -3,7 +3,7 @@ if(PHASAR_USE_Z3) target_link_libraries(PathTracingTest LINK_PUBLIC - phasar_pathsensitivity + phasar_llvm_pathsensitivity z3 ) endif() diff --git a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp similarity index 94% rename from unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp rename to unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp index d61bc16136..8add6a0921 100644 --- a/unittests/PhasarLLVM/DataFlowSolver/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp @@ -1,16 +1,16 @@ -#include "phasar/DB/ProjectIRDB.h" +#include "phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h" +#include "phasar/DataFlow/PathSensitivity/FlowPath.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManager.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathAwareIDESolver.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/FlowPath.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/LLVMPathConstraints.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/PathSensitivityManager.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitivityConfig.h" -#include "phasar/PhasarLLVM/DataFlowSolver/PathSensitivity/Z3BasedPathSensitvityManager.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h" +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h" +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h" #include "phasar/PhasarLLVM/Passes/ValueAnnotationPass.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/AdjacencyList.h" @@ -20,10 +20,6 @@ #include "phasar/Utils/Logger.h" #include "phasar/Utils/Utilities.h" -#include "gtest/gtest.h" - -#include "TestConfig.h" - #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instruction.h" @@ -31,6 +27,9 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include "TestConfig.h" +#include "gtest/gtest.h" + #include #include #include @@ -41,10 +40,9 @@ // ============== TEST FIXTURE ============== // class PathTracingTest : public ::testing::Test { protected: - const std::string PathToLlFiles = - psr::unittest::PathToLLTestFiles + "path_tracing/"; + static constexpr auto PathToLlFiles = PHASAR_BUILD_SUBFOLDER("path_tracing/"); - std::unique_ptr IRDB; + std::unique_ptr IRDB; psr::LLVMPathConstraints LPC; void SetUp() override { psr::ValueAnnotationPass::resetValueID(); } @@ -75,16 +73,14 @@ class PathTracingTest : public ::testing::Test { psr::FlowPathSequence doAnalysis(const std::string &LlvmFilePath, bool PrintDump = false) { - auto IrFiles = {PathToLlFiles + LlvmFilePath}; - IRDB = std::make_unique(IrFiles, psr::IRDBOptions::WPA); + IRDB = std::make_unique(PathToLlFiles + LlvmFilePath); psr::LLVMTypeHierarchy TH(*IRDB); - psr::LLVMPointsToSet PT(*IRDB); - psr::LLVMBasedICFG ICFG(*IRDB, psr::CallGraphAnalysisType::OTF, {"main"}, - &TH, &PT, psr::Soundness::Soundy, + psr::LLVMAliasSet PT(IRDB.get()); + psr::LLVMBasedICFG ICFG(IRDB.get(), psr::CallGraphAnalysisType::OTF, + {"main"}, &TH, &PT, psr::Soundness::Soundy, /*IncludeGlobals*/ false); - psr::IDELinearConstantAnalysis LCAProblem(IRDB.get(), &TH, &ICFG, &PT, - {"main"}); - psr::PathAwareIDESolver LCASolver(LCAProblem); + psr::IDELinearConstantAnalysis LCAProblem(IRDB.get(), &ICFG, {"main"}); + psr::PathAwareIDESolver LCASolver(LCAProblem, &ICFG); LCASolver.solve(); if (PrintDump) { // IRDB->print(); @@ -109,18 +105,17 @@ class PathTracingTest : public ::testing::Test { psr::FlowPathSequence doLambdaAnalysis(const std::string &LlvmFilePath, size_t MaxDAGDepth = SIZE_MAX) { - auto IrFiles = {PathToLlFiles + LlvmFilePath}; - IRDB = std::make_unique(IrFiles, psr::IRDBOptions::WPA); + IRDB = std::make_unique(PathToLlFiles + LlvmFilePath); psr::LLVMTypeHierarchy TH(*IRDB); - psr::LLVMPointsToSet PT(*IRDB); - psr::LLVMBasedICFG ICFG(*IRDB, psr::CallGraphAnalysisType::OTF, {"main"}, - &TH, &PT, psr::Soundness::Soundy, + psr::LLVMAliasSet PT(IRDB.get()); + psr::LLVMBasedICFG ICFG(IRDB.get(), psr::CallGraphAnalysisType::OTF, + {"main"}, &TH, &PT, psr::Soundness::Soundy, /*IncludeGlobals*/ false); - psr::TaintConfig Config(*IRDB, nlohmann::json{}); - psr::IDEExtendedTaintAnalysis<3, false> Analysis(IRDB.get(), &TH, &ICFG, - &PT, Config, {"main"}); - psr::PathAwareIDESolver Solver(Analysis); + psr::LLVMTaintConfig Config(*IRDB, nlohmann::json{}); + psr::IDEExtendedTaintAnalysis<3, false> Analysis(IRDB.get(), &ICFG, &PT, + Config, {"main"}); + psr::PathAwareIDESolver Solver(Analysis, &ICFG); Solver.solve(); auto *Main = IRDB->getFunctionDefinition("main"); From 327aa9788a38044b1a1a139453ea2f613bda1205 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 16 Mar 2023 16:11:46 +0100 Subject: [PATCH 39/65] Fix z3 dependency --- .../DataFlow/PathSensitivity/CMakeLists.txt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index 010c313485..f9552e2071 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -25,9 +25,12 @@ set(PHASAR_LINK_LIBS phasar_llvm_utils phasar_pointer phasar_llvm_pointer - # libz3 ) +if(PHASAR_USE_Z3) + list(APPEND PHASAR_LINK_LIBS z3) +endif() + set(LLVM_LINK_COMPONENTS Core Support @@ -45,13 +48,6 @@ else() ) endif() -if(PHASAR_USE_Z3) - target_link_libraries(phasar_llvm_pathsensitivity - LINK_PUBLIC - z3 - ) -endif() - set_target_properties(phasar_llvm_pathsensitivity PROPERTIES LINKER_LANGUAGE CXX From fa1f2430689bb53e68ff517292e042cc789caa5c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 17 Mar 2023 13:25:44 +0100 Subject: [PATCH 40/65] Fix UAF when copying an ExplicitESG --- .../PathSensitivity/ExplodedSuperGraph.h | 268 ++++++++++++++---- .../PathSensitivityManagerMixin.h | 60 ++-- .../PathSensitivity/PathTracingFilter.h | 15 +- .../Z3BasedPathSensitvityManager.h | 2 + .../DataFlow/PathSensitivity/CMakeLists.txt | 2 +- .../DataFlow/PathSensitivity/CMakeLists.txt | 2 +- .../PathSensitivity/PathTracingTest.cpp | 23 +- 7 files changed, 281 insertions(+), 91 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index 3e8c8feb12..8b6c4d4f70 100644 --- a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -11,12 +11,15 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H #include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h" +#include "phasar/Utils/ByRef.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/Printer.h" #include "phasar/Utils/StableVector.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/iterator_range.h" @@ -27,9 +30,10 @@ #include "llvm/Support/raw_os_ostream.h" #include "llvm/Support/raw_ostream.h" +#include #include -#include #include +#include #include #include #include @@ -37,6 +41,8 @@ #include #include +#include + /// TODO: Keep an eye on memory_resource here! it is still not supported on some /// MAC systems @@ -54,10 +60,129 @@ template class ExplodedSuperGraph { using d_t = typename AnalysisDomainTy::d_t; struct Node { + static constexpr size_t NoPredId = ~size_t(0); + }; + + struct NodeData { d_t Value{}; n_t Source{}; - Node *Predecessor = nullptr; - llvm::TinyPtrVector Neighbors{}; + }; + + struct NodeAdj { + size_t PredecessorIdx = Node::NoPredId; + llvm::SmallVector Neighbors{}; + }; + + class BuildNodeRef; + class NodeRef { + friend ExplodedSuperGraph; + friend class BuildNodeRef; + + public: + NodeRef() noexcept = default; + NodeRef(std::nullptr_t) noexcept {} + + [[nodiscard]] ByConstRef value() const noexcept { + assert(*this); + return Owner->NodeDataOwner[NodeId].Value; + } + + [[nodiscard]] ByConstRef source() const noexcept { + assert(*this); + return Owner->NodeDataOwner[NodeId].Source; + } + + [[nodiscard]] NodeRef predecessor() const noexcept { + assert(*this); + auto PredId = Owner->NodeAdjOwner[NodeId].PredecessorIdx; + return PredId == Node::NoPredId ? NodeRef() : NodeRef(PredId, Owner); + } + + [[nodiscard]] bool hasNeighbors() const noexcept { + assert(*this); + return !Owner->NodeAdjOwner[NodeId].Neighbors.empty(); + } + + [[nodiscard]] bool getNumNeighbors() const noexcept { + assert(*this); + return Owner->NodeAdjOwner[NodeId].Neighbors.size(); + } + + [[nodiscard]] auto neighbors() const noexcept { + assert(*this); + + return llvm::map_range(Owner->NodeAdjOwner[NodeId].Neighbors, + [Owner{Owner}](size_t NBIdx) { + assert(NBIdx != Node::NoPredId); + return NodeRef(NBIdx, Owner); + }); + } + + [[nodiscard]] size_t id() const noexcept { return NodeId; } + + explicit operator bool() const noexcept { + return Owner != nullptr && NodeId != Node::NoPredId; + } + + [[nodiscard]] friend bool operator==(NodeRef L, NodeRef R) noexcept { + return L.NodeId == R.NodeId && L.Owner == R.Owner; + } + [[nodiscard]] friend bool operator!=(NodeRef L, NodeRef R) noexcept { + return !(L == R); + } + [[nodiscard]] friend bool operator==(NodeRef L, + std::nullptr_t /*R*/) noexcept { + return L.Owner == nullptr; + } + [[nodiscard]] friend bool operator!=(NodeRef L, std::nullptr_t R) noexcept { + return !(L == R); + } + + friend llvm::hash_code hash_value(NodeRef NR) noexcept { // NOLINT + return llvm::hash_combine(NR.NodeId, NR.Owner); + } + + struct DSI { + [[nodiscard]] static NodeRef getEmptyKey() noexcept { + return NodeRef( + Node::NoPredId, + llvm::DenseMapInfo::getEmptyKey()); + } + + [[nodiscard]] static NodeRef getTombstoneKey() noexcept { + return NodeRef( + Node::NoPredId, + llvm::DenseMapInfo::getTombstoneKey()); + } + + [[nodiscard]] static auto getHashValue(NodeRef NR) noexcept { + return hash_value(NR); + } + + [[nodiscard]] static bool isEqual(NodeRef L, NodeRef R) noexcept { + return L == R; + } + }; + + private: + explicit NodeRef(size_t NodeId, const ExplodedSuperGraph *Owner) noexcept + : NodeId(NodeId), Owner(Owner) {} + + size_t NodeId = Node::NoPredId; + const ExplodedSuperGraph *Owner{}; + }; + + class BuildNodeRef { + public: + [[nodiscard]] NodeRef operator()(size_t NodeId) const noexcept { + return NodeRef(NodeId, Owner); + } + + private: + explicit BuildNodeRef(const ExplodedSuperGraph *Owner) noexcept + : Owner(Owner) {} + + const ExplodedSuperGraph *Owner{}; }; explicit ExplodedSuperGraph( @@ -67,11 +192,14 @@ template class ExplodedSuperGraph { : ZeroValue(std::move(ZeroValue)), NPrinter(NPrinter), DPrinter(DPrinter) {} - [[nodiscard]] Node *getNodeOrNull(n_t Inst, d_t Fact) const { + explicit ExplodedSuperGraph(const ExplodedSuperGraph &) = default; + ExplodedSuperGraph(ExplodedSuperGraph &&) noexcept = default; + + [[nodiscard]] NodeRef getNodeOrNull(n_t Inst, d_t Fact) const { auto It = FlowFactVertexMap.find( std::make_pair(std::move(Inst), std::move(Fact))); if (It != FlowFactVertexMap.end()) { - return It->second; + return NodeRef(It->second, this); } return nullptr; } @@ -81,7 +209,7 @@ template class ExplodedSuperGraph { template void saveEdges(n_t Curr, d_t CurrNode, n_t Succ, const Container &SuccNodes, ESGEdgeKind Kind) { - auto Pred = getNodeOrNull(Curr, std::move(CurrNode)); + auto PredId = getNodeIdOrNull(Curr, std::move(CurrNode)); /// The Identity CTR-flow on the zero-value has no meaning at all regarding /// path sensitivity, so skip it @@ -90,36 +218,50 @@ template class ExplodedSuperGraph { if (MaySkipEdge && SuccNode == CurrNode) { continue; } - saveEdge(Pred, Curr, CurrNode, Succ, SuccNode); + saveEdge(PredId, Curr, CurrNode, Succ, SuccNode); } } // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] auto node_begin() const noexcept { return NodeOwner.cbegin(); } + [[nodiscard]] auto node_begin() const noexcept { + assert(NodeAdjOwner.size() == NodeDataOwner.size()); + return llvm::map_iterator( + llvm::seq(size_t(0), NodeDataOwner.size()).begin(), BuildNodeRef(this)); + } // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] auto node_end() const noexcept { return NodeOwner.cend(); } + [[nodiscard]] auto node_end() const noexcept { + assert(NodeAdjOwner.size() == NodeDataOwner.size()); + return llvm::map_iterator(llvm::seq(size_t(0), NodeDataOwner.size()).end(), + BuildNodeRef(this)); + } [[nodiscard]] auto nodes() const noexcept { - return llvm::make_range(node_begin(), node_end()); + assert(NodeAdjOwner.size() == NodeDataOwner.size()); + return llvm::map_range(llvm::seq(size_t(0), NodeDataOwner.size()), + BuildNodeRef(this)); } - [[nodiscard]] size_t size() const noexcept { return NodeOwner.size(); } + [[nodiscard]] size_t size() const noexcept { + assert(NodeAdjOwner.size() == NodeDataOwner.size()); + return NodeDataOwner.size(); + } /// Printing: void printAsDot(llvm::raw_ostream &OS) const { + assert(NodeAdjOwner.size() == NodeDataOwner.size()); OS << "digraph ESG{\n"; psr::scope_exit ClosingBrace = [&OS] { OS << '}'; }; - for (const auto &Nod : NodeOwner) { + for (size_t I = 0, End = NodeDataOwner.size(); I != End; ++I) { + auto Nod = NodeRef(I, this); + OS << I << "[label=\""; + OS.write_escaped(DPrinter.DtoString(Nod.value())) << "\"];\n"; - OS << intptr_t(&Nod) << "[label=\""; - OS.write_escaped(DPrinter.DtoString(Nod.Value)) << "\"];\n"; - - OS << intptr_t(&Nod) << "->" << intptr_t(Nod.Predecessor) + OS << I << "->" << intptr_t(Nod.predecessor().id()) << R"([style="bold" label=")"; - OS.write_escaped(NPrinter.NtoString(Nod.Source)) << "\"];\n"; - for (auto *NB : Nod.Neighbors) { - OS << intptr_t(&Nod) << "->" << intptr_t(NB) << "[color=\"red\"];\n"; + OS.write_escaped(NPrinter.NtoString(Nod.source())) << "\"];\n"; + for (auto NB : Nod.neighbors()) { + OS << I << "->" << NB.id() << "[color=\"red\"];\n"; } } } @@ -130,7 +272,7 @@ template class ExplodedSuperGraph { } void printESGNodes(llvm::raw_ostream &OS) const { - for (const auto &[Node, Vtx] : FlowFactVertexMap) { + for (const auto &[Node, _] : FlowFactVertexMap) { OS << "( " << NPrinter.NtoString(Node.first) << "; " << DPrinter.DtoString(Node.second) << " )\n"; } @@ -150,64 +292,72 @@ template class ExplodedSuperGraph { } }; - void saveEdge(Node *Pred, n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode, - bool DontSkip = false) { - auto &SuccVtx = FlowFactVertexMap[std::make_pair(Succ, SuccNode)]; - - // NOLINTNEXTLINE(readability-identifier-naming) - auto makeNode = [this, Pred, Curr, Succ, &CurrNode, &SuccNode]() mutable { - auto Ret = &NodeOwner.emplace_back(); - Ret->Value = SuccNode; + [[nodiscard]] std::optional getNodeIdOrNull(n_t Inst, + d_t Fact) const { + auto It = FlowFactVertexMap.find( + std::make_pair(std::move(Inst), std::move(Fact))); + if (It != FlowFactVertexMap.end()) { + return It->second; + } + return std::nullopt; + } - if (!Pred) { - // llvm::errs() << "> No Pred at edge " << NPrinter.NtoString(Curr) << - // ", " - // << DPrinter.DtoString(CurrNode) << ") --> (" - // << NPrinter.NtoString(Succ) << ", " - // << DPrinter.DtoString(SuccNode) << ")\n"; + void saveEdge(std::optional PredId, n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode, bool DontSkip = false) { + auto [SuccVtxIt, Inserted] = FlowFactVertexMap.try_emplace( + std::make_pair(Succ, SuccNode), Node::NoPredId); + // NOLINTNEXTLINE(readability-identifier-naming) + auto makeNode = [this, PredId, Curr, &CurrNode, &SuccNode]() mutable { + assert(NodeAdjOwner.size() == NodeDataOwner.size()); + auto Ret = NodeDataOwner.size(); + auto &NodData = NodeDataOwner.emplace_back(); + auto &NodAdj = NodeAdjOwner.emplace_back(); + NodData.Value = SuccNode; + + if (!PredId) { // For the seeds: Just that the FlowFactVertexMap is filled at that // position... FlowFactVertexMap[std::make_pair(Curr, CurrNode)] = Ret; } - Ret->Predecessor = Pred; + NodAdj.PredecessorIdx = PredId.value_or(Node::NoPredId); + NodData.Source = Curr; - Ret->Source = Curr; return Ret; }; - if (!DontSkip && Pred && Pred->Value == SuccNode && - Pred->Source->getParent() == Succ->getParent() && + if (!DontSkip && PredId && NodeDataOwner[*PredId].Value == SuccNode && + NodeDataOwner[*PredId].Source->getParent() == Succ->getParent() && SuccNode != ZeroValue) { - if (!SuccVtx) { - SuccVtx = Pred; + if (Inserted) { + SuccVtxIt->second = *PredId; return; } - if (Pred == SuccVtx) { + if (*PredId == SuccVtxIt->second) { return; } } - if (!SuccVtx) { - SuccVtx = makeNode(); + if (Inserted) { + SuccVtxIt->second = makeNode(); return; } /// Check for meaningless loop: if (auto Br = llvm::dyn_cast(Curr); SuccNode != ZeroValue && Br && !Br->isConditional()) { - auto Nod = Pred; - llvm::SmallPtrSet VisitedNodes; - while (Nod && Nod->Value == SuccNode) { + auto Nod = PredId.value_or(Node::NoPredId); + llvm::SmallPtrSet VisitedNodes; + while (Nod != Node::NoPredId && NodeDataOwner[Nod].Value == SuccNode) { if (LLVM_UNLIKELY(!VisitedNodes.insert(Nod).second)) { printAsDot(llvm::errs()); llvm::errs().flush(); abort(); } - if (Nod == SuccVtx) { + if (Nod == SuccVtxIt->second) { PHASAR_LOG_LEVEL_CAT(INFO, "PathSensitivityManager", "> saveEdge -- skip meaningless loop: (" << NPrinter.NtoString(Curr) << ", " @@ -216,23 +366,27 @@ template class ExplodedSuperGraph { << DPrinter.DtoString(SuccNode) << ")"); return; } - Nod = Nod->Predecessor; + Nod = NodeAdjOwner[Nod].PredecessorIdx; } } - if (SuccVtx->Predecessor != Pred && - llvm::none_of(SuccVtx->Neighbors, [Pred](const Node *Nd) { - return Nd->Predecessor == Pred; - })) { - SuccVtx->Neighbors.push_back(makeNode()); + NodeRef SuccVtx(SuccVtxIt->second, this); + + if (SuccVtx.predecessor().id() != PredId.value_or(Node::NoPredId) && + llvm::none_of(SuccVtx.neighbors(), + [Pred = PredId.value_or(Node::NoPredId)](NodeRef Nd) { + return Nd.predecessor().id() == Pred; + })) { + auto NewNode = makeNode(); + NodeAdjOwner[SuccVtxIt->second].Neighbors.push_back(NewNode); return; } } - std::pmr::unsynchronized_pool_resource MRes; - psr::StableVector NodeOwner; - std::pmr::unordered_map, Node *, PathInfoHash, PathInfoEq> - FlowFactVertexMap{&MRes}; + std::vector NodeDataOwner; + std::vector NodeAdjOwner; + std::unordered_map, size_t, PathInfoHash, PathInfoEq> + FlowFactVertexMap{}; // ZeroValue d_t ZeroValue; diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index 8d785057de..1234270221 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -15,6 +15,8 @@ #include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" #include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h" #include "phasar/DataFlow/PathSensitivity/PathTracingFilter.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/DFAMinimizer.h" #include "phasar/Utils/GraphTraits.h" @@ -35,13 +37,13 @@ class PathSensitivityManagerMixin { using n_t = typename AnalysisDomainTy::n_t; using d_t = typename AnalysisDomainTy::d_t; - using Node = typename ExplodedSuperGraph::Node; + using NodeRef = typename ExplodedSuperGraph::NodeRef; using graph_type = GraphType; using graph_traits_t = GraphTraits; using vertex_t = typename graph_traits_t::vertex_t; struct PathsToContext { - llvm::DenseMap Cache; + llvm::DenseMap Cache; llvm::SetVector> CurrPath; }; @@ -65,7 +67,7 @@ class PathSensitivityManagerMixin { template < typename FactsRangeTy, typename ConfigTy, typename Filter = DefaultPathTracingFilter, - typename = std::enable_if_t>> + typename = std::enable_if_t>> [[nodiscard]] GraphType pathsDagToAll(n_t Inst, FactsRangeTy FactsRange, const PathSensitivityConfigBase &Config, @@ -118,6 +120,32 @@ class PathSensitivityManagerMixin { PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", "The DAG indeed has no circles"); } + + // { + // std::error_code EC; + // llvm::raw_fd_stream ROS( + // "revdag-" + + // std::filesystem::path(psr::getFilePathFromIR(Inst)) + // .filename() + // .string() + + // "-" + psr::getMetaDataID(Inst) + ".dot", + // EC); + // assert(!EC); + // printGraph(Dag, ROS, "DAG", [](llvm::ArrayRef PartialPath) { + // std::string Buf; + // llvm::raw_string_ostream ROS(Buf); + // ROS << "[ "; + // llvm::interleaveComma(PartialPath, ROS, [&ROS](const auto *Inst) { + // ROS << psr::getMetaDataID(Inst); + // }); + // ROS << " ]"; + // ROS.flush(); + // return Buf; + // }); + + // llvm::errs() << "Rev Paths DAG has " << Dag.Roots.size() << " roots\n"; + // } + #endif if (Config.DAGDepthThreshold != SIZE_MAX) { @@ -187,7 +215,7 @@ class PathSensitivityManagerMixin { template < typename ConfigTy, typename L, typename Filter = DefaultPathTracingFilter, - typename = std::enable_if_t>> + typename = std::enable_if_t>> [[nodiscard]] GraphType pathsDagTo(n_t Inst, const SolverResults &SR, const PathSensitivityConfigBase &Config, @@ -199,7 +227,7 @@ class PathSensitivityManagerMixin { template < typename ConfigTy, typename Filter = DefaultPathTracingFilter, - typename = std::enable_if_t>> + typename = std::enable_if_t>> [[nodiscard]] GraphType pathsDagTo(n_t Inst, d_t Fact, const PathSensitivityConfigBase &Config, @@ -211,21 +239,21 @@ class PathSensitivityManagerMixin { private: template - bool pathsToImplLAInvoke(vertex_t Ret, Node *Vtx, PathsToContext &Ctx, + bool pathsToImplLAInvoke(vertex_t Ret, NodeRef Vtx, PathsToContext &Ctx, graph_type &RetDag, const Filter &PFilter) const { - Node *Prev; + NodeRef Prev; bool IsEnd = false; bool IsError = false; do { Prev = Vtx; - graph_traits_t::node(RetDag, Ret).push_back(Vtx->Source); + graph_traits_t::node(RetDag, Ret).push_back(Vtx.source()); - if (!Vtx->Predecessor) { + if (!Vtx.predecessor()) { return true; } - Vtx = Vtx->Predecessor; + Vtx = Vtx.predecessor(); if (PFilter.HasReachedEnd(Prev, Vtx)) { IsEnd = true; @@ -237,7 +265,7 @@ class PathSensitivityManagerMixin { break; } - } while (Vtx->Neighbors.empty()); + } while (!Vtx.hasNeighbors()); if (!Ctx.CurrPath.insert(Ret)) { PHASAR_LOG_LEVEL(ERROR, "Node " << Ret << " already on path"); @@ -246,7 +274,7 @@ class PathSensitivityManagerMixin { scope_exit PopRet = [&Ctx] { Ctx.CurrPath.pop_back(); }; // NOLINTNEXTLINE(readability-identifier-naming) - auto traverseNext = [&Ctx, this, Ret, &RetDag, &PFilter](Node *Nxt) { + auto traverseNext = [&Ctx, this, Ret, &RetDag, &PFilter](NodeRef Nxt) { auto Succ = pathsToImplLA(Nxt, Ctx, RetDag, PFilter); if (Succ != graph_traits_t::Invalid && !Ctx.CurrPath.contains(Succ)) { graph_traits_t::addEdge(RetDag, Ret, Succ); @@ -257,7 +285,7 @@ class PathSensitivityManagerMixin { traverseNext(Vtx); } - for (auto Nxt : Vtx->Neighbors) { + for (auto Nxt : Vtx.neighbors()) { assert(Nxt != nullptr); if (PFilter.IsErrorneousTransition(Prev, Nxt)) { continue; @@ -275,7 +303,7 @@ class PathSensitivityManagerMixin { } template - vertex_t pathsToImplLA(Node *Vtx, PathsToContext &Ctx, graph_type &RetDag, + vertex_t pathsToImplLA(NodeRef Vtx, PathsToContext &Ctx, graph_type &RetDag, const Filter &PFilter) const { /// Idea: Treat the graph as firstChild-nextSibling notation and always /// traverse with one predecessor lookAhead @@ -306,14 +334,14 @@ class PathSensitivityManagerMixin { } template - vertex_t pathsToImpl(n_t QueryInst, Node *Vtx, graph_type &RetDag, + vertex_t pathsToImpl(n_t QueryInst, NodeRef Vtx, graph_type &RetDag, PathsToContext &Ctx, const Filter &PFilter) const { auto Ret = graph_traits_t::addNode(RetDag, typename graph_traits_t::value_type()); graph_traits_t::node(RetDag, Ret).push_back(QueryInst); - for (auto *NB : Vtx->Neighbors) { + for (auto NB : Vtx.neighbors()) { auto NBNode = pathsToImplLA(NB, Ctx, RetDag, PFilter); if (NBNode != graph_traits_t::Invalid) { graph_traits_t::addEdge(RetDag, Ret, NBNode); diff --git a/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h index bcdf91e8d5..e787a0da1e 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h +++ b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h @@ -33,20 +33,19 @@ struct False2 { using DefaultPathTracingFilter = PathTracingFilter; -template +template struct is_pathtracingfilter_for : std::false_type {}; -template +template struct is_pathtracingfilter_for< - PathTracingFilter, Node, - std::enable_if_t< - std::is_invocable_r_v && - std::is_invocable_r_v>> + PathTracingFilter, NodeRef, + std::enable_if_t && + std::is_invocable_r_v>> : std::true_type {}; -template +template constexpr static bool is_pathtracingfilter_for_v = - is_pathtracingfilter_for::value; + is_pathtracingfilter_for::value; } // namespace psr #endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHTRACINGFILTER_H diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h index fd18841a1d..3daa38d103 100644 --- a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -127,6 +127,8 @@ class Z3BasedPathSensitivityManager ROS.flush(); return Buf; }); + + llvm::errs() << "Paths DAG has " << Dag.Roots.size() << " roots\n"; } #endif diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index f9552e2071..6b8084aca2 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -28,7 +28,7 @@ set(PHASAR_LINK_LIBS ) if(PHASAR_USE_Z3) - list(APPEND PHASAR_LINK_LIBS z3) + list(APPEND PHASAR_LINK_LIBS libz3) endif() set(LLVM_LINK_COMPONENTS diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index ac70e1b3ea..d97887c3df 100644 --- a/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -4,6 +4,6 @@ if(PHASAR_USE_Z3) target_link_libraries(PathTracingTest LINK_PUBLIC phasar_llvm_pathsensitivity - z3 + libz3 # -- the Z3 cmake target is named libz3, so we want to have it as dependency, not just as link-target ) endif() diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp index 8add6a0921..f5c72b94e7 100644 --- a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp @@ -223,7 +223,7 @@ TEST_F(PathTracingTest, Handle_Inter_03) { // "PathSensitivityManager"); // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, // "CallStackPathFilter"); - auto PathsVec = doAnalysis("inter_03_cpp.ll", true); + auto PathsVec = doAnalysis("inter_03_cpp.ll", false); comparePaths(PathsVec, {{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 5, 17, 18, 19, 0, 1, 2, 3, 5, 20, 21, 22}}); } @@ -260,7 +260,7 @@ TEST_F(PathTracingTest, Lambda_Inter_04) { TEST_F(PathTracingTest, Handle_Inter_05) { /// NOTE: We are generating from zero a few times, so without AutoSkipZero we /// get a lot of paths here - auto PathsVec = doAnalysis("inter_05_cpp.ll", true); + auto PathsVec = doAnalysis("inter_05_cpp.ll", false); comparePaths( PathsVec, {{22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, @@ -409,7 +409,7 @@ TEST_F(PathTracingTest, Lambda_Inter_Depth3_07) { } TEST_F(PathTracingTest, Handle_Inter_08) { - auto PathsVec = doAnalysis("inter_08_cpp.ll", true); + auto PathsVec = doAnalysis("inter_08_cpp.ll", false); /// FIXME: Handle mutable z3::exprs; As of now, we reject all paths that go /// into a loop, because this requires the loop condiiton to hold, whereas /// leaving the loop requires the loop condition not to hold which is @@ -493,7 +493,7 @@ TEST_F(PathTracingTest, Lambda_Inter_08) { } TEST_F(PathTracingTest, Handle_Inter_09) { - auto PathsVec = doAnalysis("inter_09_cpp.ll", true); + auto PathsVec = doAnalysis("inter_09_cpp.ll", false); /// FIXME: Same reason as Handle_Inter_08 comparePaths( PathsVec, @@ -521,7 +521,7 @@ TEST_F(PathTracingTest, Handle_Inter_10) { // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, // "PathSensitivityManager"); GTEST_SKIP() << "Need globals support"; - auto PathsVec = doAnalysis("inter_10_cpp.ll", true); + auto PathsVec = doAnalysis("inter_10_cpp.ll", false); /// TODO: GT } @@ -692,9 +692,16 @@ TEST_F(PathTracingTest, Handle_Intra_07) { } TEST_F(PathTracingTest, Handle_Intra_08) { - // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, - // "PathSensitivityManager"); - auto PathsVec = doAnalysis("intra_08_cpp.ll"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + auto PathsVec = doAnalysis("intra_08_cpp.ll", false); + // for (const auto &Path : PathsVec) { + // for (const auto *Inst : Path) { + // llvm::errs() << " " << psr::getMetaDataID(Inst); + // } + // llvm::errs() << '\n'; + // } + /// NOTE: we have a fallthrough from case 4 to default; Therefore, we only /// have 3 paths /// UPDATE: Despite the fallthrough, clang-14 now generates 4 distinct From 0449984c16786410dc7121eb0163cce31c40929d Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 17 Mar 2023 18:29:57 +0100 Subject: [PATCH 41/65] Get rid of NodeRef::DSI --- .../PathSensitivity/ExplodedSuperGraph.h | 33 ++++++------------- .../PathSensitivityManagerMixin.h | 7 ++-- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index 8b6c4d4f70..010171310b 100644 --- a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -142,28 +142,6 @@ template class ExplodedSuperGraph { return llvm::hash_combine(NR.NodeId, NR.Owner); } - struct DSI { - [[nodiscard]] static NodeRef getEmptyKey() noexcept { - return NodeRef( - Node::NoPredId, - llvm::DenseMapInfo::getEmptyKey()); - } - - [[nodiscard]] static NodeRef getTombstoneKey() noexcept { - return NodeRef( - Node::NoPredId, - llvm::DenseMapInfo::getTombstoneKey()); - } - - [[nodiscard]] static auto getHashValue(NodeRef NR) noexcept { - return hash_value(NR); - } - - [[nodiscard]] static bool isEqual(NodeRef L, NodeRef R) noexcept { - return L == R; - } - }; - private: explicit NodeRef(size_t NodeId, const ExplodedSuperGraph *Owner) noexcept : NodeId(NodeId), Owner(Owner) {} @@ -204,7 +182,16 @@ template class ExplodedSuperGraph { return nullptr; } - [[nodiscard]] const d_t &getZeroValue() const noexcept { return ZeroValue; } + [[nodiscard]] NodeRef fromNodeId(size_t NodeId) const noexcept { + assert(NodeDataOwner.size() == NodeAdjOwner.size()); + assert(NodeId < NodeDataOwner.size()); + + return NodeRef(NodeId, this); + } + + [[nodiscard]] ByConstRef getZeroValue() const noexcept { + return ZeroValue; + } template void saveEdges(n_t Curr, d_t CurrNode, n_t Succ, const Container &SuccNodes, diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index 1234270221..508a5107a0 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -43,7 +43,7 @@ class PathSensitivityManagerMixin { using vertex_t = typename graph_traits_t::vertex_t; struct PathsToContext { - llvm::DenseMap Cache; + llvm::DenseMap Cache; llvm::SetVector> CurrPath; }; @@ -308,7 +308,8 @@ class PathSensitivityManagerMixin { /// Idea: Treat the graph as firstChild-nextSibling notation and always /// traverse with one predecessor lookAhead - auto [It, Inserted] = Ctx.Cache.try_emplace(Vtx, graph_traits_t::Invalid); + auto [It, Inserted] = + Ctx.Cache.try_emplace(Vtx.id(), graph_traits_t::Invalid); if (!Inserted) { return It->second; } @@ -321,7 +322,7 @@ class PathSensitivityManagerMixin { if (!pathsToImplLAInvoke(Ret, Vtx, Ctx, RetDag, PFilter)) { /// NOTE: Don't erase Vtx from Cache to guarantee termination // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) -- fp - Ctx.Cache[Vtx] = graph_traits_t::Invalid; + Ctx.Cache[Vtx.id()] = graph_traits_t::Invalid; if (Ctx.CurrPath.contains(Ret) || !graph_traits_t::pop(RetDag, Ret)) { PHASAR_LOG_LEVEL(WARNING, "Cannot remove invalid path at: " << Ret); From 58454ded4190dc74292273183f08c7b88302ab8f Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 22 May 2023 11:14:59 +0200 Subject: [PATCH 42/65] Fix compile error due to merge --- include/phasar/PhasarLLVM/Utils/LLVMShorthands.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h index 878b4f03d3..5639c7a170 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h @@ -77,11 +77,6 @@ llvm::ModuleSlotTracker &getModuleSlotTrackerFor(const llvm::Value *V); */ [[nodiscard]] std::string llvmIRToString(const llvm::Value *V); -/** - * @brief Returns a string representation of a LLVM Type. - */ -std::string llvmTypeToString(const llvm::Type *T); - /** * @brief Similar to llvmIRToString, but removes the metadata from the output as * they are not always stable. Prefer this function over llvmIRToString, if you From 3f4031ed797d5c82c4acc578c6f1d20a989c542c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 22 May 2023 15:58:24 +0200 Subject: [PATCH 43/65] minor --- include/phasar/DataFlow/IfdsIde/SolverResults.h | 12 +++++++++--- .../DataFlow/PathSensitivity/ExplodedSuperGraph.h | 5 +++++ .../PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h | 4 ++-- lib/Controller/AnalysisController.cpp | 10 +--------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 6a5671a50e..9401fc59fb 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -95,7 +95,7 @@ class SolverResultsBase { llvm::Instruction>, std::unordered_map> resultsAtInLLVMSSA(ByConstRef Stmt, bool AllowOverapproximation = false, - bool StripZero = false); + bool StripZero = false) const; /// Returns the L-type result at the given statement for the given data-flow /// fact while respecting LLVM's SSA semantics. @@ -118,7 +118,7 @@ class SolverResultsBase { llvm::Instruction>, l_t> resultAtInLLVMSSA(ByConstRef Stmt, d_t Value, - bool AllowOverapproximation = false); + bool AllowOverapproximation = false) const; [[nodiscard]] std::vector::Cell> getAllResultEntries() const { @@ -231,9 +231,15 @@ class OwningSolverResults D ZV) noexcept(std::is_nothrow_move_constructible_v) : Results(std::move(ResTab)), ZV(ZV) {} - [[nodiscard]] operator SolverResults() const &noexcept { + [[nodiscard]] SolverResults asRef() const &noexcept { return {Results, ZV}; } + SolverResults asRef() && = delete; + + [[nodiscard]] operator SolverResults() const &noexcept { + return asRef(); + } + operator SolverResults() && = delete; private: diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index 010171310b..9334c784b9 100644 --- a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -171,7 +171,12 @@ template class ExplodedSuperGraph { DPrinter(DPrinter) {} explicit ExplodedSuperGraph(const ExplodedSuperGraph &) = default; + ExplodedSuperGraph &operator=(const ExplodedSuperGraph &) = delete; + ExplodedSuperGraph(ExplodedSuperGraph &&) noexcept = default; + ExplodedSuperGraph &operator=(ExplodedSuperGraph &&) noexcept = default; + + ~ExplodedSuperGraph() = default; [[nodiscard]] NodeRef getNodeOrNull(n_t Inst, d_t Fact) const { auto It = FlowFactVertexMap.find( diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h index 0e334cb336..d789958cca 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h @@ -24,7 +24,7 @@ namespace psr::detail { template template auto SolverResultsBase::resultsAtInLLVMSSA( - ByConstRef Stmt, bool AllowOverapproximation, bool StripZero) -> + ByConstRef Stmt, bool AllowOverapproximation, bool StripZero) const -> typename std::enable_if_t< std::is_same_v>, llvm::Instruction>, @@ -96,7 +96,7 @@ auto SolverResultsBase::resultsAtInLLVMSSA( template template auto SolverResultsBase::resultAtInLLVMSSA( - ByConstRef Stmt, d_t Value, bool AllowOverapproximation) -> + ByConstRef Stmt, d_t Value, bool AllowOverapproximation) const -> typename std::enable_if_t< std::is_same_v>, llvm::Instruction>, diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index 5e9d1413d4..cb763d412a 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -195,15 +195,7 @@ void AnalysisController::emitRequestedHelperAnalysisResults() { if (EmitterOptions & AnalysisControllerEmitterOptions::EmitStatisticsAsText) { - llvm::outs() << "Module " << IRDB.getModule()->getName() << ":\n"; - llvm::outs() << "> LLVM IR instructions:\t" << IRDB.getNumInstructions() - << "\n"; - llvm::outs() << "> Functions:\t\t" << IRDB.getModule()->size() << "\n"; - llvm::outs() << "> Global variables:\t" << IRDB.getModule()->global_size() - << "\n"; - llvm::outs() << "> Alloca instructions:\t" - << Stats.getAllocaInstructions().size() << "\n"; - llvm::outs() << "> Call Sites:\t\t" << Stats.getFunctioncalls() << "\n"; + llvm::outs() << Stats << '\n'; } if (EmitterOptions & From 657c51f6a3c6e52f3cc155f5275d2841f3fa5926 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 22 May 2023 16:05:38 +0200 Subject: [PATCH 44/65] More const in Table --- .../IfdsIde/Solver/PathAwareIDESolver.h | 6 ++++- .../phasar/DataFlow/IfdsIde/SolverResults.h | 11 ++++---- include/phasar/Utils/Table.h | 25 +++++++++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h index cbb72d6720..d2be4e1cb7 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h @@ -42,10 +42,14 @@ class PathAwareIDESolver : public IDESolver { } [[nodiscard]] const ExplodedSuperGraph & - getExplicitESG() const noexcept { + getExplicitESG() const &noexcept { return ESG; } + [[nodiscard]] ExplodedSuperGraph &&getExplicitESG() &&noexcept { + return std::move(ESG); + } + private: void saveEdges(n_t Curr, n_t Succ, d_t CurrNode, const container_type &SuccNodes, ESGEdgeKind Kind) override { diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 9401fc59fb..a7bd381cd9 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -129,7 +129,7 @@ class SolverResultsBase { void dumpResults(const ICFGTy &ICF, const NodePrinterBase &NP, const DataFlowFactPrinterBase &DP, const EdgeFactPrinterBase &LP, - llvm::raw_ostream &OS = llvm::outs()) { + llvm::raw_ostream &OS = llvm::outs()) const { using f_t = typename ICFGTy::f_t; PAMM_GET_INSTANCE; @@ -179,7 +179,7 @@ class SolverResultsBase { template void dumpResults(const ICFGTy &ICF, const ProblemTy &IDEProblem, - llvm::raw_ostream &OS = llvm::outs()) { + llvm::raw_ostream &OS = llvm::outs()) const { dumpResults(ICF, IDEProblem, IDEProblem, IDEProblem, OS); } @@ -206,12 +206,12 @@ class SolverResults using typename base_t::l_t; using typename base_t::n_t; - SolverResults(Table &ResTab, ByConstRef ZV) noexcept + SolverResults(const Table &ResTab, ByConstRef ZV) noexcept : Results(ResTab), ZV(ZV) {} SolverResults(Table &&ResTab, ByConstRef ZV) = delete; private: - Table &Results; + const Table &Results; ByConstRef ZV; }; @@ -243,8 +243,7 @@ class OwningSolverResults operator SolverResults() && = delete; private: - // psr::Table is not const-enabled, so we have to give out mutable references - mutable Table Results; + Table Results; D ZV; }; diff --git a/include/phasar/Utils/Table.h b/include/phasar/Utils/Table.h index 6b5511f64e..c8b44ddc86 100644 --- a/include/phasar/Utils/Table.h +++ b/include/phasar/Utils/Table.h @@ -185,6 +185,21 @@ template class Table { return Tab[RowKey][ColumnKey]; } + [[nodiscard]] const V &get(R RowKey, C ColumnKey) const { + static V Empty{}; + // Returns the value corresponding to the given row and column keys, or null + // if no such mapping exists. + auto OuterIt = Tab.find(RowKey); + if (OuterIt == Tab.end()) { + return Empty; + } + auto InnerIt = OuterIt->second.find(ColumnKey); + if (InnerIt == OuterIt->second.end()) { + return Empty; + } + return InnerIt->second; + } + V remove(R RowKey, C ColumnKey) { // Removes the mapping, if any, associated with the given keys. V Val = Tab[RowKey][ColumnKey]; @@ -199,6 +214,16 @@ template class Table { return Tab[RowKey]; } + [[nodiscard]] const std::unordered_map &row(R RowKey) const { + static std::unordered_map Empty{}; + auto It = Tab.find(RowKey); + if (It == Tab.end()) { + return Empty; + } + // Returns a view of all mappings that have the given row key. + return It->second; + } + [[nodiscard]] std::multiset rowKeySet() const { // Returns a set of row keys that have one or more values in the table. std::multiset Result; From 27acc997e5ef353c5c44ddae3657b639717af8fc Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 30 May 2023 10:30:48 +0200 Subject: [PATCH 45/65] Give the PathTracing Filters more power --- .../PathSensitivity/PathSensitivityManagerMixin.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index 508a5107a0..df80111a1d 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -249,10 +249,6 @@ class PathSensitivityManagerMixin { Prev = Vtx; graph_traits_t::node(RetDag, Ret).push_back(Vtx.source()); - if (!Vtx.predecessor()) { - return true; - } - Vtx = Vtx.predecessor(); if (PFilter.HasReachedEnd(Prev, Vtx)) { @@ -265,6 +261,10 @@ class PathSensitivityManagerMixin { break; } + if (!Vtx) { + return true; + } + } while (!Vtx.hasNeighbors()); if (!Ctx.CurrPath.insert(Ret)) { From e39dec8f39fe0d8aed44bf5e37189b070a3ae1db Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 31 May 2023 09:50:03 +0200 Subject: [PATCH 46/65] Fix null error --- .../PathSensitivity/PathSensitivityManagerMixin.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index df80111a1d..d5a3d21a2d 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -253,16 +253,16 @@ class PathSensitivityManagerMixin { if (PFilter.HasReachedEnd(Prev, Vtx)) { IsEnd = true; - break; - } - - if (PFilter.IsErrorneousTransition(Prev, Vtx)) { + } else if (PFilter.IsErrorneousTransition(Prev, Vtx)) { IsError = true; - break; } if (!Vtx) { - return true; + return !IsError; + } + + if (IsEnd || IsError) { + break; } } while (!Vtx.hasNeighbors()); From a916416a03d51af8121a3bb391c4004ab92eaf0a Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 3 Jul 2023 17:49:44 +0200 Subject: [PATCH 47/65] Fix Path Tracing with chaotic edge saving due to new Worklist structure in IDESolver --- .../PathSensitivity/ExplodedSuperGraph.h | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index 9334c784b9..2638649572 100644 --- a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -41,8 +41,6 @@ #include #include -#include - /// TODO: Keep an eye on memory_resource here! it is still not supported on some /// MAC systems @@ -207,10 +205,7 @@ template class ExplodedSuperGraph { /// path sensitivity, so skip it bool MaySkipEdge = Kind == ESGEdgeKind::CallToRet && CurrNode == ZeroValue; for (const d_t &SuccNode : SuccNodes) { - if (MaySkipEdge && SuccNode == CurrNode) { - continue; - } - saveEdge(PredId, Curr, CurrNode, Succ, SuccNode); + saveEdge(PredId, Curr, CurrNode, Succ, SuccNode, MaySkipEdge); } } @@ -295,7 +290,7 @@ template class ExplodedSuperGraph { } void saveEdge(std::optional PredId, n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode, bool DontSkip = false) { + d_t SuccNode, bool MaySkipEdge, bool DontSkip = false) { auto [SuccVtxIt, Inserted] = FlowFactVertexMap.try_emplace( std::make_pair(Succ, SuccNode), Node::NoPredId); @@ -319,6 +314,15 @@ template class ExplodedSuperGraph { return Ret; }; + if (MaySkipEdge && SuccNode == CurrNode) { + assert(PredId); + if (Inserted) { + SuccVtxIt->second = makeNode(); + NodeAdjOwner.back().PredecessorIdx = Node::NoPredId; + } + return; + } + if (!DontSkip && PredId && NodeDataOwner[*PredId].Value == SuccNode && NodeDataOwner[*PredId].Source->getParent() == Succ->getParent() && SuccNode != ZeroValue) { @@ -363,6 +367,12 @@ template class ExplodedSuperGraph { } NodeRef SuccVtx(SuccVtxIt->second, this); + if (!SuccVtx.predecessor()) { + NodeAdjOwner[SuccVtxIt->second].PredecessorIdx = + PredId.value_or(Node::NoPredId); + NodeDataOwner[SuccVtxIt->second].Source = Curr; + return; + } if (SuccVtx.predecessor().id() != PredId.value_or(Node::NoPredId) && llvm::none_of(SuccVtx.neighbors(), From 0494607468d5f0cd0d0c78a92c506525ba43f73c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 4 Jul 2023 19:08:13 +0200 Subject: [PATCH 48/65] Some cleanup --- include/phasar/DataFlow.h | 3 +++ .../DataFlow/IfdsIde/Solver/ESGEdgeKind.h | 6 +++--- .../IfdsIde/Solver/PathAwareIDESolver.h | 6 +++--- .../PathSensitivity/ExplodedSuperGraph.h | 20 +++++++++++-------- .../PathSensitivity/PathSensitivityConfig.h | 6 +++--- .../PathSensitivity/PathSensitivityManager.h | 6 +++--- .../PathSensitivityManagerBase.h | 6 +++--- .../PathSensitivityManagerMixin.h | 6 +++--- .../PathSensitivity/PathTracingFilter.h | 6 +++--- .../PathSensitivity/LLVMPathConstraints.h | 7 +++---- .../Z3BasedPathSensitivityConfig.h | 6 +++--- .../Z3BasedPathSensitvityManager.h | 6 +++--- .../PathSensitivity/LLVMPathConstraints.cpp | 14 ++++++------- .../PathSensitivity/PathTracingTest.cpp | 8 ++++---- 14 files changed, 56 insertions(+), 50 deletions(-) diff --git a/include/phasar/DataFlow.h b/include/phasar/DataFlow.h index a642ae4847..88453a251d 100644 --- a/include/phasar/DataFlow.h +++ b/include/phasar/DataFlow.h @@ -24,6 +24,7 @@ #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" #include "phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h" +#include "phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h" #include "phasar/DataFlow/IfdsIde/Solver/PathEdge.h" #include "phasar/DataFlow/IfdsIde/SolverResults.h" #include "phasar/DataFlow/IfdsIde/SpecialSummaries.h" @@ -32,5 +33,7 @@ #include "phasar/DataFlow/Mono/IntraMonoProblem.h" #include "phasar/DataFlow/Mono/Solver/InterMonoSolver.h" #include "phasar/DataFlow/Mono/Solver/IntraMonoSolver.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManager.h" #endif // PHASAR_DATAFLOW_H diff --git a/include/phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h b/include/phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h index 98652a197f..94b98ed893 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_IFDSIDE_SOLVER_ESGEDGEKIND_H -#define PHASAR_PHASARLLVM_IFDSIDE_SOLVER_ESGEDGEKIND_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H namespace psr { enum class ESGEdgeKind { Normal, Call, CallToRet, SkipUnknownFn, Ret, Summary }; @@ -19,4 +19,4 @@ constexpr bool isInterProc(ESGEdgeKind Kind) noexcept { } // namespace psr -#endif // PHASAR_PHASARLLVM_IFDSIDE_SOLVER_ESGEDGEKIND_H +#endif // PHASAR_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h index d2be4e1cb7..8cc97a7898 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h" @@ -66,4 +66,4 @@ PathAwareIDESolver(ProblemTy &) } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H +#endif // PHASAR_DATAFLOW_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index 2638649572..997dfa0514 100644 --- a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H +#ifndef PHASAR_DATAFLOW_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H #include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h" #include "phasar/Utils/ByRef.h" @@ -41,9 +41,6 @@ #include #include -/// TODO: Keep an eye on memory_resource here! it is still not supported on some -/// MAC systems - namespace psr { /// An explicit representation of the ExplodedSuperGraph (ESG) of an IFDS/IDE @@ -290,7 +287,7 @@ template class ExplodedSuperGraph { } void saveEdge(std::optional PredId, n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode, bool MaySkipEdge, bool DontSkip = false) { + d_t SuccNode, bool MaySkipEdge) { auto [SuccVtxIt, Inserted] = FlowFactVertexMap.try_emplace( std::make_pair(Succ, SuccNode), Node::NoPredId); @@ -315,6 +312,8 @@ template class ExplodedSuperGraph { }; if (MaySkipEdge && SuccNode == CurrNode) { + // This CTR edge carries no information, so skip it. + // We still want to create the destination node for the ret-FF later assert(PredId); if (Inserted) { SuccVtxIt->second = makeNode(); @@ -323,15 +322,17 @@ template class ExplodedSuperGraph { return; } - if (!DontSkip && PredId && NodeDataOwner[*PredId].Value == SuccNode && + if (PredId && NodeDataOwner[*PredId].Value == SuccNode && NodeDataOwner[*PredId].Source->getParent() == Succ->getParent() && SuccNode != ZeroValue) { + // Identity edge, we don't need a new node; just assign the Pred here if (Inserted) { SuccVtxIt->second = *PredId; return; } + // This edge has already been here?! if (*PredId == SuccVtxIt->second) { return; } @@ -366,6 +367,8 @@ template class ExplodedSuperGraph { } } + // Node has already been created, but MaySkipEdge above prevented us from + // connecting with the pred. Now, we have a non-skippable edge to connect to NodeRef SuccVtx(SuccVtxIt->second, this); if (!SuccVtx.predecessor()) { NodeAdjOwner[SuccVtxIt->second].PredecessorIdx = @@ -374,6 +377,7 @@ template class ExplodedSuperGraph { return; } + // This node has more than one predecessor; add a neighbor then if (SuccVtx.predecessor().id() != PredId.value_or(Node::NoPredId) && llvm::none_of(SuccVtx.neighbors(), [Pred = PredId.value_or(Node::NoPredId)](NodeRef Nd) { @@ -400,4 +404,4 @@ template class ExplodedSuperGraph { } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h index 19ed92ebc6..582dd02b17 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H +#ifndef PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H #include #include @@ -54,4 +54,4 @@ struct PathSensitivityConfig } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h index 7f840bff43..d781d127f5 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H +#ifndef PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H #include "phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h" #include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" @@ -51,4 +51,4 @@ class PathSensitivityManager }; } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h index c9a1dee0da..c81d7be0db 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H +#ifndef PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H #include "phasar/Utils/AdjacencyList.h" #include "phasar/Utils/Logger.h" @@ -186,4 +186,4 @@ extern template class PathSensitivityManagerBase; } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index d5a3d21a2d..3ac173c212 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H +#ifndef PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H #include "phasar/DataFlow/IfdsIde/SolverResults.h" #include "phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h" @@ -362,4 +362,4 @@ class PathSensitivityManagerMixin { }; } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h index e787a0da1e..8baaa10961 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h +++ b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHTRACINGFILTER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHTRACINGFILTER_H +#ifndef PHASAR_DATAFLOW_PATHSENSITIVITY_PATHTRACINGFILTER_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHTRACINGFILTER_H #include @@ -48,4 +48,4 @@ constexpr static bool is_pathtracingfilter_for_v = is_pathtracingfilter_for::value; } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_PATHTRACINGFILTER_H +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHTRACINGFILTER_H diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h index 580dc8b89c..887f4f54bc 100644 --- a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H +#ifndef PHASAR_PHASARLLVM_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H +#define PHASAR_PHASARLLVM_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H #include "phasar/Utils/MaybeUniquePtr.h" @@ -85,7 +85,6 @@ class LLVMPathConstraints { [[nodiscard]] ConstraintAndVariables getFunctionCallAsZ3(const llvm::CallBase *CallSite); - friend class LLVMPathConstraints; friend class SizeGuardCheck; friend class LoopGuardCheck; @@ -95,4 +94,4 @@ class LLVMPathConstraints { }; } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H +#endif // PHASAR_PHASARLLVM_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h index 03f2ffd00a..3d219f5fcd 100644 --- a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H +#ifndef PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H +#define PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H #include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" @@ -38,4 +38,4 @@ struct Z3BasedPathSensitivityConfig }; } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H +#endif // PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h index 3daa38d103..988a977c4a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H +#ifndef PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H +#define PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H #include "phasar/DataFlow/PathSensitivity/FlowPath.h" #include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h" @@ -183,4 +183,4 @@ class Z3BasedPathSensitivityManager }; } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H +#endif // PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp index 113c35b0d8..9ea5c94fcc 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp @@ -45,9 +45,9 @@ auto LLVMPathConstraints::internalGetConstraintAndVariablesFromEdge( } std::optional -LLVMPathConstraints::getConstraintFromEdge(const llvm::Instruction *From, - const llvm::Instruction *To) { - if (auto CV = internalGetConstraintAndVariablesFromEdge(From, To)) { +LLVMPathConstraints::getConstraintFromEdge(const llvm::Instruction *Curr, + const llvm::Instruction *Succ) { + if (auto CV = internalGetConstraintAndVariablesFromEdge(Curr, Succ)) { return CV->Constraint; } @@ -55,9 +55,9 @@ LLVMPathConstraints::getConstraintFromEdge(const llvm::Instruction *From, } auto LLVMPathConstraints::getConstraintAndVariablesFromEdge( - const llvm::Instruction *From, const llvm::Instruction *To) + const llvm::Instruction *Curr, const llvm::Instruction *Succ) -> std::optional { - auto CV = internalGetConstraintAndVariablesFromEdge(From, To); + auto CV = internalGetConstraintAndVariablesFromEdge(Curr, Succ); if (CV) { /// Deduplicate the Variables vector std::sort(CV->Variables.begin(), CV->Variables.end()); @@ -362,7 +362,7 @@ auto LLVMPathConstraints::handleCmpInst(const llvm::CmpInst *Cmp) LhsZ3Expr.Constraint = LhsZ3Expr.Constraint < RhsZ3Expr.Constraint; break; case llvm::CmpInst::Predicate::ICMP_SLE: ///< signed less or equal - LhsZ3Expr.Constraint = LhsZ3Expr.Constraint < RhsZ3Expr.Constraint; + LhsZ3Expr.Constraint = LhsZ3Expr.Constraint <= RhsZ3Expr.Constraint; break; default: llvm::report_fatal_error("unhandled predicate!"); @@ -656,4 +656,4 @@ auto LLVMPathConstraints::getFunctionCallAsZ3(const llvm::CallBase *CallSite) llvm::report_fatal_error("unhandled function call!"); } -} // namespace psr \ No newline at end of file +} // namespace psr diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp index f5c72b94e7..f1a6b6366d 100644 --- a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp @@ -124,10 +124,10 @@ class PathTracingTest : public ::testing::Test { llvm::outs() << "Target instruction: " << psr::llvmIRToString(LastInst) << '\n'; - std::error_code EC; - llvm::raw_fd_ostream ROS(LlvmFilePath + "_explicit_esg.dot", EC); - assert(!EC); - Solver.getExplicitESG().printAsDot(ROS); + // std::error_code EC; + // llvm::raw_fd_ostream ROS(LlvmFilePath + "_explicit_esg.dot", EC); + // assert(!EC); + // Solver.getExplicitESG().printAsDot(ROS); psr::Z3BasedPathSensitivityManager PSM( &Solver.getExplicitESG(), From 35c3efffed16869d9e3b895190dac34ce3a59f03 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 4 Jul 2023 19:53:10 +0200 Subject: [PATCH 49/65] pre-commit --- include/phasar/DataFlow/PathSensitivity/FlowPath.h | 4 ++-- include/phasar/Utils/DFAMinimizer.h | 4 ++-- include/phasar/Utils/TypeTraits.h | 4 +--- lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/FlowPath.h b/include/phasar/DataFlow/PathSensitivity/FlowPath.h index dcbf903a5d..532852ab0e 100644 --- a/include/phasar/DataFlow/PathSensitivity/FlowPath.h +++ b/include/phasar/DataFlow/PathSensitivity/FlowPath.h @@ -10,11 +10,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOW_PATHSENSITIVITY_FLOWPATH_H #define PHASAR_PHASARLLVM_DATAFLOW_PATHSENSITIVITY_FLOWPATH_H -#include "z3++.h" - #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "z3++.h" + namespace psr { template struct FlowPath { llvm::SmallVector Path; diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 1509d7103b..00a20f0db9 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -24,7 +24,7 @@ template [[nodiscard]] std::decay_t createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) #if __cplusplus >= 202002L - requires is_graph + requires is_graph #endif { using traits_t = GraphTraits; @@ -86,7 +86,7 @@ createEquivalentGraphFrom(GraphTy &&G, const llvm::IntEqClasses &Eq) template [[nodiscard]] llvm::IntEqClasses minimizeGraph(const GraphTy &G) #if __cplusplus >= 202002L - requires is_graph + requires is_graph #endif { diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index a8dfd9cb42..e14db975bd 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -195,9 +195,7 @@ static inline constexpr bool AreEqualityComparable = detail::AreEqualityComparable::value; #if __cplusplus < 202002L -template struct type_identity { - using type = T; -}; +template struct type_identity { using type = T; }; #else template using type_identity = std::type_identity; #endif diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index 6b8084aca2..78699965ea 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -5,7 +5,7 @@ if(NOT PHASAR_USE_Z3) # get_filename_component(LLVMPathConstraints_src LLVMPathConstraints.cpp ABSOLUTE) # list(REMOVE_ITEM PATHSENSITIVITY_SRC ${LLVMPathConstraints_src}) - + get_filename_component(Z3BasedPathSensitvityManager_src Z3BasedPathSensitvityManager.cpp ABSOLUTE) # message("Not compiling ${Z3BasedPathSensitvityManager_src} since Z3 is disabled.") # list(REMOVE_ITEM PATHSENSITIVITY_SRC ${Z3BasedPathSensitvityManager_src}) From 74f84327254930bbc58c33b5979d85d4935cc087 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Tue, 1 Aug 2023 18:46:04 +0200 Subject: [PATCH 50/65] Apply some review comments --- .../PathSensitivityManagerBase.h | 13 ++-- .../PathSensitivityManagerMixin.h | 70 ------------------- .../Z3BasedPathSensitivityManager.cpp | 17 +---- 3 files changed, 8 insertions(+), 92 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h index c81d7be0db..0c2ec0afe6 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h @@ -114,18 +114,19 @@ template class PathSensitivityManagerBase { // it is small enough static constexpr size_t MaxNumBytesInStackBuf = 8192; - auto *Buf = NumBytes <= MaxNumBytesInStackBuf ? alloca(NumBytes) - : new char[NumBytes]; - std::unique_ptr Owner; + auto *Buf = NumBytes <= MaxNumBytesInStackBuf + ? reinterpret_cast(alloca(NumBytes)) + : new char[NumBytes]; + std::unique_ptr Owner; // NOLINT if (NumBytes > MaxNumBytesInStackBuf) { - Owner.reset((char *)Buf); + Owner.reset(Buf); } - auto Cache = (vertex_t *)Buf; + auto Cache = reinterpret_cast(Buf); std::uninitialized_fill_n(Cache, EquivSize, graph_traits_t::Invalid); auto *WLConsumeBegin = - (std::pair *)((vertex_t *)Buf + EquivSize); + reinterpret_cast *>(Cache + EquivSize); auto *WLConsumeEnd = WLConsumeBegin; auto *WLInsertBegin = WLConsumeBegin + EquivSize; auto *WLInsertEnd = WLInsertBegin; diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index 3ac173c212..9807367ab9 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -80,11 +80,6 @@ class PathSensitivityManagerMixin { if (!Nod) { - // llvm::errs() << "At Inst " << llvmIRToString(Inst) << "; Fact: " << - // Fact - // << '\n'; - // llvm::errs(); - { std::error_code EC; llvm::raw_fd_ostream ROS("explicitesg-err.dot", EC); @@ -121,31 +116,6 @@ class PathSensitivityManagerMixin { "The DAG indeed has no circles"); } - // { - // std::error_code EC; - // llvm::raw_fd_stream ROS( - // "revdag-" + - // std::filesystem::path(psr::getFilePathFromIR(Inst)) - // .filename() - // .string() + - // "-" + psr::getMetaDataID(Inst) + ".dot", - // EC); - // assert(!EC); - // printGraph(Dag, ROS, "DAG", [](llvm::ArrayRef PartialPath) { - // std::string Buf; - // llvm::raw_string_ostream ROS(Buf); - // ROS << "[ "; - // llvm::interleaveComma(PartialPath, ROS, [&ROS](const auto *Inst) { - // ROS << psr::getMetaDataID(Inst); - // }); - // ROS << " ]"; - // ROS.flush(); - // return Buf; - // }); - - // llvm::errs() << "Rev Paths DAG has " << Dag.Roots.size() << " roots\n"; - // } - #endif if (Config.DAGDepthThreshold != SIZE_MAX) { @@ -155,53 +125,13 @@ class PathSensitivityManagerMixin { } if (Config.MinimizeDAG) { - // { - // std::error_code EC; - // llvm::raw_fd_ostream ROS("unminimized_graph.dot", EC); - // assert(!EC); - // printGraph(Dag, ROS, "Unminimized DAG", [](const auto &Node) { - // std::string Str; - // llvm::raw_string_ostream StrStr(Str); - // StrStr << "["; - // llvm::interleaveComma(Node, StrStr, [&StrStr](const auto *Inst) { - // StrStr << getMetaDataID(Inst); - // }); - // StrStr << "]"; - // return Str; - // }); - // } auto Equiv = minimizeGraph(Dag); - // llvm::errs() << "Equiv:\n"; - // llvm::errs() << "> Size: " << Equiv.getNumClasses() << '\n'; - // for (size_t i = 0, end = Equiv.getNumClasses(); i < end; ++i) { - // llvm::errs() << "[" << i << "] = " << Equiv[i] << '\n'; - // } - Dag = createEquivalentGraphFrom(std::move(Dag), Equiv); - // Dag = Derived::reverseDAG( - // std::move(Dag), [&Equiv](vertex_t Vtx) { return Equiv[Vtx]; }, - // Equiv.getNumClasses(), Config.DAGDepthThreshold); #ifndef NDEBUG if (!static_cast(this)->assertIsDAG(Dag)) { - // { - // std::error_code EC; - // llvm::raw_fd_ostream ROS("minimized_graph.dot", EC); - // assert(!EC); - // printGraph(Dag, ROS, "Minimized DAG", [](const auto &Node) { - // std::string Str; - // llvm::raw_string_ostream StrStr(Str); - // StrStr << "["; - // llvm::interleaveComma(Node, StrStr, [&StrStr](const auto *Inst) { - // StrStr << getMetaDataID(Inst); - // }); - // StrStr << "]"; - // return Str; - // }); - // } - llvm::report_fatal_error("Invariant violated: DAG has a circle in it!"); } else { PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp index 4c952589a1..801a8e10f1 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -78,21 +78,6 @@ z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( auto Sat = Ctx.Solver.check(); if (Sat == z3::check_result::unsat) { - // llvm::errs() << "> Unsat: " << Ctx.Solver.to_smt2() << '\n'; - // llvm::errs() << ">> With X: " << X.to_string() << '\n'; - // llvm::errs() << ">> With Y: " << Y.to_string() << '\n'; - // llvm::errs() << ">> With NodeConstraints[" << Adj - // << "]: " << Ctx.NodeConstraints[Adj].to_string() << - // '\n'; - // if (auto Constr = - // LPC.getConstraintFromEdge(PartialPath.front(), AdjPP.back())) - // { - // llvm::errs() << ">> With EdgeConstraint: " << Constr->to_string() - // << '\n'; - // } else { - // llvm::errs() << ">> Without EdgeConstraint\n"; - // } - Iter = graph_traits_t::removeEdge(RevDAG, Vtx, It); Ctx.Ctr++; } else { @@ -483,7 +468,7 @@ auto Z3BasedPathSensitivityManagerBase::filterAndFlattenRevDag( /// that gets returned at the end /// Problem: We still have way too many Z3 solver invocations (> 900000 for - /// all teatcases) + /// some small test programs) /// Solution idea: In contrast to the context sensitivity check, the Path /// constraints are context-independent. So, it might be beneficial to /// compute the end-reachability constraints of each _node_ in a bottom-up From ea76bc125d7ab85e8b358d79e7ae267da228727b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 2 Aug 2023 21:18:32 +0200 Subject: [PATCH 51/65] Write ESG to temp file instead of hard-coded file --- .../PathSensitivity/PathSensitivityManagerMixin.h | 13 ++++++++----- tools/example-tool/myphasartool.cpp | 3 +++ tools/phasar-cli/phasar-cli.cpp | 6 +++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index 9807367ab9..e11b4c437b 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -79,17 +79,20 @@ class PathSensitivityManagerMixin { auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); if (!Nod) { + llvm::errs() << "Fatal eror occurred. Writing ESG to temp file...\n"; + llvm::errs().flush(); + + auto FileName = + std::string(std::tmpnam(nullptr)) + "-explicitesg-err.dot"; { std::error_code EC; - llvm::raw_fd_ostream ROS("explicitesg-err.dot", EC); + llvm::raw_fd_ostream ROS(FileName, EC); ESG.printAsDot(ROS); } - llvm::errs() - << "> ESG written to " - << std::filesystem::canonical("explicitesg-err.dot").string() - << '\n'; + llvm::errs() << "> ESG written to " + << std::filesystem::canonical(FileName).string() << '\n'; llvm::errs().flush(); llvm::report_fatal_error( diff --git a/tools/example-tool/myphasartool.cpp b/tools/example-tool/myphasartool.cpp index 642c6fd975..6f7027b9b2 100644 --- a/tools/example-tool/myphasartool.cpp +++ b/tools/example-tool/myphasartool.cpp @@ -28,6 +28,9 @@ int main(int Argc, const char **Argv) { std::vector EntryPoints = {"main"s}; HelperAnalyses HA(Argv[1], EntryPoints); + if (!HA.getProjectIRDB().isValid()) { + return 1; + } if (const auto *F = HA.getProjectIRDB().getFunctionDefinition("main")) { // print type hierarchy diff --git a/tools/phasar-cli/phasar-cli.cpp b/tools/phasar-cli/phasar-cli.cpp index ef221b8cd3..012a4e875f 100644 --- a/tools/phasar-cli/phasar-cli.cpp +++ b/tools/phasar-cli/phasar-cli.cpp @@ -260,7 +260,7 @@ void validateParamModule() { if (!(std::filesystem::exists(ModulePath) && !std::filesystem::is_directory(ModulePath) && (ModulePath.extension() == ".ll" || ModulePath.extension() == ".bc"))) { - llvm::errs() << "LLVM module '" << std::filesystem::absolute(ModulePath) + llvm::errs() << "LLVM module '" << std::filesystem::canonical(ModulePath) << "' does not exist!\n"; exit(1); } @@ -453,6 +453,10 @@ int main(int Argc, const char **Argv) { !AnalysisController::needsToEmitPTA(EmitterOptions), EntryOpt, std::move(PrecomputedCallGraph), CGTypeOpt, SoundnessOpt, AutoGlobalsOpt); + if (!HA.getProjectIRDB().isValid()) { + // Note: Error message has already been printed + return 1; + } AnalysisController Controller( HA, DataFlowAnalysisOpt, {AnalysisConfigOpt.getValue()}, EntryOpt, From 58a8d35a27723e3baf919063b0e6e33adee8b841 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 6 Aug 2023 13:16:22 +0200 Subject: [PATCH 52/65] minor --- .../PathSensitivityManagerMixin.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index e11b4c437b..c1da1baf9d 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -27,6 +27,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" +#include #include #include #include @@ -78,12 +79,13 @@ class PathSensitivityManagerMixin { for (const d_t &Fact : FactsRange) { auto Nod = ESG.getNodeOrNull(Inst, std::move(Fact)); - if (!Nod) { - llvm::errs() << "Fatal eror occurred. Writing ESG to temp file...\n"; + if (LLVM_UNLIKELY(!Nod)) { + llvm::errs() << "Invalid Instruction-FlowFact pair. Only use those " + "pairs that are part of the IDE analysis results!\n"; + llvm::errs() << "Fatal error occurred. Writing ESG to temp file...\n"; llvm::errs().flush(); - auto FileName = - std::string(std::tmpnam(nullptr)) + "-explicitesg-err.dot"; + auto FileName = std::string(tmpnam(nullptr)) + "-explicitesg-err.dot"; { std::error_code EC; @@ -91,13 +93,10 @@ class PathSensitivityManagerMixin { ESG.printAsDot(ROS); } - llvm::errs() << "> ESG written to " - << std::filesystem::canonical(FileName).string() << '\n'; + llvm::errs() << "> ESG written to " << FileName << '\n'; llvm::errs().flush(); - llvm::report_fatal_error( - "Invalid Instruction-FlowFact pair. Only use those pairs that are " - "part of the IDE analysis results!"); + abort(); } /// NOTE: We don't need to check that Nod has not been processed yet, From e0735d82dafc81ebb700b4b7379348b0c8b7d805 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 15 Aug 2023 19:49:24 +0200 Subject: [PATCH 53/65] pre-commitIDESolver.h --- include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 0bcbf0d299..3199aa3b96 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -392,7 +392,8 @@ class IDESolver INC_COUNTER("FF Queries", 1, Full); const container_type ReturnedFacts = computeReturnFlowFunction( RetFunction, d3, d4, n, Container{d2}); - ADD_TO_HISTOGRAM("Data-flow facts", returnedFacts.size(), 1, Full); + ADD_TO_HISTOGRAM("Data-flow facts", returnedFacts.size(), 1, + Full); saveEdges(eP, RetSiteN, d4, ReturnedFacts, ESGEdgeKind::Ret); // for each target value of the function for (d_t d5 : ReturnedFacts) { From 9136cada8baee0b3e0dd0344eaee484df69c889c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 15 Aug 2023 19:50:36 +0200 Subject: [PATCH 54/65] pre-commit Utilities.h --- include/phasar/Utils/Utilities.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 9d05cafbe3..7dfbe381dc 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -254,7 +254,6 @@ auto remove_by_index(Container &Cont, const Indices &Idx) { return remove_by_index(begin(Cont), end(Cont), begin(Idx), end(Idx)); } - /// See https://en.cppreference.com/w/cpp/utility/forward_like template [[nodiscard]] constexpr auto &&forward_like(U &&X) noexcept { // NOLINT From a2ab5fa7c36a80fb2478561e76acaad28ec5ef3c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 15 Aug 2023 19:55:36 +0200 Subject: [PATCH 55/65] trailing whitespace IDESolver.h --- include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 3199aa3b96..a473622d32 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -392,7 +392,7 @@ class IDESolver INC_COUNTER("FF Queries", 1, Full); const container_type ReturnedFacts = computeReturnFlowFunction( RetFunction, d3, d4, n, Container{d2}); - ADD_TO_HISTOGRAM("Data-flow facts", returnedFacts.size(), 1, + ADD_TO_HISTOGRAM("Data-flow facts", returnedFacts.size(), 1, Full); saveEdges(eP, RetSiteN, d4, ReturnedFacts, ESGEdgeKind::Ret); // for each target value of the function From d491f6f95203b7a6cf91d490806f7d6372bd6017 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 18 Aug 2023 17:46:16 +0200 Subject: [PATCH 56/65] Fix errors due to merge --- include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index a473622d32..40318fa915 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -320,7 +320,7 @@ class IDESolver for (n_t ReturnSiteN : ReturnSiteNs) { container_type Res = computeSummaryFlowFunction(SpecialSum, d1, d2); INC_COUNTER("SpecialSummary-FF Application", 1, Full); - ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, Full); + ADD_TO_HISTOGRAM("Data-flow facts", Res.size(), 1, Full); saveEdges(n, ReturnSiteN, d2, Res, ESGEdgeKind::Summary); for (d_t d3 : Res) { EdgeFunction SumEdgFnE = @@ -392,7 +392,7 @@ class IDESolver INC_COUNTER("FF Queries", 1, Full); const container_type ReturnedFacts = computeReturnFlowFunction( RetFunction, d3, d4, n, Container{d2}); - ADD_TO_HISTOGRAM("Data-flow facts", returnedFacts.size(), 1, + ADD_TO_HISTOGRAM("Data-flow facts", ReturnedFacts.size(), 1, Full); saveEdges(eP, RetSiteN, d4, ReturnedFacts, ESGEdgeKind::Ret); // for each target value of the function @@ -450,7 +450,7 @@ class IDESolver INC_COUNTER("FF Queries", 1, Full); container_type ReturnFacts = computeCallToReturnFlowFunction(CallToReturnFF, d1, d2); - ADD_TO_HISTOGRAM("Data-flow facts", returnFacts.size(), 1, Full); + ADD_TO_HISTOGRAM("Data-flow facts", ReturnFacts.size(), 1, Full); saveEdges(n, ReturnSiteN, d2, ReturnFacts, HasNoCalleeInformation ? ESGEdgeKind::SkipUnknownFn : ESGEdgeKind::CallToRet); @@ -491,7 +491,7 @@ class IDESolver CachedFlowEdgeFunctions.getNormalFlowFunction(n, nPrime); INC_COUNTER("FF Queries", 1, Full); const container_type Res = computeNormalFlowFunction(FlowFunc, d1, d2); - ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, Full); + ADD_TO_HISTOGRAM("Data-flow facts", Res.size(), 1, Full); saveEdges(n, nPrime, d2, Res, ESGEdgeKind::Normal); for (d_t d3 : Res) { EdgeFunction g = @@ -851,7 +851,7 @@ class IDESolver for (d_t d4 : Entry.second) { const container_type Targets = computeReturnFlowFunction(RetFunction, d1, d2, c, Entry.second); - ADD_TO_HISTOGRAM("Data-flow facts", targets.size(), 1, Full); + ADD_TO_HISTOGRAM("Data-flow facts", Targets.size(), 1, Full); saveEdges(n, RetSiteC, d2, Targets, ESGEdgeKind::Ret); // for each target value at the return site // line 23 @@ -919,7 +919,7 @@ class IDESolver INC_COUNTER("FF Queries", 1, Full); const container_type Targets = computeReturnFlowFunction( RetFunction, d1, d2, Caller, Container{ZeroValue}); - ADD_TO_HISTOGRAM("Data-flow facts", targets.size(), 1, Full); + ADD_TO_HISTOGRAM("Data-flow facts", Targets.size(), 1, Full); saveEdges(n, RetSiteC, d2, Targets, ESGEdgeKind::Ret); for (d_t d5 : Targets) { EdgeFunction f5 = From 5cdca10e048ec9d1dd066321a242938ef5ae900e Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 25 Aug 2023 09:51:25 +0200 Subject: [PATCH 57/65] Integrate free-functions NToString and DToString into ExplicitESG --- .../IfdsIde/Solver/PathAwareIDESolver.h | 2 +- .../PathSensitivity/ExplodedSuperGraph.h | 32 +++++++------------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h index 8cc97a7898..711932c878 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h @@ -31,7 +31,7 @@ class PathAwareIDESolver : public IDESolver { explicit PathAwareIDESolver( IDETabulationProblem &Problem, const i_t *ICF) - : base_t(Problem, ICF), ESG(Problem.getZeroValue(), Problem, Problem) { + : base_t(Problem, ICF), ESG(Problem.getZeroValue()) { if (Problem.getIFDSIDESolverConfig().autoAddZero()) { PHASAR_LOG_LEVEL( diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index 997dfa0514..efb48b848a 100644 --- a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -158,12 +158,9 @@ template class ExplodedSuperGraph { const ExplodedSuperGraph *Owner{}; }; - explicit ExplodedSuperGraph( - d_t ZeroValue, const psr::NodePrinter &NPrinter, - const psr::DataFlowFactPrinter - &DPrinter) noexcept(std::is_nothrow_move_constructible_v) - : ZeroValue(std::move(ZeroValue)), NPrinter(NPrinter), - DPrinter(DPrinter) {} + explicit ExplodedSuperGraph(d_t ZeroValue) noexcept( + std::is_nothrow_move_constructible_v) + : ZeroValue(std::move(ZeroValue)) {} explicit ExplodedSuperGraph(const ExplodedSuperGraph &) = default; ExplodedSuperGraph &operator=(const ExplodedSuperGraph &) = delete; @@ -239,11 +236,11 @@ template class ExplodedSuperGraph { for (size_t I = 0, End = NodeDataOwner.size(); I != End; ++I) { auto Nod = NodeRef(I, this); OS << I << "[label=\""; - OS.write_escaped(DPrinter.DtoString(Nod.value())) << "\"];\n"; + OS.write_escaped(DToString(Nod.value())) << "\"];\n"; OS << I << "->" << intptr_t(Nod.predecessor().id()) << R"([style="bold" label=")"; - OS.write_escaped(NPrinter.NtoString(Nod.source())) << "\"];\n"; + OS.write_escaped(NToString(Nod.source())) << "\"];\n"; for (auto NB : Nod.neighbors()) { OS << I << "->" << NB.id() << "[color=\"red\"];\n"; } @@ -257,8 +254,8 @@ template class ExplodedSuperGraph { void printESGNodes(llvm::raw_ostream &OS) const { for (const auto &[Node, _] : FlowFactVertexMap) { - OS << "( " << NPrinter.NtoString(Node.first) << "; " - << DPrinter.DtoString(Node.second) << " )\n"; + OS << "( " << NToString(Node.first) << "; " << DToString(Node.second) + << " )\n"; } } @@ -355,12 +352,11 @@ template class ExplodedSuperGraph { abort(); } if (Nod == SuccVtxIt->second) { - PHASAR_LOG_LEVEL_CAT(INFO, "PathSensitivityManager", - "> saveEdge -- skip meaningless loop: (" - << NPrinter.NtoString(Curr) << ", " - << DPrinter.DtoString(CurrNode) << ") --> (" - << NPrinter.NtoString(Succ) << ", " - << DPrinter.DtoString(SuccNode) << ")"); + PHASAR_LOG_LEVEL_CAT( + INFO, "PathSensitivityManager", + "> saveEdge -- skip meaningless loop: (" + << NToString(Curr) << ", " << DToString(CurrNode) << ") --> (" + << NToString(Succ) << ", " << DToString(SuccNode) << ")"); return; } Nod = NodeAdjOwner[Nod].PredecessorIdx; @@ -396,10 +392,6 @@ template class ExplodedSuperGraph { // ZeroValue d_t ZeroValue; - // References to Node and DataFlowFactPrinters required for visualizing the - // results - const psr::NodePrinter &NPrinter; - const psr::DataFlowFactPrinter &DPrinter; }; } // namespace psr From 7d3d9a878a73d21dec98fcb9a2913eb5b0f29ddc Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 25 Aug 2023 15:02:57 +0200 Subject: [PATCH 58/65] Adapt invariants due to chaotic solving (worklist vs recursion) --- .../PathSensitivity/ExplodedSuperGraph.h | 45 ++++++------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h index efb48b848a..df9d1ec3cc 100644 --- a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -288,10 +288,15 @@ template class ExplodedSuperGraph { auto [SuccVtxIt, Inserted] = FlowFactVertexMap.try_emplace( std::make_pair(Succ, SuccNode), Node::NoPredId); + // Save a reference into the FlowFactVertexMap before the SuccVtxIt gets + // invalidated + auto &SuccVtxNode = SuccVtxIt->second; + // NOLINTNEXTLINE(readability-identifier-naming) auto makeNode = [this, PredId, Curr, &CurrNode, &SuccNode]() mutable { assert(NodeAdjOwner.size() == NodeDataOwner.size()); auto Ret = NodeDataOwner.size(); + auto &NodData = NodeDataOwner.emplace_back(); auto &NodAdj = NodeAdjOwner.emplace_back(); NodData.Value = SuccNode; @@ -313,7 +318,7 @@ template class ExplodedSuperGraph { // We still want to create the destination node for the ret-FF later assert(PredId); if (Inserted) { - SuccVtxIt->second = makeNode(); + SuccVtxNode = makeNode(); NodeAdjOwner.back().PredecessorIdx = Node::NoPredId; } return; @@ -325,51 +330,28 @@ template class ExplodedSuperGraph { // Identity edge, we don't need a new node; just assign the Pred here if (Inserted) { - SuccVtxIt->second = *PredId; + SuccVtxNode = *PredId; return; } // This edge has already been here?! - if (*PredId == SuccVtxIt->second) { + if (*PredId == SuccVtxNode) { return; } } if (Inserted) { - SuccVtxIt->second = makeNode(); + SuccVtxNode = makeNode(); return; } - /// Check for meaningless loop: - if (auto Br = llvm::dyn_cast(Curr); - SuccNode != ZeroValue && Br && !Br->isConditional()) { - auto Nod = PredId.value_or(Node::NoPredId); - llvm::SmallPtrSet VisitedNodes; - while (Nod != Node::NoPredId && NodeDataOwner[Nod].Value == SuccNode) { - if (LLVM_UNLIKELY(!VisitedNodes.insert(Nod).second)) { - printAsDot(llvm::errs()); - llvm::errs().flush(); - abort(); - } - if (Nod == SuccVtxIt->second) { - PHASAR_LOG_LEVEL_CAT( - INFO, "PathSensitivityManager", - "> saveEdge -- skip meaningless loop: (" - << NToString(Curr) << ", " << DToString(CurrNode) << ") --> (" - << NToString(Succ) << ", " << DToString(SuccNode) << ")"); - return; - } - Nod = NodeAdjOwner[Nod].PredecessorIdx; - } - } - // Node has already been created, but MaySkipEdge above prevented us from // connecting with the pred. Now, we have a non-skippable edge to connect to - NodeRef SuccVtx(SuccVtxIt->second, this); + NodeRef SuccVtx(SuccVtxNode, this); if (!SuccVtx.predecessor()) { - NodeAdjOwner[SuccVtxIt->second].PredecessorIdx = + NodeAdjOwner[SuccVtxNode].PredecessorIdx = PredId.value_or(Node::NoPredId); - NodeDataOwner[SuccVtxIt->second].Source = Curr; + NodeDataOwner[SuccVtxNode].Source = Curr; return; } @@ -379,8 +361,9 @@ template class ExplodedSuperGraph { [Pred = PredId.value_or(Node::NoPredId)](NodeRef Nd) { return Nd.predecessor().id() == Pred; })) { + auto NewNode = makeNode(); - NodeAdjOwner[SuccVtxIt->second].Neighbors.push_back(NewNode); + NodeAdjOwner[SuccVtxNode].Neighbors.push_back(NewNode); return; } } From 56ec0a6010dd11a482e08c9da7e655bf4eeda18a Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 25 Oct 2023 19:03:59 +0200 Subject: [PATCH 59/65] Add LLVMSSA version of pathsDagTo as temporary solution until f-IDESolverStrategy is merged --- .../PathSensitivityManagerMixin.h | 45 +++++++ .../PathSensitivity/PathTracingTest.cpp | 115 ++++++++++++++++-- 2 files changed, 150 insertions(+), 10 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h index c1da1baf9d..6a986d99c7 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -19,6 +19,7 @@ #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/DFAMinimizer.h" #include "phasar/Utils/GraphTraits.h" +#include "phasar/Utils/Printer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -32,6 +33,10 @@ #include #include +namespace llvm { +class DbgInfoIntrinsic; +} // namespace llvm + namespace psr { template class PathSensitivityManagerMixin { @@ -169,6 +174,46 @@ class PathSensitivityManagerMixin { PFilter); } + template < + typename ConfigTy, typename Filter = DefaultPathTracingFilter, + typename = std::enable_if_t>> + [[nodiscard]] GraphType + pathsDagToInLLVMSSA(n_t Inst, d_t Fact, + const PathSensitivityConfigBase &Config, + const Filter &PFilter = {}) const { + // Temporary code to bridge the time until merging f-IDESolverStrategy + // into development + if (Inst->getType()->isVoidTy()) { + return pathsDagToAll(Inst, llvm::ArrayRef(&Fact, 1), Config, PFilter); + } + + if (auto Next = Inst->getNextNonDebugInstruction()) { + return pathsDagToAll(Next, llvm::ArrayRef(&Fact, 1), Config, PFilter); + } + + PHASAR_LOG_LEVEL(WARNING, "[pathsDagToInLLVMSSA]: Cannot precisely " + "determine the ESG node for inst-flowfact-pair (" + << NToString(Inst) << ", " << DToString(Fact) + << "). Fall-back to an approximation"); + + for (const auto *BB : llvm::successors(Inst)) { + const auto *First = &BB->front(); + if (llvm::isa(First)) { + First = First->getNextNonDebugInstruction(); + } + if (ESG.getNodeOrNull(First, Fact)) { + return pathsDagToAll(First, llvm::ArrayRef(&Fact, 1), Config, PFilter); + } + } + + llvm::report_fatal_error("Could not determine any ESG node corresponding " + "to the inst-flowfact-pair (" + + llvm::Twine(NToString(Inst)) + ", " + + DToString(Fact) + ")"); + + return {}; + } + private: template bool pathsToImplLAInvoke(vertex_t Ret, NodeRef Vtx, PathsToContext &Ctx, diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp index f1a6b6366d..f8d92f2f3c 100644 --- a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp @@ -37,20 +37,15 @@ #include #include +namespace { // ============== TEST FIXTURE ============== // class PathTracingTest : public ::testing::Test { -protected: +public: static constexpr auto PathToLlFiles = PHASAR_BUILD_SUBFOLDER("path_tracing/"); - std::unique_ptr IRDB; - psr::LLVMPathConstraints LPC; - - void SetUp() override { psr::ValueAnnotationPass::resetValueID(); } - void TearDown() override { psr::Logger::disable(); } - - std::pair - getInterestingInstFact() { - auto *Main = IRDB->getFunctionDefinition("main"); + static std::pair + getInterestingInstFact(psr::LLVMProjectIRDB &IRDB) { + auto *Main = IRDB.getFunctionDefinition("main"); assert(Main); auto *LastInst = &Main->back().back(); auto *InterestingFact = [&] { @@ -71,6 +66,18 @@ class PathTracingTest : public ::testing::Test { return {LastInst, InterestingFact}; } +protected: + std::unique_ptr IRDB; + psr::LLVMPathConstraints LPC; + + void SetUp() override { psr::ValueAnnotationPass::resetValueID(); } + void TearDown() override { psr::Logger::disable(); } + + std::pair + getInterestingInstFact() { + return getInterestingInstFact(*IRDB); + } + psr::FlowPathSequence doAnalysis(const std::string &LlvmFilePath, bool PrintDump = false) { IRDB = std::make_unique(PathToLlFiles + LlvmFilePath); @@ -759,6 +766,94 @@ TEST(PathsDAGTest, ForwardMinimizeDAGTest) { 0); } +template +std::vector> getPaths(const GraphTy &G) { + std::vector> Ret; + std::vector Curr; + using traits_t = psr::GraphTraits; + auto doGetPaths = [&G, &Curr, &Ret](const auto &doGetPaths, + auto Vtx) -> void { + size_t Sz = Curr.size(); + for (const auto *N : traits_t::node(G, Vtx)) { + Curr.push_back(psr::getMetaDataID(N)); + } + bool HasSucc = false; + for (auto Edge : traits_t::outEdges(G, Vtx)) { + HasSucc = true; + doGetPaths(doGetPaths, traits_t::target(Edge)); + } + if (!HasSucc) { + Ret.push_back(Curr); + } + Curr.resize(Sz); + }; + + for (auto Rt : traits_t::roots(G)) { + doGetPaths(doGetPaths, Rt); + } + + return Ret; +} + +TEST(PathsDAGTest, InLLVMSSA) { + psr::LLVMProjectIRDB IRDB(PathTracingTest::PathToLlFiles + "inter_01_cpp.ll"); + psr::LLVMTypeHierarchy TH(IRDB); + psr::LLVMAliasSet PT(&IRDB); + psr::LLVMBasedICFG ICFG(&IRDB, psr::CallGraphAnalysisType::OTF, {"main"}, &TH, + &PT, psr::Soundness::Soundy, + /*IncludeGlobals*/ false); + psr::IDELinearConstantAnalysis LCAProblem(&IRDB, &ICFG, {"main"}); + psr::PathAwareIDESolver LCASolver(LCAProblem, &ICFG); + LCASolver.solve(); + // if (PrintDump) { + // // IRDB->print(); + // // ICFG.print(); + // // LCASolver.dumpResults(); + // std::error_code EC; + // llvm::raw_fd_ostream ROS(LlvmFilePath + "_explicit_esg.dot", EC); + // assert(!EC); + // LCASolver.getExplicitESG().printAsDot(ROS); + // } + auto [LastInst, InterestingFact] = + PathTracingTest::getInterestingInstFact(IRDB); + // llvm::outs() << "Target instruction: " << psr::llvmIRToString(LastInst); + // llvm::outs() << "\nTarget data-flow fact: " + // << psr::llvmIRToString(InterestingFact) << '\n'; + + const auto *InterestingFactInst = + llvm::dyn_cast(InterestingFact); + ASSERT_FALSE(InterestingFact->getType()->isVoidTy()); + ASSERT_NE(nullptr, InterestingFactInst); + + psr::PathSensitivityManager PSM( + &LCASolver.getExplicitESG()); + + auto Dag = PSM.pathsDagToInLLVMSSA(InterestingFactInst, InterestingFact, + psr::PathSensitivityConfig{}); + + // psr::printGraph(Dag, llvm::outs(), "", [](const auto &Node) { + // std::string Str; + // llvm::raw_string_ostream ROS(Str); + // ROS << '['; + // llvm::interleaveComma(Node, ROS, [&ROS](const auto *Inst) { + // ROS << psr::getMetaDataID(Inst); + // }); + // ROS << ']'; + + // return Str; + // }); + auto Paths = getPaths(Dag); + ASSERT_EQ(1, Paths.size()); + + // TODO: Should the "18" be removed? + std::vector Gt = {"17", "16", "5", "3", "2", "1", + "0", "15", "14", "13", "12", "11", + "10", "9", "8", "7", "6", "18"}; + EXPECT_EQ(Gt, Paths[0]); +} + +} // namespace + // main function for the test case int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); From b947c1e084910509090b1ca8f2c7f45932d0afa6 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 25 Oct 2023 19:40:23 +0200 Subject: [PATCH 60/65] minor --- .../PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp index f8d92f2f3c..0194d0eead 100644 --- a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp @@ -119,7 +119,7 @@ class PathTracingTest : public ::testing::Test { {"main"}, &TH, &PT, psr::Soundness::Soundy, /*IncludeGlobals*/ false); - psr::LLVMTaintConfig Config(*IRDB, nlohmann::json{}); + psr::LLVMTaintConfig Config(*IRDB); psr::IDEExtendedTaintAnalysis<3, false> Analysis(IRDB.get(), &ICFG, &PT, Config, {"main"}); psr::PathAwareIDESolver Solver(Analysis, &ICFG); From 1a15261d75e7eb6ba3263c325a5d77af2120b729 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 10 Nov 2023 09:07:38 +0100 Subject: [PATCH 61/65] Use system z3 --- .gitmodules | 4 -- CMakeLists.txt | 37 +++---------------- external/z3 | 1 - .../DataFlow/PathSensitivity/CMakeLists.txt | 2 +- .../DataFlow/PathSensitivity/CMakeLists.txt | 2 +- 5 files changed, 8 insertions(+), 38 deletions(-) delete mode 160000 external/z3 diff --git a/.gitmodules b/.gitmodules index 8d1e7f5f01..70653bf9e2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,3 @@ [submodule "external/json-schema-validator"] path = external/json-schema-validator url = https://github.com/pboettch/json-schema-validator.git -[submodule "external/z3"] - path = external/z3 - url = https://github.com/fabianbs96/z3 - branch = LLVMCompatibleZ3 diff --git a/CMakeLists.txt b/CMakeLists.txt index f1c9b243d7..f2dde3ae56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,7 +87,7 @@ endif(BUILD_SWIFT_TESTS) option(PHASAR_BUILD_OPENSSL_TS_UNITTESTS "Build OPENSSL typestate tests (require OpenSSL, default is OFF)" OFF) -option(PHASAR_USE_Z3 "Build the phasar_llvm_pathsensitivity library with Z3 support for constraint solving (default is ON as long as we are building out of tree)" ON) +option(PHASAR_USE_Z3 "Build the phasar_llvm_pathsensitivity library with Z3 support for constraint solving (default is OFF)" OFF) option(PHASAR_BUILD_IR "Build IR test code (default is ON)" ON) @@ -242,37 +242,12 @@ endif() add_definitions(${LLVM_DEFINITIONS}) # Z3 Solver + if(PHASAR_USE_Z3) - if(NOT Z3_FOUND) - # Z3 does not compile with '-Werror', so disable it for Z3's build - # string(REPLACE "-Werror" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - - # Do not pass DebugSan to z3 as it is unable to handle it - if(CMAKE_BUILD_TYPE STREQUAL "DebugSan") - set(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3 ON) - set(CMAKE_BUILD_TYPE "Debug") - endif() - - # Convince z3 to install its library along with phasar libs - # To avoid possible side effects we only change CMAKE_INSTALL_LIBDIR - # for including z3 (here) and restore it afterwards - set(ORIGINAL_CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) - set(CMAKE_INSTALL_LIBDIR ${PHASAR_INSTALL_LIBDIR}) - add_subdirectory(external/z3/) - set(CMAKE_INSTALL_LIBDIR ${ORIGINAL_CMAKE_INSTALL_LIBDIR}) - - if(CMAKE_BUILD_TYPE_ADAPTED_FOR_Z3) - set(CMAKE_BUILD_TYPE "DebugSan") - endif() - - include_directories(external/z3/src/) - include_directories(external/z3/src/api/) - include_directories(external/z3/src/api/c++/) - link_directories(${Z3_BINARY_DIR}) - link_directories(${Z3_BINARY_DIR}/src) - - # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") - endif() + # This z3-version is the same version LLVM requires; however, we cannot just use Z3 via the LLVM interface + # as it lacks some functionality (such as z3::expr::simplify()) that we require + find_package(Z3 4.7.1 REQUIRED) + include_directories(${Z3_INCLUDE_DIR}) endif(PHASAR_USE_Z3) if(NOT PHASAR_IN_TREE) diff --git a/external/z3 b/external/z3 deleted file mode 160000 index 7b64f84b10..0000000000 --- a/external/z3 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7b64f84b10ffb7ac9b5b3ddf5acac53859d0777c diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index 78699965ea..9a02c27eae 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -28,7 +28,7 @@ set(PHASAR_LINK_LIBS ) if(PHASAR_USE_Z3) - list(APPEND PHASAR_LINK_LIBS libz3) + list(APPEND PHASAR_LINK_LIBS ${Z3_LIBRARIES}) endif() set(LLVM_LINK_COMPONENTS diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index d97887c3df..11f6cc1e5d 100644 --- a/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -4,6 +4,6 @@ if(PHASAR_USE_Z3) target_link_libraries(PathTracingTest LINK_PUBLIC phasar_llvm_pathsensitivity - libz3 # -- the Z3 cmake target is named libz3, so we want to have it as dependency, not just as link-target + ${Z3_LIBRARIES} ) endif() From 57b0f815f4ce949e6424bb219d892d9d3913a0bb Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 15 Nov 2023 13:46:12 +0100 Subject: [PATCH 62/65] Find z3 from psr installation --- CMakeLists.txt | 2 +- Config.cmake.in | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8513cb2164..38299b52d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.9) +cmake_minimum_required (VERSION 3.14) # Avoid IPO/LTO Warnings: cmake_policy(SET CMP0069 NEW) diff --git a/Config.cmake.in b/Config.cmake.in index 98d5c07c78..e0efbc22c7 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -13,6 +13,11 @@ find_package(LLVM 14 REQUIRED CONFIG) set(PHASAR_USE_LLVM_FAT_LIB @USE_LLVM_FAT_LIB@) set(PHASAR_BUILD_DYNLIB @PHASAR_BUILD_DYNLIB@) +set(PHASAR_USE_Z3 @PHASAR_USE_Z3@) + +if (PHASAR_USE_Z3) + find_dependency(Z3) +endif() # TODO: The order seems to be important in the include'ing loop below. Fix this! From f7402d35276bf959f3aee591a160057383e9ce04 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 19 Nov 2023 12:35:58 +0100 Subject: [PATCH 63/65] Assert size overflow --- .../DataFlow/PathSensitivity/PathSensitivityManagerBase.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h index 0c2ec0afe6..e1195bb573 100644 --- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h @@ -106,9 +106,10 @@ template class PathSensitivityManagerBase { // WLInsert. This way, we can stop the process, when we have reached the // MaxDepth - auto NumBytes = - (sizeof(vertex_t) + 2 * sizeof(std::pair)) * - EquivSize; + constexpr auto Factor = + sizeof(vertex_t) + 2 * sizeof(std::pair); + assert(EquivSize <= SIZE_MAX / Factor && "Overflow on size calculation"); + auto NumBytes = Factor * EquivSize; // For performance reasons, we wish to allocate the buffer on the stack, if // it is small enough From d9a0fee1a5845843b22dd8ae28eb89937b22d157 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 19 Nov 2023 12:36:53 +0100 Subject: [PATCH 64/65] Enable Z3 in CI --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d109a180f3..f5e1650543 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,7 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.build }} \ -DBUILD_SWIFT_TESTS=ON \ -DPHASAR_DEBUG_LIBDEPS=ON \ + -DPHASAR_ENABLE_Z3=ON \ ${{ matrix.flags }} \ -G Ninja cmake --build . From a478f9bd6cd886235b1ce537675f2711569b98c0 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 19 Nov 2023 12:39:59 +0100 Subject: [PATCH 65/65] fix naming issue --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5e1650543..67a32f1a53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.build }} \ -DBUILD_SWIFT_TESTS=ON \ -DPHASAR_DEBUG_LIBDEPS=ON \ - -DPHASAR_ENABLE_Z3=ON \ + -DPHASAR_USE_Z3=ON \ ${{ matrix.flags }} \ -G Ninja cmake --build .