From 290f455410b07106d411e7195dac47b39bb9fb58 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 20 Apr 2023 10:44:33 +0200 Subject: [PATCH 01/59] Consume solver results (#608) * Change solver-config default to not implicitly record the ESG edges anymore * Allow moving the SolverResults out of the IDESolver * Move some more results code from IDESolver to SolverResults --- .../DataFlow/IfdsIde/IFDSIDESolverConfig.h | 5 +- .../DataFlow/IfdsIde/Solver/IDESolver.h | 123 +++------ .../DataFlow/IfdsIde/Solver/IFDSSolver.h | 26 +- .../phasar/DataFlow/IfdsIde/SolverResults.h | 233 ++++++++++++++++-- include/phasar/Utils/Printer.h | 15 +- tools/example-tool/myphasartool.cpp | 7 +- 6 files changed, 279 insertions(+), 130 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h b/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h index e402ada1c..b3f949364 100644 --- a/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h +++ b/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h @@ -63,9 +63,8 @@ struct IFDSIDESolverConfig { const IFDSIDESolverConfig &SC); private: - SolverConfigOptions Options = SolverConfigOptions::AutoAddZero | - SolverConfigOptions::ComputeValues | - SolverConfigOptions::RecordEdges; + SolverConfigOptions Options = + SolverConfigOptions::AutoAddZero | SolverConfigOptions::ComputeValues; }; } // namespace psr diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 555a69bf5..4564a2489 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -50,14 +50,7 @@ #include #include -namespace llvm { -class Instruction; -class Value; -} // namespace llvm - namespace psr { -// For sorting the results in dumpResults() -std::string getMetaDataID(const llvm::Value *V); /// Solves the given IDETabulationProblem as described in the 1996 paper by /// Sagiv, Horwitz and Reps. To solve the problem, call solve(). Results @@ -180,8 +173,8 @@ class IDESolver { } /// Returns the L-type result for the given value at the given statement. - [[nodiscard]] virtual l_t resultAt(n_t Stmt, d_t Value) { - return ValTab.get(Stmt, Value); + [[nodiscard]] l_t resultAt(n_t Stmt, d_t Value) { + return getSolverResults().resultAt(Stmt, Value); } /// Returns the L-type result at the given statement for the given data-flow @@ -203,11 +196,7 @@ class IDESolver { [[nodiscard]] typename std::enable_if_t< std::is_same_v, llvm::Instruction *>, l_t> resultAtInLLVMSSA(NTy Stmt, d_t Value) { - if (Stmt->getType()->isVoidTy()) { - return ValTab.get(Stmt, Value); - } - assert(Stmt->getNextNode() && "Expected to find a valid successor node!"); - return ValTab.get(Stmt->getNextNode(), Value); + return getSolverResults().resultAtInLLVMSSA(Stmt, Value); } /// Returns the resulting environment for the given statement. @@ -215,17 +204,7 @@ class IDESolver { /// TOP values are never returned. [[nodiscard]] virtual std::unordered_map resultsAt(n_t Stmt, bool StripZero = false) /*TODO const*/ { - std::unordered_map Result = ValTab.row(Stmt); - if (StripZero) { - for (auto It = Result.begin(); It != Result.end();) { - if (IDEProblem.isZeroValue(It->first)) { - It = Result.erase(It); - } else { - ++It; - } - } - } - return Result; + return getSolverResults().resultsAt(Stmt, StripZero); } /// Returns the data-flow results at the given statement while respecting @@ -248,23 +227,7 @@ class IDESolver { std::is_same_v, llvm::Instruction *>, std::unordered_map> resultsAtInLLVMSSA(NTy Stmt, bool StripZero = false) { - std::unordered_map Result = [this, Stmt]() { - if (Stmt->getType()->isVoidTy()) { - return ValTab.row(Stmt); - } - return ValTab.row(Stmt->getNextNode()); - }(); - if (StripZero) { - // TODO: replace with std::erase_if (C++20) - for (auto It = Result.begin(); It != Result.end();) { - if (IDEProblem.isZeroValue(It->first)) { - It = Result.erase(It); - } else { - ++It; - } - } - } - return Result; + return getSolverResults().resultsAtInLLVMSSA(Stmt, StripZero); } virtual void emitTextReport(llvm::raw_ostream &OS = llvm::outs()) { @@ -276,49 +239,7 @@ class IDESolver { } void dumpResults(llvm::raw_ostream &OS = llvm::outs()) { - PAMM_GET_INSTANCE; - START_TIMER("DFA IDE Result Dumping", PAMM_SEVERITY_LEVEL::Full); - OS << "\n***************************************************************\n" - << "* Raw IDESolver results *\n" - << "***************************************************************\n"; - auto Cells = this->ValTab.cellVec(); - if (Cells.empty()) { - OS << "No results computed!" << '\n'; - } else { - std::sort( - Cells.begin(), Cells.end(), [](const auto &Lhs, const auto &Rhs) { - if constexpr (std::is_same_v) { - return StringIDLess{}(getMetaDataID(Lhs.getRowKey()), - getMetaDataID(Rhs.getRowKey())); - } else { - // If non-LLVM IR is used - return Lhs.getRowKey() < Rhs.getRowKey(); - } - }); - n_t Prev = n_t{}; - n_t Curr = n_t{}; - f_t PrevFn = f_t{}; - f_t CurrFn = f_t{}; - for (unsigned I = 0; I < Cells.size(); ++I) { - Curr = Cells[I].getRowKey(); - CurrFn = ICF->getFunctionOf(Curr); - if (PrevFn != CurrFn) { - PrevFn = CurrFn; - OS << "\n\n============ Results for function '" + - ICF->getFunctionName(CurrFn) + "' ============\n"; - } - if (Prev != Curr) { - Prev = Curr; - std::string NString = IDEProblem.NtoString(Curr); - std::string Line(NString.size(), '-'); - OS << "\n\nN: " << NString << "\n---" << Line << '\n'; - } - OS << "\tD: " << IDEProblem.DtoString(Cells[I].getColumnKey()) - << " | V: " << IDEProblem.LtoString(Cells[I].getValue()) << '\n'; - } - } - OS << '\n'; - STOP_TIMER("DFA IDE Result Dumping", PAMM_SEVERITY_LEVEL::Full); + getSolverResults().dumpResults(*ICF, IDEProblem, OS); } void dumpAllInterPathEdges() { @@ -361,9 +282,24 @@ class IDESolver { } } - SolverResults getSolverResults() { - return SolverResults(this->ValTab, - IDEProblem.getZeroValue()); + /// Returns a view into the computed solver-results. + /// + /// NOTE: The SolverResults store a reference into this IDESolver, so its + /// lifetime is also bound to the lifetime of this solver. If you want to use + /// the solverResults beyond the lifetime of this solver, use + /// comsumeSolverResults() instead. + [[nodiscard]] SolverResults getSolverResults() noexcept { + return SolverResults(this->ValTab, ZeroValue); + } + + /// Moves the computed solver-results out of this solver such that the solver + /// can be destroyed without that the analysis results are lost. + /// Do not call any function (including getSolverResults()) on this IDESolver + /// instance after that. + [[nodiscard]] OwningSolverResults + consumeSolverResults() noexcept(std::is_nothrow_move_constructible_v) { + return OwningSolverResults(std::move(this->ValTab), + std::move(ZeroValue)); } protected: @@ -1818,6 +1754,17 @@ template using IDESolver_P = IDESolver; +template +OwningSolverResults +solveIDEProblem(IDETabulationProblem &Problem, + const typename AnalysisDomainTy::i_t &ICF) { + IDESolver Solver(Problem, &ICF); + Solver.solve(); + return Solver.consumeSolverResults(); +} + } // namespace psr #endif diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h index f9ed15d76..60f4bb892 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h @@ -28,8 +28,10 @@ namespace psr { -template -class IFDSSolver : public IDESolver> { +template > +class IFDSSolver + : public IDESolver, Container> { public: using ProblemTy = IFDSTabulationProblem; using d_t = typename AnalysisDomainTy::d_t; @@ -39,7 +41,8 @@ class IFDSSolver : public IDESolver> { template >> - IFDSSolver(IFDSTabulationProblem &IFDSProblem, const i_t *ICF) + IFDSSolver(IFDSTabulationProblem &IFDSProblem, + const i_t *ICF) : IDESolver>(IFDSProblem, ICF) {} virtual ~IFDSSolver() = default; @@ -96,10 +99,23 @@ class IFDSSolver : public IDESolver> { template IFDSSolver(Problem &, ICF *) - -> IFDSSolver; + -> IFDSSolver; template -using IFDSSolver_P = IFDSSolver; +using IFDSSolver_P = IFDSSolver; + +template +OwningSolverResults +solveIFDSProblem(IFDSTabulationProblem &Problem, + const typename AnalysisDomainTy::i_t &ICF) { + IFDSSolver Solver(Problem, &ICF); + Solver.solve(); + return Solver.consumeSolverResults(); +} } // namespace psr diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 85f9aade7..0e760878c 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -19,60 +19,243 @@ #include "phasar/Domain/BinaryDomain.h" #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/PAMMMacros.h" +#include "phasar/Utils/Printer.h" #include "phasar/Utils/Table.h" +#include "phasar/Utils/Utilities.h" #include #include #include #include -namespace psr { +namespace llvm { +class Instruction; +class Value; +} // namespace llvm -template class SolverResults { -private: - Table &Results; - D ZV; +namespace psr { +// For sorting the results in dumpResults() +std::string getMetaDataID(const llvm::Value *V); +namespace detail { +template +class SolverResultsBase { public: - SolverResults(Table &ResTab, D ZV) : Results(ResTab), ZV(ZV) {} + using n_t = N; + using d_t = D; + using l_t = L; - ByConstRef resultAt(ByConstRef Stmt, ByConstRef Node) const { - return Results.get(Stmt, Node); + [[nodiscard]] ByConstRef resultAt(ByConstRef Stmt, + ByConstRef Node) const { + return self().Results.get(Stmt, Node); } - std::unordered_map resultsAt(ByConstRef Stmt, - bool StripZero = false) const { - std::unordered_map Result = Results.row(Stmt); + [[nodiscard]] std::unordered_map + resultsAt(ByConstRef Stmt, bool StripZero = false) const { + std::unordered_map Result = self().Results.row(Stmt); if (StripZero) { - for (auto It = Result.begin(); It != Result.end();) { - if (It->first == ZV) { - It = Result.erase(It); - } else { - ++It; - } - } + Result.erase(self().ZV); } return Result; } // this function only exists for IFDS problems which use BinaryDomain as their // value domain L - template >> - std::set ifdsResultsAt(ByConstRef Stmt) const { + [[nodiscard]] std::set ifdsResultsAt(ByConstRef Stmt) const { std::set KeySet; - std::unordered_map ResultMap = this->resultsAt(Stmt); - for (auto FlowFact : ResultMap) { - KeySet.insert(FlowFact.first); + const auto &ResultMap = self().Results.row(Stmt); + for (const auto &[FlowFact, Val] : ResultMap) { + KeySet.insert(FlowFact); } return KeySet; } - [[nodiscard]] std::vector::Cell> + /// Returns the data-flow results at the given statement while respecting + /// LLVM's SSA semantics. + /// + /// An example: when a value is loaded and the location loaded from, here + /// variable 'i', is a data-flow fact that holds, then the loaded value '%0' + /// will usually be generated and also holds. However, due to the underlying + /// theory (and respective implementation) this load instruction causes the + /// loaded value to be generated and thus, it will be valid only AFTER the + /// load instruction, i.e., at the successor instruction. + /// + /// %0 = load i32, i32* %i, align 4 + /// + /// This result accessor function returns the results at the successor + /// instruction(s) reflecting that the expression on the left-hand side holds + /// if the expression on the right-hand side holds. + template + [[nodiscard]] typename std::enable_if_t< + std::is_same_v>, + llvm::Instruction>, + std::unordered_map> + resultsAtInLLVMSSA(ByConstRef Stmt, bool StripZero = false) { + std::unordered_map Result = [this, Stmt]() { + if (Stmt->getType()->isVoidTy()) { + return self().Results.row(Stmt); + } + assert(Stmt->getNextNode() && "Expected to find a valid successor node!"); + return self().Results.row(Stmt->getNextNode()); + }(); + if (StripZero) { + Result.erase(self().ZV); + } + return Result; + } + + /// Returns the L-type result at the given statement for the given data-flow + /// fact while respecting LLVM's SSA semantics. + /// + /// An example: when a value is loaded and the location loaded from, here + /// variable 'i', is a data-flow fact that holds, then the loaded value '%0' + /// will usually be generated and also holds. However, due to the underlying + /// theory (and respective implementation) this load instruction causes the + /// loaded value to be generated and thus, it will be valid only AFTER the + /// load instruction, i.e., at the successor instruction. + /// + /// %0 = load i32, i32* %i, align 4 + /// + /// This result accessor function returns the results at the successor + /// instruction(s) reflecting that the expression on the left-hand side holds + /// if the expression on the right-hand side holds. + template + [[nodiscard]] typename std::enable_if_t< + std::is_same_v>, + llvm::Instruction>, + l_t> + resultAtInLLVMSSA(ByConstRef Stmt, d_t Value) { + if (Stmt->getType()->isVoidTy()) { + return self().Results.get(Stmt, Value); + } + assert(Stmt->getNextNode() && "Expected to find a valid successor node!"); + return self().Results.get(Stmt->getNextNode(), Value); + } + + [[nodiscard]] std::vector::Cell> getAllResultEntries() const { - return Results.cellVec(); + return self().Results.cellVec(); } + + template + void dumpResults(const ICFGTy &ICF, const NodePrinterBase &NP, + const DataFlowFactPrinterBase &DP, + const EdgeFactPrinterBase &LP, + llvm::raw_ostream &OS = llvm::outs()) { + using f_t = typename ICFGTy::f_t; + + PAMM_GET_INSTANCE; + START_TIMER("DFA IDE Result Dumping", PAMM_SEVERITY_LEVEL::Full); + OS << "\n***************************************************************\n" + << "* Raw IDESolver results *\n" + << "***************************************************************\n"; + auto Cells = self().Results.cellVec(); + if (Cells.empty()) { + OS << "No results computed!" << '\n'; + } else { + std::sort( + Cells.begin(), Cells.end(), [](const auto &Lhs, const auto &Rhs) { + if constexpr (std::is_same_v) { + return StringIDLess{}(getMetaDataID(Lhs.getRowKey()), + getMetaDataID(Rhs.getRowKey())); + } else { + // If non-LLVM IR is used + return Lhs.getRowKey() < Rhs.getRowKey(); + } + }); + n_t Prev = n_t{}; + n_t Curr = n_t{}; + f_t PrevFn = f_t{}; + f_t CurrFn = f_t{}; + for (unsigned I = 0; I < Cells.size(); ++I) { + Curr = Cells[I].getRowKey(); + CurrFn = ICF.getFunctionOf(Curr); + if (PrevFn != CurrFn) { + PrevFn = CurrFn; + OS << "\n\n============ Results for function '" + + ICF.getFunctionName(CurrFn) + "' ============\n"; + } + if (Prev != Curr) { + Prev = Curr; + std::string NString = NP.NtoString(Curr); + std::string Line(NString.size(), '-'); + OS << "\n\nN: " << NString << "\n---" << Line << '\n'; + } + OS << "\tD: " << DP.DtoString(Cells[I].getColumnKey()) + << " | V: " << LP.LtoString(Cells[I].getValue()) << '\n'; + } + } + OS << '\n'; + STOP_TIMER("DFA IDE Result Dumping", PAMM_SEVERITY_LEVEL::Full); + } + + template + void dumpResults(const ICFGTy &ICF, const ProblemTy &IDEProblem, + llvm::raw_ostream &OS = llvm::outs()) { + dumpResults(ICF, IDEProblem, IDEProblem, IDEProblem, OS); + } + +private: + [[nodiscard]] Derived &self() noexcept { + static_assert(std::is_base_of_v); + return static_cast(*this); + } + [[nodiscard]] const Derived &self() const noexcept { + static_assert(std::is_base_of_v); + return static_cast(*this); + } +}; +} // namespace detail + +template +class SolverResults + : public detail::SolverResultsBase, N, D, L> { + using base_t = detail::SolverResultsBase, N, D, L>; + friend base_t; + +public: + using typename base_t::d_t; + using typename base_t::l_t; + using typename base_t::n_t; + + SolverResults(Table &ResTab, ByConstRef ZV) noexcept + : Results(ResTab), ZV(ZV) {} + SolverResults(Table &&ResTab, ByConstRef ZV) = delete; + +private: + Table &Results; + ByConstRef ZV; +}; + +template +class OwningSolverResults + : public detail::SolverResultsBase, N, D, L> { + using base_t = + detail::SolverResultsBase, N, D, L>; + friend base_t; + +public: + using typename base_t::d_t; + using typename base_t::l_t; + using typename base_t::n_t; + + OwningSolverResults(Table ResTab, + D ZV) noexcept(std::is_nothrow_move_constructible_v) + : Results(std::move(ResTab)), ZV(ZV) {} + + [[nodiscard]] operator SolverResults() const &noexcept { + return {Results, ZV}; + } + operator SolverResults() && = delete; + +private: + // psr::Table is not const-enabled, so we have to give out mutable references + mutable Table Results; + D ZV; }; } // namespace psr diff --git a/include/phasar/Utils/Printer.h b/include/phasar/Utils/Printer.h index c30e21401..fae88ba2f 100644 --- a/include/phasar/Utils/Printer.h +++ b/include/phasar/Utils/Printer.h @@ -72,18 +72,21 @@ template struct TypePrinter { } }; -template struct EdgeFactPrinter { - using l_t = typename AnalysisDomainTy::l_t; +template struct EdgeFactPrinterBase { + using l_t = L; - virtual ~EdgeFactPrinter() = default; + virtual ~EdgeFactPrinterBase() = default; - virtual void printEdgeFact(llvm::raw_ostream &OS, l_t L) const = 0; + virtual void printEdgeFact(llvm::raw_ostream &OS, l_t Val) const = 0; - [[nodiscard]] std::string LtoString(l_t L) const { // NOLINT - return toStringBuilder(&EdgeFactPrinter::printEdgeFact, this, L); + [[nodiscard]] std::string LtoString(l_t Val) const { // NOLINT + return toStringBuilder(&EdgeFactPrinterBase::printEdgeFact, this, Val); } }; +template +using EdgeFactPrinter = EdgeFactPrinterBase; + template struct FunctionPrinter { using F = typename AnalysisDomainTy::f_t; diff --git a/tools/example-tool/myphasartool.cpp b/tools/example-tool/myphasartool.cpp index 9d82236d1..fbfc269c6 100644 --- a/tools/example-tool/myphasartool.cpp +++ b/tools/example-tool/myphasartool.cpp @@ -57,9 +57,10 @@ int main(int Argc, const char **Argv) { llvm::outs() << "Testing IDE:\n"; auto M = createAnalysisProblem(HA, EntryPoints); - IDESolver T(M, &HA.getICFG()); - T.solve(); - T.dumpResults(); + // Alternative way of solving an IFDS/IDEProblem: + auto IDEResults = solveIDEProblem(M, HA.getICFG()); + IDEResults.dumpResults(HA.getICFG(), M); + } else { llvm::errs() << "error: file does not contain a 'main' function!\n"; } From 7a8b476acdec8a51e86d4ce7fff747e37567326c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 20 Apr 2023 11:13:48 +0200 Subject: [PATCH 02/59] The fix (#609) --- include/phasar/Utils/Logger.h | 52 +++++++++++++++++++++------------- unittests/Utils/CMakeLists.txt | 4 +++ unittests/Utils/LoggerTest.cpp | 28 ++++++++++++++++++ 3 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 unittests/Utils/LoggerTest.cpp diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index 9dc9306b4..7ffdfdc2d 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -105,43 +105,51 @@ class Logger final { computation; \ } -#define IS_LOG_ENABLED Logger::isLoggingEnabled() +#define IS_LOG_ENABLED ::psr::Logger::isLoggingEnabled() #define IF_LOG_ENABLED(computation) \ - IF_LOG_ENABLED_BOOL(Logger::isLoggingEnabled(), computation) + IF_LOG_ENABLED_BOOL(::psr::Logger::isLoggingEnabled(), computation) #define PHASAR_LOG_LEVEL(level, message) \ IF_LOG_ENABLED_BOOL( \ - Logger::isLoggingEnabled() && (level) >= Logger::getLoggerFilterLevel(), \ + ::psr::Logger::isLoggingEnabled() && \ + (::psr::SeverityLevel::level) >= \ + ::psr::Logger::getLoggerFilterLevel(), \ do { \ - auto &S = Logger::getLogStream(level, std::nullopt); \ - Logger::addLinePrefix(S, level, std::nullopt); \ + auto &Stream = ::psr::Logger::getLogStream( \ + ::psr::SeverityLevel::level, std::nullopt); \ + ::psr::Logger::addLinePrefix(Stream, ::psr::SeverityLevel::level, \ + std::nullopt); \ /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - S << message << '\n'; \ + Stream << message << '\n'; \ } while (false);) #define PHASAR_LOG(message) PHASAR_LOG_LEVEL(DEBUG, message) #define PHASAR_LOG_LEVEL_CAT(level, cat, message) \ IF_LOG_ENABLED_BOOL( \ - Logger::isLoggingEnabled() && \ - (level) >= Logger::getLoggerFilterLevel() && \ - Logger::logCategory(cat, level), \ + ::psr::Logger::isLoggingEnabled() && \ + (::psr::SeverityLevel::level) >= \ + ::psr::Logger::getLoggerFilterLevel() && \ + ::psr::Logger::logCategory(cat, ::psr::SeverityLevel::level), \ do { \ - auto &S = Logger::getLogStream(level, cat); \ - Logger::addLinePrefix(S, level, cat); \ + auto &Stream = \ + ::psr::Logger::getLogStream(::psr::SeverityLevel::level, cat); \ + ::psr::Logger::addLinePrefix(Stream, ::psr::SeverityLevel::level, \ + cat); \ /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - S << message << '\n'; \ + Stream << message << '\n'; \ } while (false);) #define PHASAR_LOG_CAT(cat, message) \ IF_LOG_ENABLED_BOOL( \ - Logger::isLoggingEnabled() && Logger::logCategory(cat, std::nullopt), \ + ::psr::Logger::isLoggingEnabled() && \ + ::psr::Logger::logCategory(cat, std::nullopt), \ do { \ - auto &S = Logger::getLogStream(std::nullopt, cat); \ - Logger::addLinePrefix(S, std::nullopt, cat); \ + auto &Stream = ::psr::Logger::getLogStream(std::nullopt, cat); \ + ::psr::Logger::addLinePrefix(Stream, std::nullopt, cat); \ /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - S << message << '\n'; \ + Stream << message << '\n'; \ } while (false);) #else @@ -149,10 +157,14 @@ class Logger final { {} #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) -#define PHASAR_LOG_LEVEL(level, message) ((void)0) +#define PHASAR_LOG(computation) \ + {} +#define PHASAR_LOG_CAT(cat, message) \ + {} +#define PHASAR_LOG_LEVEL_CAT(level, cat, message) \ + {} +#define PHASAR_LOG_LEVEL(level, message) \ + {} #define IS_LOG_ENABLED false #endif diff --git a/unittests/Utils/CMakeLists.txt b/unittests/Utils/CMakeLists.txt index b40a6f5e8..4edc79c48 100644 --- a/unittests/Utils/CMakeLists.txt +++ b/unittests/Utils/CMakeLists.txt @@ -8,6 +8,10 @@ set(UtilsSources StableVectorTest.cpp ) +if(PHASAR_ENABLE_DYNAMIC_LOG) + list(APPEND UtilsSources LoggerTest.cpp) +endif() + foreach(TEST_SRC ${UtilsSources}) add_phasar_unittest(${TEST_SRC}) endforeach(TEST_SRC) diff --git a/unittests/Utils/LoggerTest.cpp b/unittests/Utils/LoggerTest.cpp new file mode 100644 index 000000000..ea25511e6 --- /dev/null +++ b/unittests/Utils/LoggerTest.cpp @@ -0,0 +1,28 @@ +#include "phasar/Utils/Logger.h" + +#include "gtest/gtest.h" + +TEST(LoggerTest, BasicWithinPsr) { + using namespace psr; + Logger::initializeStderrLogger(SeverityLevel::INFO); + Logger::initializeStderrLogger(SeverityLevel::DEBUG, "LLVMAliasSet"); + PHASAR_LOG("This should not be shown"); + PHASAR_LOG_LEVEL(INFO, "Basic category-less message"); + PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMAliasSet", + "Some message specific to LLVMAliasSet"); +} + +TEST(LoggerTest, BasicOutsidePsr) { + psr::Logger::initializeStderrLogger(psr::SeverityLevel::INFO); + psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + "LLVMAliasSet"); + PHASAR_LOG("This should not be shown"); + PHASAR_LOG_LEVEL(INFO, "Basic category-less message"); + PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMAliasSet", + "Some message specific to LLVMAliasSet"); +} + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} From 710ef6607e7e4d635a8ef73485dbaf9f9b5ca4f4 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 20 Apr 2023 11:14:22 +0200 Subject: [PATCH 03/59] Update bootstrap.h to work properly when boost is not already installed (#612) --- bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index c49d0a728..2b5bfe397 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -84,7 +84,7 @@ if [ ! -z "${DESIRED_BOOST_DIR}" ]; then else # New way of installing boost: # Check whether we have the required boost packages installed - BOOST_VERSION=$(echo -e '#include \nBOOST_LIB_VERSION' | gcc -s -x c++ -E - 2>/dev/null| grep "^[^#;]" | tr -d '\"') + (BOOST_VERSION=$(echo -e '#include \nBOOST_LIB_VERSION' | gcc -s -x c++ -E - 2>/dev/null| grep "^[^#;]" | tr -d '\"')) || true if [ -z "$BOOST_VERSION" ] ;then if [ -x "$(command -v pacman)" ]; then From 88e42a2f79dc521e8a58d17e24dc6dcf62fc109e Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 4 May 2023 07:59:58 +0200 Subject: [PATCH 04/59] Ref-counted ModuleSlotTracker (#614) * Make the ModuleSlotTracker ref-counted * minor --- .gitignore | 1 + lib/PhasarLLVM/Utils/LLVMShorthands.cpp | 42 +++++++++++++++++++------ unittests/Utils/LLVMShorthandsTest.cpp | 19 +++++++++++ 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index f175263c3..1cc71e473 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ bin/* # build directories for cmake build/ build_*/ +build-*/ # LLVM project llvm-project/* diff --git a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp index 772bd9629..62672afab 100644 --- a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp +++ b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -504,32 +505,44 @@ llvm::StringRef getVarAnnotationIntrinsicName(const llvm::CallInst *CallInst) { return Data->getAsCString(); } +struct PhasarModuleSlotTrackerWrapper { + PhasarModuleSlotTrackerWrapper(const llvm::Module *M) : MST(M) {} + + llvm::ModuleSlotTracker MST; + size_t RefCount = 0; +}; + static llvm::SmallDenseMap, 2> + std::unique_ptr, 2> MToST{}; +static std::mutex MSTMx; + llvm::ModuleSlotTracker & ModulesToSlotTracker::getSlotTrackerForModule(const llvm::Module *M) { + std::lock_guard Lck(MSTMx); + auto &Ret = MToST[M]; if (M == nullptr && Ret == nullptr) { - Ret = std::make_unique(M); + Ret = std::make_unique(M); + Ret->RefCount++; } assert(Ret != nullptr && "no ModuleSlotTracker instance for module cached"); - return *Ret; + return Ret->MST; } void ModulesToSlotTracker::setMSTForModule(const llvm::Module *M) { + std::lock_guard Lck(MSTMx); + auto [It, Inserted] = MToST.try_emplace(M, nullptr); - if (!Inserted) { - llvm::report_fatal_error( - "Cannot register the same module twice in the ModulesToSlotTracker! " - "Probably you have managed the same LLVM Module with multiple " - "ProjectIRDB instances at the same time. Don't do that!"); + if (Inserted) { + It->second = std::make_unique(M); } - It->second = std::make_unique(M); + It->second->RefCount++; } void ModulesToSlotTracker::updateMSTForModule(const llvm::Module *Module) { + std::lock_guard Lck(MSTMx); auto It = MToST.find(Module); if (It == MToST.end()) { llvm::report_fatal_error( @@ -541,7 +554,16 @@ void ModulesToSlotTracker::updateMSTForModule(const llvm::Module *Module) { } void ModulesToSlotTracker::deleteMSTForModule(const llvm::Module *M) { - MToST.erase(M); + std::lock_guard Lck(MSTMx); + + auto It = MToST.find(M); + if (It == MToST.end()) { + return; + } + + if (--It->second->RefCount == 0) { + MToST.erase(It); + } } } // namespace psr diff --git a/unittests/Utils/LLVMShorthandsTest.cpp b/unittests/Utils/LLVMShorthandsTest.cpp index d6104664c..2c19ff675 100644 --- a/unittests/Utils/LLVMShorthandsTest.cpp +++ b/unittests/Utils/LLVMShorthandsTest.cpp @@ -4,6 +4,7 @@ #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" @@ -43,6 +44,24 @@ TEST(LLVMGetterTest, HandlesLLVMTermInstruction) { ASSERT_EQ(getNthTermInstruction(F, 5), nullptr); } +TEST(SlotTrackerTest, HandleTwoReferences) { + LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + + "control_flow/global_stmt_cpp.ll"); + + const auto *F = IRDB.getFunctionDefinition("main"); + + ASSERT_NE(F, nullptr); + const auto *Inst = getNthInstruction(F, 6); + llvm::StringRef InstStr = "%0 = load i32, i32* @i, align 4 | ID: 6"; + { + LLVMProjectIRDB IRDB2(IRDB.getModule()); + + EXPECT_EQ(llvmIRToStableString(Inst), InstStr); + } + + EXPECT_EQ(llvmIRToStableString(Inst), InstStr); +} + int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); return RUN_ALL_TESTS(); From 0309ccb40871c87f60bdf8b5d9db8cce891980eb Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 4 May 2023 08:26:01 +0200 Subject: [PATCH 05/59] Misc fixes (#615) * Fix some bugs * Add utils to LLVMIRToSrc * Make the Container type parameter of the flow function templates actually settable * Fix recursive template instantiation in C++20 mode * feat: boolean to toggle trim --------- Co-authored-by: Sriteja Kummita --- include/phasar/DB/ProjectIRDBBase.h | 2 +- .../phasar/DataFlow/IfdsIde/EdgeFunction.h | 4 +- .../phasar/DataFlow/IfdsIde/FlowFunctions.h | 23 +++-- include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h | 25 +++-- include/phasar/Utils/MaybeUniquePtr.h | 2 +- lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp | 92 +++++++++++-------- 6 files changed, 86 insertions(+), 62 deletions(-) diff --git a/include/phasar/DB/ProjectIRDBBase.h b/include/phasar/DB/ProjectIRDBBase.h index 78c946417..092019686 100644 --- a/include/phasar/DB/ProjectIRDBBase.h +++ b/include/phasar/DB/ProjectIRDBBase.h @@ -112,7 +112,7 @@ template class ProjectIRDBBase { /// module for this function to work [[nodiscard]] size_t getInstructionId(n_t Inst) const { assert(isValid()); - return self().getInstructionId(Inst); + return self().getInstructionIdImpl(Inst); } [[nodiscard]] decltype(auto) getAllInstructions() const { diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index ca75fd53d..e872c23fb 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -58,8 +58,8 @@ template concept IsEdgeFunction = requires(const T &EF, const EdgeFunction& TEEF, EdgeFunctionRef CEF, typename T::l_t Src) { typename T::l_t; {EF.computeTarget(Src)} -> std::convertible_to; - {T::compose(CEF, TEEF)} -> std::convertible_to>; - {T::join(CEF, TEEF)} -> std::convertible_to>; + {T::compose(CEF, TEEF)} -> std::same_as>; + {T::join(CEF, TEEF)} -> std::same_as>; }; // clang-format on diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index 13fcb3bac..0aadfaebf 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -22,6 +22,7 @@ #include "llvm/ADT/ArrayRef.h" #include +#include #include #include #include @@ -133,11 +134,8 @@ template > auto identityFlow() { /// v v v v v /// x1 x2 x x3 x4 /// -template , - typename = std::enable_if_t< - std::is_invocable_v && - std::is_convertible_v, Container>>> -auto lambdaFlow(Fn &&F) { +template auto lambdaFlow(Fn &&F) { + using Container = std::invoke_result_t; struct LambdaFlow final : public FlowFunction { LambdaFlow(Fn &&F) : Flow(std::forward(F)) {} Container computeTargets(D Source) override { @@ -204,7 +202,8 @@ auto generateFlow(psr::type_identity_t FactToGenerate, D From) { /// f(x) = {v, x} if p(x) == true /// f(x) = {x} else. /// -template , +template , + typename Fn = psr::TrueFn, typename = std::enable_if_t>> auto generateFlowIf(D FactToGenerate, Fn Predicate) { struct GenFlowIf final : public FlowFunction { @@ -243,7 +242,8 @@ auto generateFlowIf(D FactToGenerate, Fn Predicate) { /// v v v v ... \ v ... /// x w v1 v2 ... vN u /// -template , +template , + typename Range = std::initializer_list, typename = std::enable_if_t>> auto generateManyFlows(Range &&FactsToGenerate, D From) { struct GenMany final : public FlowFunction { @@ -319,7 +319,8 @@ auto killFlow(D FactToKill) { /// f(x) = {} if p(x) == true /// f(x) = {x} else. /// -template , +template , + typename Fn = psr::TrueFn, typename = std::enable_if_t>> auto killFlowIf(Fn Predicate) { struct KillFlowIf final : public FlowFunction { @@ -357,7 +358,8 @@ auto killFlowIf(Fn Predicate) { /// v v /// u v1 v2 ... vN w ... /// -template , +template , + typename Range = std::initializer_list, typename = std::enable_if_t>> auto killManyFlows(Range &&FactsToKill) { struct KillMany final : public FlowFunction { @@ -465,7 +467,8 @@ auto generateFlowAndKillAllOthers(psr::type_identity_t FactToGenerate, /// v v v ... \ ... /// x w v1 v2 ... vN u /// -template , +template , + typename Range = std::initializer_list, typename = std::enable_if_t>> auto generateManyFlowsAndKillAllOthers(Range &&FactsToGenerate, D From) { struct GenManyAndKillAllOthers final : public FlowFunction { diff --git a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h index 1c6013f61..908481976 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h @@ -29,25 +29,32 @@ class Function; class Value; class GlobalVariable; class Module; +class DIFile; } // namespace llvm namespace psr { -std::string getVarNameFromIR(const llvm::Value *V); +[[nodiscard]] std::string getVarNameFromIR(const llvm::Value *V); -std::string getFunctionNameFromIR(const llvm::Value *V); +[[nodiscard]] std::string getFunctionNameFromIR(const llvm::Value *V); -std::string getFilePathFromIR(const llvm::Value *V); +[[nodiscard]] std::string getFilePathFromIR(const llvm::Value *V); -std::string getDirectoryFromIR(const llvm::Value *V); +[[nodiscard]] std::string getDirectoryFromIR(const llvm::Value *V); -unsigned int getLineFromIR(const llvm::Value *V); +[[nodiscard]] const llvm::DIFile *getDIFileFromIR(const llvm::Value *V); -unsigned int getColumnFromIR(const llvm::Value *V); +[[nodiscard]] unsigned int getLineFromIR(const llvm::Value *V); -std::string getSrcCodeFromIR(const llvm::Value *V); +[[nodiscard]] unsigned int getColumnFromIR(const llvm::Value *V); -std::string getModuleIDFromIR(const llvm::Value *V); +[[nodiscard]] std::pair +getLineAndColFromIR(const llvm::Value *V); + +[[nodiscard]] std::string getSrcCodeFromIR(const llvm::Value *V, + bool Trim = true); + +[[nodiscard]] std::string getModuleIDFromIR(const llvm::Value *V); struct SourceCodeInfo { std::string SourceCodeLine; @@ -76,7 +83,7 @@ void from_json(const nlohmann::json &J, SourceCodeInfo &Info); /// SourceCodeInfo void to_json(nlohmann::json &J, const SourceCodeInfo &Info); -SourceCodeInfo getSrcCodeInfoFromIR(const llvm::Value *V); +[[nodiscard]] SourceCodeInfo getSrcCodeInfoFromIR(const llvm::Value *V); } // namespace psr diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index 4a20f6e75..d5d0dd1aa 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -79,7 +79,7 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { : detail::MaybeUniquePtrBase( std::exchange(Other.Data, {})) {} - void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other, Data); } + void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other.Data); } friend void swap(MaybeUniquePtr &LHS, MaybeUniquePtr &RHS) noexcept { LHS.swap(RHS); diff --git a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp index 6e0b45f4c..3f1a3e83b 100644 --- a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp +++ b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp @@ -103,32 +103,6 @@ llvm::DILocation *getDILocation(const llvm::Value *V) { return nullptr; } -llvm::DIFile *getDIFile(const llvm::Value *V) { - if (const auto *GO = llvm::dyn_cast(V)) { - if (auto *MN = GO->getMetadata(llvm::LLVMContext::MD_dbg)) { - if (auto *Subpr = llvm::dyn_cast(MN)) { - return Subpr->getFile(); - } - if (auto *GVExpr = llvm::dyn_cast(MN)) { - return GVExpr->getVariable()->getFile(); - } - } - } else if (const auto *Arg = llvm::dyn_cast(V)) { - if (auto *LocVar = getDILocalVariable(Arg)) { - return LocVar->getFile(); - } - } else if (const auto *I = llvm::dyn_cast(V)) { - if (I->isUsedByMetadata()) { - if (auto *LocVar = getDILocalVariable(I)) { - return LocVar->getFile(); - } - } else if (I->getMetadata(llvm::LLVMContext::MD_dbg)) { - return I->getDebugLoc()->getFile(); - } - } - return nullptr; -} - std::string getVarNameFromIR(const llvm::Value *V) { if (auto *LocVar = getDILocalVariable(V)) { return LocVar->getName().str(); @@ -154,7 +128,7 @@ std::string getFunctionNameFromIR(const llvm::Value *V) { } std::string getFilePathFromIR(const llvm::Value *V) { - if (auto *DIF = getDIFile(V)) { + if (auto *DIF = getDIFileFromIR(V)) { std::filesystem::path File(DIF->getFilename().str()); std::filesystem::path Dir(DIF->getDirectory().str()); if (!File.empty()) { @@ -181,32 +155,58 @@ std::string getFilePathFromIR(const llvm::Value *V) { return ""; } -unsigned int getLineFromIR(const llvm::Value *V) { +const llvm::DIFile *getDIFileFromIR(const llvm::Value *V) { + if (const auto *GO = llvm::dyn_cast(V)) { + if (auto *MN = GO->getMetadata(llvm::LLVMContext::MD_dbg)) { + if (auto *Subpr = llvm::dyn_cast(MN)) { + return Subpr->getFile(); + } + if (auto *GVExpr = llvm::dyn_cast(MN)) { + return GVExpr->getVariable()->getFile(); + } + } + } else if (const auto *Arg = llvm::dyn_cast(V)) { + if (auto *LocVar = getDILocalVariable(Arg)) { + return LocVar->getFile(); + } + } else if (const auto *I = llvm::dyn_cast(V)) { + if (I->isUsedByMetadata()) { + if (auto *LocVar = getDILocalVariable(I)) { + return LocVar->getFile(); + } + } else if (I->getMetadata(llvm::LLVMContext::MD_dbg)) { + return I->getDebugLoc()->getFile(); + } + } + return nullptr; +} + +std::string getDirectoryFromIR(const llvm::Value *V) { // Argument and Instruction if (auto *DILoc = getDILocation(V)) { - return DILoc->getLine(); + return DILoc->getDirectory().str(); } if (auto *DISubpr = getDISubprogram(V)) { // Function - return DISubpr->getLine(); + return DISubpr->getDirectory().str(); } if (auto *DIGV = getDIGlobalVariable(V)) { // Globals - return DIGV->getLine(); + return DIGV->getDirectory().str(); } - return 0; + return ""; } -std::string getDirectoryFromIR(const llvm::Value *V) { +unsigned int getLineFromIR(const llvm::Value *V) { // Argument and Instruction if (auto *DILoc = getDILocation(V)) { - return DILoc->getDirectory().str(); + return DILoc->getLine(); } if (auto *DISubpr = getDISubprogram(V)) { // Function - return DISubpr->getDirectory().str(); + return DISubpr->getLine(); } if (auto *DIGV = getDIGlobalVariable(V)) { // Globals - return DIGV->getDirectory().str(); + return DIGV->getLine(); } - return ""; + return 0; } unsigned int getColumnFromIR(const llvm::Value *V) { @@ -217,7 +217,21 @@ unsigned int getColumnFromIR(const llvm::Value *V) { return 0; } -std::string getSrcCodeFromIR(const llvm::Value *V) { +std::pair getLineAndColFromIR(const llvm::Value *V) { + // Argument and Instruction + if (auto *DILoc = getDILocation(V)) { + return {DILoc->getLine(), DILoc->getColumn()}; + } + if (auto *DISubpr = getDISubprogram(V)) { // Function + return {DISubpr->getLine(), 0}; + } + if (auto *DIGV = getDIGlobalVariable(V)) { // Globals + return {DIGV->getLine(), 0}; + } + return {0, 0}; +} + +std::string getSrcCodeFromIR(const llvm::Value *V, bool Trim) { unsigned int LineNr = getLineFromIR(V); if (LineNr > 0) { std::filesystem::path Path(getFilePathFromIR(V)); @@ -230,7 +244,7 @@ std::string getSrcCodeFromIR(const llvm::Value *V) { Ifs.ignore(std::numeric_limits::max(), '\n'); } std::getline(Ifs, SrcLine); - return llvm::StringRef(SrcLine).trim().str(); + return Trim ? llvm::StringRef(SrcLine).trim().str() : SrcLine; } } } From 285f03e2aa6c4f182e9d47b5a9c9cdcd9ef1cd01 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Fri, 12 May 2023 20:40:19 +0200 Subject: [PATCH 06/59] Enable building phasar with C++20 (#618) --- CMakeLists.txt | 9 ++++++++- include/phasar/DataFlow/IfdsIde/EdgeFunction.h | 6 ++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f80a1ca2..f447abe60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,15 @@ if (NOT PHASAR_IN_TREE) set(CMAKE_PROJECT_NAME "phasar") endif () +option(PHASAR_EXPERIMENTAL_CXX20 "Build phasar in C++20 mode. THis is an experimental feature" OFF) + set(CMAKE_EXPORT_COMPILE_COMMANDS YES) -set(CMAKE_CXX_STANDARD 17) +if(PHASAR_EXPERIMENTAL_CXX20) + message(STATUS "Selected experimental C++ build") + set(CMAKE_CXX_STANDARD 20) +else() + set(CMAKE_CXX_STANDARD 17) +endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index e872c23fb..064e21575 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -222,10 +222,8 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// Implicit-conversion constructor from EdgeFunctionRef. Increments the /// ref-count if not small-object optimized - template > && - IsEdgeFunction>> + template >>> EdgeFunction(EdgeFunctionRef CEF) noexcept : EdgeFunction(CEF.Instance, {&VTableFor, [CEF] { From d7cb8ea23e2768e0b9c142fc0c940ee4a2380cca Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 16 May 2023 20:52:50 +0200 Subject: [PATCH 07/59] Fix result[s]AtInLLVMSSA() (#620) * Fix resultsAtInLLVMSSA in case the statement is an invoke inst * minor * small fix * Assert overapproximation (optionally) * minor --- .../phasar/DataFlow/IfdsIde/SolverResults.h | 24 +-- .../DataFlow/IfdsIde/LLVMSolverResults.h | 169 ++++++++++++++++++ .../Problems/IDEInstInteractionAnalysis.h | 1 + lib/AnalysisStrategy/Strategies.cpp | 1 - 4 files changed, 174 insertions(+), 21 deletions(-) create mode 100644 include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 0e760878c..6a5671a50 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -94,19 +94,8 @@ class SolverResultsBase { std::is_same_v>, llvm::Instruction>, std::unordered_map> - resultsAtInLLVMSSA(ByConstRef Stmt, bool StripZero = false) { - std::unordered_map Result = [this, Stmt]() { - if (Stmt->getType()->isVoidTy()) { - return self().Results.row(Stmt); - } - assert(Stmt->getNextNode() && "Expected to find a valid successor node!"); - return self().Results.row(Stmt->getNextNode()); - }(); - if (StripZero) { - Result.erase(self().ZV); - } - return Result; - } + resultsAtInLLVMSSA(ByConstRef Stmt, bool AllowOverapproximation = false, + bool StripZero = false); /// Returns the L-type result at the given statement for the given data-flow /// fact while respecting LLVM's SSA semantics. @@ -128,13 +117,8 @@ class SolverResultsBase { std::is_same_v>, llvm::Instruction>, l_t> - resultAtInLLVMSSA(ByConstRef Stmt, d_t Value) { - if (Stmt->getType()->isVoidTy()) { - return self().Results.get(Stmt, Value); - } - assert(Stmt->getNextNode() && "Expected to find a valid successor node!"); - return self().Results.get(Stmt->getNextNode(), Value); - } + resultAtInLLVMSSA(ByConstRef Stmt, d_t Value, + bool AllowOverapproximation = false); [[nodiscard]] std::vector::Cell> getAllResultEntries() const { diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h new file mode 100644 index 000000000..0e334cb33 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h @@ -0,0 +1,169 @@ +/****************************************************************************** + * Copyright (c) 2017 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Philipp Schubert, Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_LLVMSOLVERRESULTS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_LLVMSOLVERRESULTS_H + +#include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/Logger.h" + +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/Support/ErrorHandling.h" + +namespace psr::detail { + +template +template +auto SolverResultsBase::resultsAtInLLVMSSA( + ByConstRef Stmt, bool AllowOverapproximation, bool StripZero) -> + typename std::enable_if_t< + std::is_same_v>, + llvm::Instruction>, + std::unordered_map> { + std::unordered_map Result = [this, Stmt, AllowOverapproximation]() { + if (Stmt->getType()->isVoidTy()) { + return self().Results.row(Stmt); + } + if (!Stmt->getNextNode()) { + auto GetStartRow = [this](const llvm::BasicBlock *BB) -> decltype(auto) { + const auto *First = &BB->front(); + if (llvm::isa(First)) { + First = First->getNextNonDebugInstruction(); + } + return self().Results.row(First); + }; + + // We have reached the end of a BasicBlock. If there is a successor BB + // that only has one predecessor, we are lucky and can just take results + // from there + for (const llvm::BasicBlock *Succ : llvm::successors(Stmt)) { + if (Succ->hasNPredecessors(1)) { + return GetStartRow(Succ); + } + } + + if (!AllowOverapproximation) { + llvm::report_fatal_error("[resultsAtInLLVMSSA]: Cannot precisely " + "collect the results at instruction " + + llvm::Twine(llvmIRToString(Stmt))); + } + + // There is no successor with only one predecessor. + // All we can do is merge the results from all successors to get a sound + // overapproximation. This is not optimal and may be replaced in the + // future. + PHASAR_LOG_LEVEL(WARNING, "[resultsAtInLLVMSSA]: Cannot precisely " + "collect the results at instruction " + << llvmIRToString(Stmt) + << ". Use a sound, but potentially " + "imprecise overapproximation"); + std::unordered_map Ret; + for (const llvm::BasicBlock *Succ : llvm::successors(Stmt)) { + const auto &Row = GetStartRow(Succ); + for (const auto &[Fact, Value] : Row) { + auto [It, Inserted] = Ret.try_emplace(Fact, Value); + if (!Inserted && Value != It->second) { + if constexpr (HasJoinLatticeTraits) { + It->second = JoinLatticeTraits::join(It->second, Value); + } else { + // We have no way of correctly merging, so set the value to the + // default constructed l_t hoping it marks BOTTOM. + It->second = l_t(); + } + } + } + } + return Ret; + } + assert(Stmt->getNextNode() && "Expected to find a valid successor node!"); + return self().Results.row(Stmt->getNextNode()); + }(); + if (StripZero) { + Result.erase(self().ZV); + } + return Result; +} + +template +template +auto SolverResultsBase::resultAtInLLVMSSA( + ByConstRef Stmt, d_t Value, bool AllowOverapproximation) -> + typename std::enable_if_t< + std::is_same_v>, + llvm::Instruction>, + l_t> { + if (Stmt->getType()->isVoidTy()) { + return self().Results.get(Stmt, Value); + } + if (!Stmt->getNextNode()) { + auto GetStartVal = [this, + &Value](const llvm::BasicBlock *BB) -> decltype(auto) { + const auto *First = &BB->front(); + if (llvm::isa(First)) { + First = First->getNextNonDebugInstruction(); + } + return self().Results.get(First, Value); + }; + + // We have reached the end of a BasicBlock. If there is a successor BB + // that only has one predecessor, we are lucky and can just take results + // from there + for (const llvm::BasicBlock *Succ : llvm::successors(Stmt)) { + if (Succ->hasNPredecessors(1)) { + return GetStartVal(Succ); + } + } + + if (!AllowOverapproximation) { + llvm::report_fatal_error("[resultsAtInLLVMSSA]: Cannot precisely " + "collect the results at instruction " + + llvm::Twine(llvmIRToString(Stmt))); + } + + // There is no successor with only one predecessor. + // All we can do is merge the results from all successors to get a sound + // overapproximation. This is not optimal and may be replaced in the + // future. + PHASAR_LOG_LEVEL(WARNING, "[resultAtInLLVMSSA]: Cannot precisely " + "collect the results at instruction " + << *Stmt + << ". Use a sound, but potentially " + "imprecise overapproximation"); + auto It = llvm::succ_begin(Stmt); + auto End = llvm::succ_end(Stmt); + l_t Ret{}; + if (It != End) { + Ret = GetStartVal(*It); + for (++It; It != End; ++It) { + const auto &Val = GetStartVal(*It); + if constexpr (HasJoinLatticeTraits) { + Ret = JoinLatticeTraits::join(Ret, Val); + if (Ret == JoinLatticeTraits::bottom()) { + break; + } + } else { + if (Ret != Val) { + // We have no way of correctly merging, so set the value to the + // default constructed l_t hoping it marks BOTTOM. + return {}; + } + } + } + } + return Ret; + } + assert(Stmt->getNextNode() && "Expected to find a valid successor node!"); + return self().Results.get(Stmt->getNextNode(), Value); +} +} // namespace psr::detail + +#endif // PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_LLVMSOLVERRESULTS_H diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index c39808640..c0824c7a5 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -18,6 +18,7 @@ #include "phasar/Domain/LatticeDomain.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" diff --git a/lib/AnalysisStrategy/Strategies.cpp b/lib/AnalysisStrategy/Strategies.cpp index a05ba5848..844b4e650 100644 --- a/lib/AnalysisStrategy/Strategies.cpp +++ b/lib/AnalysisStrategy/Strategies.cpp @@ -16,7 +16,6 @@ namespace psr { std::string toString(const AnalysisStrategy &S) { switch (S) { - default: #define ANALYSIS_STRATEGY_TYPES(NAME, CMDFLAG, DESC) \ case AnalysisStrategy::NAME: \ return #NAME; \ From a58655824dda42d0b5a7073f09159397c1ca94a9 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Wed, 31 May 2023 14:14:20 +0200 Subject: [PATCH 08/59] Deserialization for LLVMBasedICFG (#617) * Fix fromMetaDataId + add deserialization support for LLVMBasedICFG * pre-commit * Remove out-commented code --- .../PhasarLLVM/ControlFlow/LLVMBasedICFG.h | 3 + include/phasar/PhasarLLVM/HelperAnalyses.h | 2 + .../phasar/PhasarLLVM/HelperAnalysisConfig.h | 1 + lib/Controller/AnalysisController.cpp | 5 + lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp | 69 ++++++-- lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp | 2 +- lib/PhasarLLVM/HelperAnalyses.cpp | 20 ++- lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp | 3 +- tools/phasar-cli/phasar-cli.cpp | 35 +++- .../PhasarLLVM/ControlFlow/CMakeLists.txt | 1 + .../LLVMBasedICFGSerializationTest.cpp | 155 ++++++++++++++++++ 11 files changed, 269 insertions(+), 27 deletions(-) create mode 100644 unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 3878aa155..9570ad1ba 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -89,6 +89,9 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { Soundness S = Soundness::Soundy, bool IncludeGlobals = true); + explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, + const nlohmann::json &SerializedCG); + ~LLVMBasedICFG(); LLVMBasedICFG(const LLVMBasedICFG &) = delete; diff --git a/include/phasar/PhasarLLVM/HelperAnalyses.h b/include/phasar/PhasarLLVM/HelperAnalyses.h index 07b09878d..ebaabdcbf 100644 --- a/include/phasar/PhasarLLVM/HelperAnalyses.h +++ b/include/phasar/PhasarLLVM/HelperAnalyses.h @@ -33,6 +33,7 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) std::optional PrecomputedPTS, AliasAnalysisType PTATy, bool AllowLazyPTS, std::vector EntryPoints, + std::optional PrecomputedCG, CallGraphAnalysisType CGTy, Soundness SoundnessLevel, bool AutoGlobalSupport) noexcept; @@ -69,6 +70,7 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) bool AllowLazyPTS{}; // ICF + std::optional PrecomputedCG; std::vector EntryPoints; CallGraphAnalysisType CGTy{}; Soundness SoundnessLevel{}; diff --git a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h index d35195e76..21b52a958 100644 --- a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h +++ b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h @@ -21,6 +21,7 @@ namespace psr { struct HelperAnalysisConfig { std::optional PrecomputedPTS = std::nullopt; + std::optional PrecomputedCG = std::nullopt; AliasAnalysisType PTATy = AliasAnalysisType::CFLAnders; CallGraphAnalysisType CGTy = CallGraphAnalysisType::OTF; Soundness SoundnessLevel = Soundness::Soundy; diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index 5e9d1413d..c3ad51db1 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -9,6 +9,7 @@ #include "phasar/Controller/AnalysisController.h" +#include "phasar//Utils/NlohmannLogging.h" #include "phasar/AnalysisStrategy/Strategies.h" #include "phasar/Controller/AnalysisControllerEmitterOptions.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" @@ -184,6 +185,10 @@ void AnalysisController::emitRequestedHelperAnalysisResults() { WithResultFileOrStdout("/psr-cg.txt", [this](auto &OS) { HA.getICFG().print(OS); }); } + if (EmitterOptions & AnalysisControllerEmitterOptions::EmitCGAsJson) { + WithResultFileOrStdout( + "/psr-cg.json", [this](auto &OS) { OS << HA.getICFG().getAsJson(); }); + } if (EmitterOptions & (AnalysisControllerEmitterOptions::EmitStatisticsAsJson | diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index 974988ae6..eac1f5a2c 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -366,9 +366,8 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, llvm::ArrayRef EntryPoints, LLVMTypeHierarchy *TH, LLVMAliasInfoRef PT, Soundness S, bool IncludeGlobals) - : TH(TH) { + : IRDB(IRDB), TH(TH) { assert(IRDB != nullptr); - this->IRDB = IRDB; Builder B{IRDB, this, PT}; LLVMAliasInfo PTOwn; @@ -398,6 +397,52 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, << std::chrono::steady_clock::now().time_since_epoch().count()); } +LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, + const nlohmann::json &SerializedCG) + : IRDB(IRDB) { + assert(IRDB != nullptr); + + PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG", + "Load precomputed call-graph from JSON"); + + auto It = SerializedCG.find(PhasarConfig::JsonCallGraphID().str()); + + if (It == SerializedCG.end()) { + PHASAR_LOG_LEVEL_CAT(ERROR, "LLVMBasedICFG", + "Cannot deserialize call-graph from JSON: No key '" + << PhasarConfig::JsonCallGraphID() << "' present"); + return; + } + + const auto &Edges = It.value(); + + CallersOf.reserve(Edges.size()); + CalleesAt.reserve(Edges.size()); + VertexFunctions.reserve(Edges.size()); + + for (const auto &[FunName, CallerIDs] : Edges.items()) { + const auto *Fun = IRDB->getFunction(FunName); + if (!Fun) { + PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG", + "Invalid function name: " << FunName); + continue; + } + auto *CEdges = addFunctionVertex(Fun); + CEdges->reserve(CallerIDs.size()); + + for (const auto &JId : CallerIDs) { + auto Id = JId.get(); + const auto *CS = IRDB->getInstruction(Id); + if (!CS) { + PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG", + "Invalid CAll-Instruction Id: " << Id); + } + + addCallEdge(CS, Fun); + } + } +} + LLVMBasedICFG::~LLVMBasedICFG() = default; [[nodiscard]] FunctionRange LLVMBasedICFG::getAllFunctionsImpl() const { @@ -504,22 +549,12 @@ void LLVMBasedICFG::printImpl(llvm::raw_ostream &OS) const { [[nodiscard]] nlohmann::json LLVMBasedICFG::getAsJsonImpl() const { nlohmann::json J; - for (size_t Vtx = 0, VtxEnd = VertexFunctions.size(); Vtx != VtxEnd; ++Vtx) { - auto VtxFunName = VertexFunctions[Vtx]->getName().str(); - J[PhasarConfig::JsonCallGraphID().str()][VtxFunName] = - nlohmann::json::array(); - - for (const auto &Inst : llvm::instructions(VertexFunctions[Vtx])) { - if (!llvm::isa(Inst)) { - continue; - } + auto &Edges = J[PhasarConfig::JsonCallGraphID().str()]; + for (const auto &[Fun, Callers] : CallersOf) { + auto &JCallers = Edges[Fun->getName().str()]; - if (auto It = CalleesAt.find(&Inst); It != CalleesAt.end()) { - for (const auto *Succ : *It->second) { - J[PhasarConfig::JsonCallGraphID().str()][VtxFunName].push_back( - Succ->getName().str()); - } - } + for (const auto *CS : *Callers) { + JCallers.push_back(IRDB->getInstructionId(CS)); } } diff --git a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp index 17f05d6c8..d06b52acc 100644 --- a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp +++ b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp @@ -260,5 +260,5 @@ const llvm::Value *psr::fromMetaDataId(const LLVMProjectIRDB &IRDB, } auto IdNr = ParseInt(Id); - return IdNr ? IRDB.getInstruction(*IdNr) : nullptr; + return IdNr ? IRDB.getValueFromId(*IdNr) : nullptr; } diff --git a/lib/PhasarLLVM/HelperAnalyses.cpp b/lib/PhasarLLVM/HelperAnalyses.cpp index 42700df9d..e0d13925e 100644 --- a/lib/PhasarLLVM/HelperAnalyses.cpp +++ b/lib/PhasarLLVM/HelperAnalyses.cpp @@ -13,11 +13,13 @@ HelperAnalyses::HelperAnalyses(std::string IRFile, std::optional PrecomputedPTS, AliasAnalysisType PTATy, bool AllowLazyPTS, std::vector EntryPoints, + std::optional PrecomputedCG, CallGraphAnalysisType CGTy, Soundness SoundnessLevel, bool AutoGlobalSupport) noexcept : IRFile(std::move(IRFile)), PrecomputedPTS(std::move(PrecomputedPTS)), PTATy(PTATy), AllowLazyPTS(AllowLazyPTS), + PrecomputedCG(std::move(PrecomputedCG)), EntryPoints(std::move(EntryPoints)), CGTy(CGTy), SoundnessLevel(SoundnessLevel), AutoGlobalSupport(AutoGlobalSupport) {} @@ -26,8 +28,10 @@ HelperAnalyses::HelperAnalyses(std::string IRFile, HelperAnalysisConfig Config) noexcept : IRFile(std::move(IRFile)), PrecomputedPTS(std::move(Config.PrecomputedPTS)), PTATy(Config.PTATy), - AllowLazyPTS(Config.AllowLazyPTS), EntryPoints(std::move(EntryPoints)), - CGTy(Config.CGTy), SoundnessLevel(Config.SoundnessLevel), + AllowLazyPTS(Config.AllowLazyPTS), + PrecomputedCG(std::move(Config.PrecomputedCG)), + EntryPoints(std::move(EntryPoints)), CGTy(Config.CGTy), + SoundnessLevel(Config.SoundnessLevel), AutoGlobalSupport(Config.AutoGlobalSupport) {} HelperAnalyses::HelperAnalyses(const llvm::Twine &IRFile, @@ -70,10 +74,14 @@ LLVMTypeHierarchy &HelperAnalyses::getTypeHierarchy() { LLVMBasedICFG &HelperAnalyses::getICFG() { if (!ICF) { - ICF = std::make_unique( - &getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(), - CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr, - SoundnessLevel, AutoGlobalSupport); + if (PrecomputedCG.has_value()) { + ICF = std::make_unique(&getProjectIRDB(), *PrecomputedCG); + } else { + ICF = std::make_unique( + &getProjectIRDB(), CGTy, std::move(EntryPoints), &getTypeHierarchy(), + CGTy == CallGraphAnalysisType::OTF ? &getAliasInfo() : nullptr, + SoundnessLevel, AutoGlobalSupport); + } } return *ICF; diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp index 2e7badc4d..b50121f61 100644 --- a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp @@ -100,7 +100,8 @@ LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB, assert(IRDB != nullptr); // Assume, we already have validated the json schema - llvm::outs() << "Load precomputed points-to info from JSON\n"; + PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMAliasSet", + "Load precomputed points-to info from JSON"); const auto &Sets = SerializedPTS.at("AliasSets"); assert(Sets.is_array()); diff --git a/tools/phasar-cli/phasar-cli.cpp b/tools/phasar-cli/phasar-cli.cpp index 1ac2672d7..ef221b8cd 100644 --- a/tools/phasar-cli/phasar-cli.cpp +++ b/tools/phasar-cli/phasar-cli.cpp @@ -169,7 +169,6 @@ cl::opt cl::opt ProjectIdOpt("project-id", cl::desc("Project id used for output"), - cl::init("default-phasar-project"), cl::cat(PsrCat), cl::Hidden); PSR_SHORTLONG_OPTION(OutDirOpt, std::string, "O", "out", @@ -233,6 +232,12 @@ cl::opt "via emit-pta-as-json from the given file"), cl::cat(PsrCat)); +cl::opt LoadCGFromJsonOpt( + "load-cg-from-json", + cl::desc("Load the persisted call-graph previously exported via " + "emit-cg-as-json from the given file"), + cl::cat(PsrCat)); + PSR_SHORTLONG_OPTION(PammOutOpt, std::string, "A", "pamm-out", "Filename for PAMM's gathered data", cl::init("PAMM_data.json"), cl::cat(PsrCat), cl::Hidden); @@ -344,6 +349,15 @@ int main(int Argc, const char **Argv) { return 1; } + if (ProjectIdOpt.empty()) { + ProjectIdOpt = std::filesystem::path(ModuleOpt.getValue()) + .filename() + .replace_extension(); + if (ProjectIdOpt.empty()) { + ProjectIdOpt = "default-phasar-project"; + } + } + validateParamModule(); validateParamOutput(); validateParamPointerAnalysis(); @@ -385,6 +399,15 @@ int main(int Argc, const char **Argv) { if (EmitCGAsDotOpt) { EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsDot; } + if (EmitCGAsJsonOpt) { + EmitterOptions |= AnalysisControllerEmitterOptions::EmitCGAsJson; + } + if (EmitCGAsTextOpt) { + llvm::errs() + << "ERROR: emit-cg-as-text is currently not supported. Did you mean " + "emit-cg-as-dot? For reversible serialization use emit-cg-as-json\n"; + return 1; + } if (EmitPTAAsTextOpt) { EmitterOptions |= AnalysisControllerEmitterOptions::EmitPTAAsText; } @@ -410,9 +433,16 @@ int main(int Argc, const char **Argv) { std::optional PrecomputedAliasSet; if (!LoadPTAFromJsonOpt.empty()) { + PHASAR_LOG_LEVEL(INFO, "Load AliasInfo from file: " << LoadCGFromJsonOpt); PrecomputedAliasSet = readJsonFile(LoadPTAFromJsonOpt); } + std::optional PrecomputedCallGraph; + if (!LoadCGFromJsonOpt.empty()) { + PHASAR_LOG_LEVEL(INFO, "Load CallGraph from file: " << LoadCGFromJsonOpt); + PrecomputedCallGraph = readJsonFile(LoadCGFromJsonOpt); + } + if (EntryOpt.empty()) { EntryOpt.push_back("main"); } @@ -421,7 +451,8 @@ int main(int Argc, const char **Argv) { HelperAnalyses HA(std::move(ModuleOpt.getValue()), std::move(PrecomputedAliasSet), AliasTypeOpt, !AnalysisController::needsToEmitPTA(EmitterOptions), - EntryOpt, CGTypeOpt, SoundnessOpt, AutoGlobalsOpt); + EntryOpt, std::move(PrecomputedCallGraph), CGTypeOpt, + SoundnessOpt, AutoGlobalsOpt); AnalysisController Controller( HA, DataFlowAnalysisOpt, {AnalysisConfigOpt.getValue()}, EntryOpt, diff --git a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt index a7d45fd5f..04cb11d94 100644 --- a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt +++ b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt @@ -9,6 +9,7 @@ set(ControlFlowSources LLVMBasedBackwardICFGTest.cpp LLVMBasedICFGExportTest.cpp LLVMBasedICFGGlobCtorDtorTest.cpp + LLVMBasedICFGSerializationTest.cpp ) foreach(TEST_SRC ${ControlFlowSources}) diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp new file mode 100644 index 000000000..ec1d476da --- /dev/null +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp @@ -0,0 +1,155 @@ + +#include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +class LLVMBasedICFGGSerializationTest : public ::testing::Test { +protected: + static constexpr auto PathToLLFiles = PHASAR_BUILD_SUBFOLDER("call_graphs/"); + + void serAndDeser(const llvm::Twine &IRFile) { + using namespace std::string_literals; + + psr::LLVMProjectIRDB IRDB(PathToLLFiles + IRFile); + + psr::LLVMBasedICFG ICF(&IRDB, psr::CallGraphAnalysisType::OTF, {"main"s}); + auto Ser = ICF.getAsJson(); + + psr::LLVMBasedICFG Deser(&IRDB, Ser); + + compareResults(ICF, Deser); + } + + void compareResults(const psr::LLVMBasedICFG &Orig, + const psr::LLVMBasedICFG &Deser) { + EXPECT_EQ(Orig.getAllVertexFunctions().size(), + Deser.getAllVertexFunctions().size()); + + { + llvm::DenseSet DeserFuns( + Deser.getAllVertexFunctions().begin(), + Deser.getAllVertexFunctions().end()); + for (const auto *Fun : Orig.getAllVertexFunctions()) { + EXPECT_TRUE(DeserFuns.contains(Fun)) + << "Deserialized ICFG does not contain vertex function " + << Fun->getName().str(); + } + } + + for (const auto *Fun : Orig.getAllVertexFunctions()) { + + const auto &Calls = Orig.getCallsFromWithin(Fun); + + for (const auto *CS : Calls) { + llvm::DenseSet DeserCallees( + Deser.getCalleesOfCallAt(CS).begin(), + Deser.getCalleesOfCallAt(CS).end()); + EXPECT_EQ(Orig.getCalleesOfCallAt(CS).size(), DeserCallees.size()); + + for (const auto *OrigCallee : Orig.getCalleesOfCallAt(CS)) { + EXPECT_TRUE(DeserCallees.contains(OrigCallee)) + << "Deserialized ICFG does not contain call to " + << OrigCallee->getName().str() << " from " + << psr::llvmIRToString(CS); + } + } + } + } +}; + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG01) { + serAndDeser("static_callsite_1_c.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG02) { + serAndDeser("static_callsite_2_c.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG03) { + serAndDeser("static_callsite_3_c.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG04) { + serAndDeser("static_callsite_4_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG05) { + serAndDeser("static_callsite_5_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG06) { + serAndDeser("static_callsite_6_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG07) { + serAndDeser("static_callsite_7_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG08) { + serAndDeser("static_callsite_8_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG09) { + serAndDeser("static_callsite_9_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG10) { + serAndDeser("static_callsite_10_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG11) { + serAndDeser("static_callsite_11_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG12) { + serAndDeser("static_callsite_12_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFG13) { + serAndDeser("static_callsite_13_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV1) { + serAndDeser("virtual_call_1_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV2) { + serAndDeser("virtual_call_2_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV3) { + serAndDeser("virtual_call_3_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV4) { + serAndDeser("virtual_call_4_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV5) { + serAndDeser("virtual_call_5_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV6) { + serAndDeser("virtual_call_6_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV7) { + serAndDeser("virtual_call_7_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV8) { + serAndDeser("virtual_call_8_cpp.ll"); +} + +TEST_F(LLVMBasedICFGGSerializationTest, SerICFGV9) { + serAndDeser("virtual_call_9_cpp.ll"); +} + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} From c3b932c2df44df61eb33e99b1a76bec6ea64e412 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Wed, 31 May 2023 18:07:05 +0200 Subject: [PATCH 09/59] Explicit Call Graph (#619) * Start adding explicit call graph * Integrate CallGraph into LLVMBasedICFG * Add CallGraph interface and integrate it into the ICFG * Allow constructing LLVMBasedICFG with already given CallGraph * pre-compile Callgraph with LLVM config * Fix deserialization * some cleanup of LLVMBasedICFG * Make dot printing part of the call graph --- include/phasar/ControlFlow/CallGraph.h | 304 ++++++++++++++++++ include/phasar/ControlFlow/CallGraphBase.h | 59 ++++ include/phasar/ControlFlow/ICFGBase.h | 22 +- .../PhasarLLVM/ControlFlow/LLVMBasedICFG.h | 69 ++-- include/phasar/Utils/StableVector.h | 31 +- lib/ControlFlow/CallGraph.cpp | 6 + lib/Controller/AnalysisController.cpp | 2 +- lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp | 232 +++---------- .../LLVMBasedICFGSerializationTest.cpp | 4 +- 9 files changed, 475 insertions(+), 254 deletions(-) create mode 100644 include/phasar/ControlFlow/CallGraph.h create mode 100644 include/phasar/ControlFlow/CallGraphBase.h create mode 100644 lib/ControlFlow/CallGraph.cpp diff --git a/include/phasar/ControlFlow/CallGraph.h b/include/phasar/ControlFlow/CallGraph.h new file mode 100644 index 000000000..973528545 --- /dev/null +++ b/include/phasar/ControlFlow/CallGraph.h @@ -0,0 +1,304 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_CONTROLFLOW_CALLGRAPH_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPH_H + +#include "phasar/ControlFlow/CallGraphBase.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/Logger.h" +#include "phasar/Utils/StableVector.h" +#include "phasar/Utils/Utilities.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" + +#include "nlohmann/json.hpp" + +#include +#include +#include + +namespace psr { +template class CallGraphBuilder; +template class CallGraph; + +template struct CGTraits> { + using n_t = N; + using f_t = F; +}; + +/// An explicit graph-representation of a call-graph. Only represents the data, +/// not the call-graph analysis that creates it. +/// +/// This type is immutable. To incrementally build it from your call-graph +/// analysis, use the CallGraphBuilder +template +class CallGraph : public CallGraphBase> { + using base_t = CallGraphBase>; + friend base_t; + friend class CallGraphBuilder; + +public: + using typename base_t::f_t; + using typename base_t::n_t; + using FunctionVertexTy = llvm::SmallVector; + using InstructionVertexTy = llvm::SmallVector; + + /// Creates a new, empty call-graph + CallGraph() noexcept = default; + + /// Deserializes a previously computed call-graph + template + [[nodiscard]] static CallGraph + deserialize(const nlohmann::json &PrecomputedCG, + FunctionGetter GetFunctionFromName, + InstructionGetter GetInstructionFromId); + + /// A range of all functions that are vertices in the call-graph. The number + /// of vertex functions can be retrieved by getNumVertexFunctions(). + [[nodiscard]] auto getAllVertexFunctions() const noexcept { + return llvm::make_first_range(CallersOf); + } + + /// A range of all call-sites that are vertices in the call-graph. The number + /// of vertex-callsites can be retrived by getNumVertexCallSites(). + [[nodiscard]] auto getAllVertexCallSites() const noexcept { + return llvm::make_first_range(CalleesAt); + } + + [[nodiscard]] size_t getNumVertexFunctions() const noexcept { + return CallersOf.size(); + } + [[nodiscard]] size_t getNumVertexCallSites() const noexcept { + return CalleesAt.size(); + } + + /// The number of functions within this call-graph + [[nodiscard]] size_t size() const noexcept { return getNumVertexFunctions(); } + + [[nodiscard]] bool empty() const noexcept { return CallersOf.empty(); } + + /// Creates a JSON representation of this call-graph suitable for presistent + /// storage. + /// Use the ctor taking a json object for deserialization + template + [[nodiscard]] nlohmann::json getAsJson(FunctionIdGetter GetFunctionId, + InstIdGetter GetInstructionId) const { + nlohmann::json J; + + for (const auto &[Fun, Callers] : CallersOf) { + auto &JCallers = J[std::invoke(GetFunctionId, Fun)]; + + for (const auto &CS : *Callers) { + JCallers.push_back(std::invoke(GetInstructionId, CS)); + } + } + + return J; + } + + template + void printAsDot(llvm::raw_ostream &OS, FunctionLabelGetter GetFunctionLabel, + InstParentGetter GetFunctionFromInst, + InstLabelGetter GetInstLabel) const { + OS << "digraph CallGraph{\n"; + scope_exit CloseBrace = [&OS] { OS << "}\n"; }; + + llvm::DenseMap Fun2Id; + Fun2Id.reserve(CallersOf.size()); + + size_t CurrId = 0; + for (const auto &Fun : getAllVertexFunctions()) { + OS << CurrId << "[label=\""; + OS.write_escaped(std::invoke(GetFunctionLabel, Fun)) << "\"];\n"; + Fun2Id[Fun] = CurrId++; + } + + for (const auto &[CS, Callees] : CalleesAt) { + const auto &Fun = std::invoke(GetFunctionFromInst, CS); + + for (const auto &Succ : *Callees) { + OS << Fun2Id.lookup(Fun) << "->" << Fun2Id.lookup(Succ) << "[label=\""; + OS.write_escaped(std::invoke(GetInstLabel, CS)) << "\"];\n"; + } + } + } + +private: + [[nodiscard]] llvm::ArrayRef + getCalleesOfCallAtImpl(ByConstRef Inst) const noexcept { + if (const auto *CalleesPtr = CalleesAt.lookup(Inst)) { + return *CalleesPtr; + } + return {}; + } + + [[nodiscard]] llvm::ArrayRef + getCallersOfImpl(ByConstRef Fun) const noexcept { + if (const auto *CallersPtr = CallersOf.lookup(Fun)) { + return *CallersPtr; + } + return {}; + } + + // --- + + StableVector InstVertexOwner; + std::vector FunVertexOwner; + + llvm::DenseMap CalleesAt{}; + llvm::DenseMap CallersOf{}; +}; + +/// A mutable wrapper over a CallGraph. Use this to build a call-graph from +/// within your call-graph ananlysis. +template class CallGraphBuilder { +public: + using n_t = typename CallGraph::n_t; + using f_t = typename CallGraph::f_t; + using FunctionVertexTy = typename CallGraph::FunctionVertexTy; + using InstructionVertexTy = typename CallGraph::InstructionVertexTy; + + void reserve(size_t MaxNumFunctions) { + CG.FunVertexOwner.reserve(MaxNumFunctions); + CG.CalleesAt.reserve(MaxNumFunctions); + CG.CallersOf.reserve(MaxNumFunctions); + } + + /// Registeres a new function in the call-graph. Returns a list of all + /// call-sites that are known so far to potentially call this function. + /// Do not manually add elements to this vector -- use addCallEdge instead. + [[nodiscard]] FunctionVertexTy *addFunctionVertex(f_t Fun) { + auto [It, Inserted] = CG.CallersOf.try_emplace(std::move(Fun), nullptr); + if (Inserted) { + auto Cap = CG.FunVertexOwner.capacity(); + assert(CG.FunVertexOwner.size() < Cap && + "Trying to add more than MaxNumFunctions Function Vertices"); + It->second = &CG.FunVertexOwner.emplace_back(); + } + return It->second; + } + + /// Registeres a new call-site in the call-graph. Returns a list of all + /// callee functions that are known so far to potentially be called by this + /// function. + /// Do not manually add elements to this vector -- use addCallEdge instead. + [[nodiscard]] InstructionVertexTy *addInstructionVertex(n_t Inst) { + auto [It, Inserted] = CG.CalleesAt.try_emplace(std::move(Inst), nullptr); + if (Inserted) { + It->second = &CG.InstVertexOwner.emplace_back(); + } + return It->second; + } + + /// Tries to lookup the InstructionVertex for the given call-site. Returns + /// nullptr on failure. + [[nodiscard]] InstructionVertexTy * + getInstVertexOrNull(ByConstRef Inst) const noexcept { + return CG.CalleesAt.lookup(Inst); + } + + /// Adds a new directional edge to the call-graph indicating that CS may call + /// Callee + void addCallEdge(n_t CS, f_t Callee) { + auto IVtx = addInstructionVertex(CS); + auto FVtx = addFunctionVertex(Callee); + addCallEdge(std::move(CS), IVtx, std::move(Callee), FVtx); + } + + /// Same as addCallEdge(n_t, f_t), but uses an already known + /// InstructionVertexTy to save a lookup + void addCallEdge(n_t CS, InstructionVertexTy *Callees, f_t Callee) { + auto *Callers = addFunctionVertex(Callee); + addCallEdge(std::move(CS), Callees, std::move(Callee), Callers); + } + + /// Same as addCallEdge(n_t, f_t), but uses an already known + /// FunctionVertexTy to save a lookup + void addCallEdge(n_t CS, f_t Callee, FunctionVertexTy *Callers) { + auto *Callees = addInstructionVertex(CS); + addCallEdge(std::move(CS), Callees, std::move(Callee), Callers); + } + + /// Moves the completely built call-graph out of this builder for further + /// use. Do not use the builder after it anymore. + [[nodiscard]] CallGraph consumeCallGraph() noexcept { + return std::move(CG); + } + + /// Returns a view on the current (partial) call-graph that has already been + /// constructed + [[nodiscard]] const CallGraph &viewCallGraph() const noexcept { + return CG; + } + +private: + void addCallEdge(n_t CS, InstructionVertexTy *Callees, f_t Callee, + FunctionVertexTy *Callers) { + Callees->push_back(std::move(Callee)); + Callers->push_back(std::move(CS)); + } + + CallGraph CG{}; +}; + +template +template +[[nodiscard]] CallGraph +CallGraph::deserialize(const nlohmann::json &PrecomputedCG, + FunctionGetter GetFunctionFromName, + InstructionGetter GetInstructionFromId) { + if (!PrecomputedCG.is_object()) { + PHASAR_LOG_LEVEL_CAT(ERROR, "CallGraph", "Invalid Json. Expected object"); + return {}; + } + + CallGraphBuilder CGBuilder; + CGBuilder.reserve(PrecomputedCG.size()); + + for (const auto &[FunName, CallerIDs] : PrecomputedCG.items()) { + const auto &Fun = std::invoke(GetFunctionFromName, FunName); + if (!Fun) { + PHASAR_LOG_LEVEL_CAT(WARNING, "CallGraph", + "Invalid function name: " << FunName); + continue; + } + + auto *CEdges = CGBuilder.addFunctionVertex(Fun); + CEdges->reserve(CallerIDs.size()); + + for (const auto &JId : CallerIDs) { + auto Id = JId.get(); + const auto &CS = std::invoke(GetInstructionFromId, Id); + if (!CS) { + PHASAR_LOG_LEVEL_CAT(WARNING, "CallGraph", + "Invalid CAll-Instruction Id: " << Id); + } + + CGBuilder.addCallEdge(CS, Fun); + } + } + return CGBuilder.consumeCallGraph(); +} +} // namespace psr + +namespace llvm { +class Function; +class Instruction; +} // namespace llvm + +extern template class psr::CallGraph; +extern template class psr::CallGraphBuilder; + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPH_H diff --git a/include/phasar/ControlFlow/CallGraphBase.h b/include/phasar/ControlFlow/CallGraphBase.h new file mode 100644 index 000000000..9440829d8 --- /dev/null +++ b/include/phasar/ControlFlow/CallGraphBase.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_CONTROLFLOW_CALLGRAPHBASE_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHBASE_H + +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/TypeTraits.h" + +#include "nlohmann/json.hpp" + +namespace psr { +template struct CGTraits { + // using n_t + // using f_t +}; + +/// Base class of all CallGraph implementations within phasar (currently only +/// CallGraph). +/// Only represents the data, not how to create it. +template class CallGraphBase { +public: + using n_t = typename CGTraits::n_t; + using f_t = typename CGTraits::f_t; + + /// Returns an iterable range of all possible callee candidates at the given + /// call-site induced by the used call-graph. + /// + /// NOTE: This function is typically called in a hot part of the analysis and + /// should therefore be very fast + [[nodiscard]] decltype(auto) getCalleesOfCallAt(ByConstRef Inst) const + noexcept(noexcept(self().getCalleesOfCallAtImpl(Inst))) { + static_assert( + is_iterable_over_v); + return self().getCalleesOfCallAtImpl(Inst); + } + + /// Returns an iterable range of all possible call-site candidates that may + /// call the given function induced by the used call-graph. + [[nodiscard]] decltype(auto) getCallersOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getCallersOfImpl(Fun); + } + +private: + const Derived &self() const noexcept { + return static_cast(*this); + } +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHBASE_H diff --git a/include/phasar/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h index e85520de2..339671fd7 100644 --- a/include/phasar/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -11,6 +11,7 @@ #define PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H #include "phasar/ControlFlow/CFGBase.h" +#include "phasar/ControlFlow/CallGraphBase.h" #include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/StringRef.h" @@ -64,20 +65,24 @@ template class ICFGBase { is_iterable_over_v); return self().allNonCallStartNodesImpl(); } + + /// Returns a view to the underlying call-graph + [[nodiscard]] decltype(auto) getCallGraph() const noexcept { + static_assert( + is_crtp_base_of_v>); + return self().getCallGraphImpl(); + } + /// Returns an iterable range of all possible callee candidates at the given - /// call-site induced by the used call-graph. NOTE: This function is typically - /// called in a hot part of the analysis and should therefore be very fast + /// call-site induced by the used call-graph. [[nodiscard]] decltype(auto) getCalleesOfCallAt(ByConstRef Inst) const { - static_assert( - is_iterable_over_v); - return self().getCalleesOfCallAtImpl(Inst); + return getCallGraph().getCalleesOfCallAt(Inst); } /// Returns an iterable range of all possible call-site candidates that may /// call the given function induced by the used call-graph. [[nodiscard]] decltype(auto) getCallersOf(ByConstRef Fun) const { - static_assert( - is_iterable_over_v); - return self().getCallersOfImpl(Fun); + return getCallGraph().getCallersOf(Fun); } /// Returns an iterable range of all call-instruction in the given function [[nodiscard]] decltype(auto) getCallsFromWithin(ByConstRef Fun) const { @@ -114,7 +119,6 @@ template class ICFGBase { } private: - Derived &self() noexcept { return static_cast(*this); } const Derived &self() const noexcept { return static_cast(*this); } diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 9570ad1ba..e2171a31a 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -17,6 +17,7 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ +#include "phasar/ControlFlow/CallGraph.h" #include "phasar/ControlFlow/CallGraphAnalysisType.h" #include "phasar/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" @@ -29,6 +30,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" @@ -37,16 +39,8 @@ #include -/// On some MAC systems, is still not fully implemented, so do -/// a workaround here - -#if !HAS_MEMORY_RESOURCE -#include "llvm/Support/Allocator.h" -#endif - namespace psr { class LLVMTypeHierarchy; -class LLVMPointsToInfo; class LLVMProjectIRDB; class LLVMBasedICFG; @@ -57,10 +51,6 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { struct Builder; - struct OnlyDestroyDeleter { - template void operator()(T *Data) { std::destroy_at(Data); } - }; - public: static constexpr llvm::StringLiteral GlobalCRuntimeModelName = "__psrCRuntimeGlobalCtorsModel"; @@ -89,16 +79,21 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { Soundness S = Soundness::Soundy, bool IncludeGlobals = true); + /// Creates an ICFG with an already given call-graph + explicit LLVMBasedICFG(CallGraph CG, LLVMProjectIRDB *IRDB, + LLVMTypeHierarchy *TH = nullptr); + explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, - const nlohmann::json &SerializedCG); + const nlohmann::json &SerializedCG, + LLVMTypeHierarchy *TH = nullptr); ~LLVMBasedICFG(); LLVMBasedICFG(const LLVMBasedICFG &) = delete; LLVMBasedICFG &operator=(const LLVMBasedICFG &) = delete; - LLVMBasedICFG(LLVMBasedICFG &&) noexcept = delete; - LLVMBasedICFG &operator=(LLVMBasedICFG &&) noexcept = delete; + LLVMBasedICFG(LLVMBasedICFG &&) noexcept = default; + LLVMBasedICFG &operator=(LLVMBasedICFG &&) noexcept = default; /// Exports the whole ICFG (not only the call-graph) as DOT. /// @@ -111,9 +106,15 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { [[nodiscard]] nlohmann::json exportICFGAsJson(bool WithSourceCodeInfo = true) const; + [[nodiscard]] size_t getNumVertexFunctions() const noexcept { + return CG.getNumVertexFunctions(); + } + /// Returns all functions from the underlying IRDB that are part of the ICFG, /// i.e. that are reachable from the entry-points - [[nodiscard]] llvm::ArrayRef getAllVertexFunctions() const noexcept; + [[nodiscard]] auto getAllVertexFunctions() const noexcept { + return CG.getAllVertexFunctions(); + } /// Gets the underlying IRDB [[nodiscard]] LLVMProjectIRDB *getIRDB() const noexcept { return IRDB; } @@ -131,47 +132,21 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { [[nodiscard]] bool isIndirectFunctionCallImpl(n_t Inst) const; [[nodiscard]] bool isVirtualFunctionCallImpl(n_t Inst) const; [[nodiscard]] std::vector allNonCallStartNodesImpl() const; - [[nodiscard]] llvm::ArrayRef - getCalleesOfCallAtImpl(n_t Inst) const noexcept; - [[nodiscard]] llvm::ArrayRef getCallersOfImpl(f_t Fun) const noexcept; [[nodiscard]] llvm::SmallVector getCallsFromWithinImpl(f_t Fun) const; [[nodiscard]] llvm::SmallVector getReturnSitesOfCallAtImpl(n_t Inst) const; void printImpl(llvm::raw_ostream &OS) const; [[nodiscard]] nlohmann::json getAsJsonImpl() const; + [[nodiscard]] const CallGraph &getCallGraphImpl() const noexcept { + return CG; + } [[nodiscard]] llvm::Function *buildCRuntimeGlobalCtorsDtorsModel( llvm::Module &M, llvm::ArrayRef UserEntryPoints); - // -------------------- Utilities -------------------- - - llvm::SmallVector * - addFunctionVertex(const llvm::Function *F); - llvm::SmallVector * - addInstructionVertex(const llvm::Instruction *Inst); - - void addCallEdge(const llvm::Instruction *CS, const llvm::Function *Callee); - void addCallEdge(const llvm::Instruction *CS, - llvm::SmallVector *Callees, - const llvm::Function *Callee); - -#if HAS_MEMORY_RESOURCE - std::pmr::monotonic_buffer_resource MRes; -#else - llvm::BumpPtrAllocator MRes; -#endif - - llvm::DenseMap, - OnlyDestroyDeleter>> - CalleesAt; - llvm::DenseMap, - OnlyDestroyDeleter>> - CallersOf; - - llvm::SmallVector VertexFunctions; + // --- + CallGraph CG; LLVMProjectIRDB *IRDB = nullptr; MaybeUniquePtr TH; }; diff --git a/include/phasar/Utils/StableVector.h b/include/phasar/Utils/StableVector.h index f89ed5ab9..c7e340451 100644 --- a/include/phasar/Utils/StableVector.h +++ b/include/phasar/Utils/StableVector.h @@ -199,33 +199,32 @@ 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); } - - StableVector &operator=(StableVector Other) noexcept { - swap(*this, Other); - return *this; + friend void swap(StableVector &LHS, StableVector &RHS) noexcept { + LHS.swap(RHS); } + // This would be silently expensive... If you really want this, call clone() + StableVector &operator=(const StableVector &) = delete; + StableVector &operator=(StableVector &&Other) noexcept { - swap(*this, Other); + swap(Other); return *this; } diff --git a/lib/ControlFlow/CallGraph.cpp b/lib/ControlFlow/CallGraph.cpp new file mode 100644 index 000000000..ad5aaef20 --- /dev/null +++ b/lib/ControlFlow/CallGraph.cpp @@ -0,0 +1,6 @@ +#include "phasar/ControlFlow/CallGraph.h" + +template class psr::CallGraph; +template class psr::CallGraphBuilder; diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index c3ad51db1..8406720ef 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -9,7 +9,6 @@ #include "phasar/Controller/AnalysisController.h" -#include "phasar//Utils/NlohmannLogging.h" #include "phasar/AnalysisStrategy/Strategies.h" #include "phasar/Controller/AnalysisControllerEmitterOptions.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" @@ -17,6 +16,7 @@ #include "phasar/PhasarLLVM/HelperAnalyses.h" #include "phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h" #include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" +#include "phasar/Utils/NlohmannLogging.h" #include "phasar/Utils/Utilities.h" #include "llvm/ADT/STLExtras.h" diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index eac1f5a2c..591e4e746 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -10,6 +10,7 @@ #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/Config/Configuration.h" +#include "phasar/ControlFlow/CallGraph.h" #include "phasar/ControlFlow/CallGraphAnalysisType.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" @@ -28,6 +29,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" #include "llvm/Support/ErrorHandling.h" #include @@ -36,8 +39,10 @@ namespace psr { struct LLVMBasedICFG::Builder { LLVMProjectIRDB *IRDB = nullptr; - LLVMBasedICFG *ICF = nullptr; LLVMAliasInfoRef PT{}; + LLVMTypeHierarchy *TH{}; + CallGraphBuilder + CGBuilder{}; std::unique_ptr Res = nullptr; llvm::DenseSet VisitedFunctions{}; llvm::SmallVector UserEntryPoints{}; @@ -56,7 +61,8 @@ struct LLVMBasedICFG::Builder { void initEntryPoints(llvm::ArrayRef EntryPoints); void initGlobalsAndWorkList(LLVMBasedICFG *ICFG, bool IncludeGlobals); - void buildCallGraph(Soundness S); + [[nodiscard]] CallGraph + buildCallGraph(Soundness S); /// \returns FixPointReached bool processFunction(/*bidigraph_t &Callgraph,*/ const llvm::Function *F); @@ -75,7 +81,7 @@ void LLVMBasedICFG::Builder::initEntryPoints( // outside! if (!Fun->isDeclaration() && Fun->hasName() && (Fun->hasExternalLinkage() || Fun->getName() == "main")) { - UserEntryPoints.push_back(IRDB->getFunctionDefinition(Fun->getName())); + UserEntryPoints.push_back(IRDB->getFunction(Fun->getName())); } } } else { @@ -104,9 +110,13 @@ void LLVMBasedICFG::Builder::initGlobalsAndWorkList(LLVMBasedICFG *ICFG, FunctionWL.insert(FunctionWL.end(), UserEntryPoints.begin(), UserEntryPoints.end()); } + // Note: Pre-allocate the call-graph builder *after* adding the + // CRuntimeGlobalCtorsDtorsModel + CGBuilder.reserve(IRDB->getNumFunctions()); } -void LLVMBasedICFG::Builder::buildCallGraph(Soundness /*S*/) { +auto LLVMBasedICFG::Builder::buildCallGraph(Soundness /*S*/) + -> CallGraph { PHASAR_LOG_LEVEL_CAT(INFO, "LLVMBasedICFG", "Starting CallGraphAnalysisType: " << Res->str()); VisitedFunctions.reserve(IRDB->getNumFunctions()); @@ -139,7 +149,7 @@ void LLVMBasedICFG::Builder::buildCallGraph(Soundness /*S*/) { REG_COUNTER("CG Edges", boost::num_edges(ret), PAMM_SEVERITY_LEVEL::Full); PHASAR_LOG_LEVEL_CAT(INFO, "LLVMBasedICFG", "Call graph has been constructed"); - // return Ret; + return CGBuilder.consumeCallGraph(); } bool LLVMBasedICFG::Builder::processFunction(const llvm::Function *F) { @@ -155,7 +165,7 @@ bool LLVMBasedICFG::Builder::processFunction(const llvm::Function *F) { assert(Res != nullptr); // add a node for function F to the call graph (if not present already) - ICF->addFunctionVertex(F); + std::ignore = CGBuilder.addFunctionVertex(F); bool FixpointReached = true; @@ -191,7 +201,7 @@ bool LLVMBasedICFG::Builder::processFunction(const llvm::Function *F) { "Found dynamic call-site: " << " " << llvmIRToString(CS)); IndirectCalls[CS] = 0; - ICF->addInstructionVertex(CS); + std::ignore = CGBuilder.addInstructionVertex(CS); FixpointReached = false; continue; @@ -204,12 +214,12 @@ bool LLVMBasedICFG::Builder::processFunction(const llvm::Function *F) { Res->handlePossibleTargets(CS, PossibleTargets); - auto *CallSiteId = ICF->addInstructionVertex(CS); + auto *CallSiteId = CGBuilder.addInstructionVertex(CS); // Insert possible target inside the graph and add the link with // the current function for (const auto *PossibleTarget : PossibleTargets) { - ICF->addCallEdge(CS, CallSiteId, PossibleTarget); + CGBuilder.addCallEdge(CS, CallSiteId, PossibleTarget); FunctionWL.push_back(PossibleTarget); } @@ -224,58 +234,6 @@ bool LLVMBasedICFG::Builder::processFunction(const llvm::Function *F) { return FixpointReached; } -llvm::SmallVector * -LLVMBasedICFG::addFunctionVertex(const llvm::Function *F) { - auto [It, Inserted] = CallersOf.try_emplace(F, nullptr); - if (Inserted) { - VertexFunctions.push_back(F); - - using type = llvm::SmallVector; - auto *RawBytes = -#if HAS_MEMORY_RESOURCE - MRes.allocate(sizeof(type), alignof(type)); -#else - MRes.Allocate(); -#endif - It->second.reset(new (RawBytes) type()); - } - - return It->second.get(); -} - -llvm::SmallVector * -LLVMBasedICFG::addInstructionVertex(const llvm::Instruction *Inst) { - auto [It, Inserted] = CalleesAt.try_emplace(Inst, nullptr); - if (Inserted) { - using type = llvm::SmallVector; - auto *RawBytes = -#if HAS_MEMORY_RESOURCE - MRes.allocate(sizeof(type), alignof(type)); -#else - MRes.Allocate(); -#endif - It->second.reset(new (RawBytes) type()); - } - - return It->second.get(); -} - -void LLVMBasedICFG::addCallEdge(const llvm::Instruction *CS, - const llvm::Function *Callee) { - return addCallEdge(CS, addInstructionVertex(CS), Callee); -} - -void LLVMBasedICFG::addCallEdge( - const llvm::Instruction *CS, - llvm::SmallVector *Callees, - const llvm::Function *Callee) { - - auto *Callers = addFunctionVertex(Callee); - - Callees->push_back(Callee); - Callers->push_back(CS); -} - static bool internalIsVirtualFunctionCall(const llvm::Instruction *Inst, const LLVMTypeHierarchy &TH) { assert(Inst != nullptr); @@ -301,16 +259,14 @@ bool LLVMBasedICFG::Builder::constructDynamicCall(const llvm::Instruction *CS) { bool NewTargetsFound = false; // Find vertex of calling function. - auto FvmItr = ICF->CalleesAt.find(CS); + auto *Callees = CGBuilder.getInstVertexOrNull(CS); - if (FvmItr == ICF->CalleesAt.end()) { + if (!Callees) { llvm::report_fatal_error( "constructDynamicCall: Did not find vertex of calling function " + CS->getFunction()->getName() + " at callsite " + llvmIRToString(CS)); } - auto *Callees = FvmItr->second.get(); - if (const auto *CallSite = llvm::dyn_cast(CS)) { Res->preCall(CallSite); @@ -320,8 +276,8 @@ bool LLVMBasedICFG::Builder::constructDynamicCall(const llvm::Instruction *CS) { PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG", " " << llvmIRToString(CS)); // call the resolve routine - assert(ICF->TH != nullptr); - auto PossibleTargets = internalIsVirtualFunctionCall(CallSite, *ICF->TH) + assert(TH != nullptr); + auto PossibleTargets = internalIsVirtualFunctionCall(CallSite, *TH) ? Res->resolveVirtualCall(CallSite) : Res->resolveFunctionPointer(CallSite); @@ -349,7 +305,7 @@ bool LLVMBasedICFG::Builder::constructDynamicCall(const llvm::Instruction *CS) { // Insert possible target inside the graph and add the link with // the current function for (const auto *PossibleTarget : PossibleTargets) { - ICF->addCallEdge(CallSite, Callees, PossibleTarget); + CGBuilder.addCallEdge(CallSite, Callees, PossibleTarget); FunctionWL.push_back(PossibleTarget); } @@ -369,12 +325,13 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, : IRDB(IRDB), TH(TH) { assert(IRDB != nullptr); - Builder B{IRDB, this, PT}; - LLVMAliasInfo PTOwn; - - if (!TH && CGType != CallGraphAnalysisType::NORESOLVE) { + if (!TH) { this->TH = std::make_unique(*IRDB); } + + Builder B{IRDB, PT, this->TH.get()}; + LLVMAliasInfo PTOwn; + if (!PT && CGType == CallGraphAnalysisType::OTF) { PTOwn = std::make_unique(IRDB); B.PT = PTOwn.asRef(); @@ -389,7 +346,7 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, "Starting ICFG construction " << std::chrono::steady_clock::now().time_since_epoch().count()); - B.buildCallGraph(S); + this->CG = B.buildCallGraph(S); PHASAR_LOG_LEVEL_CAT( INFO, "LLVMBasedICFG", @@ -397,49 +354,24 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, << std::chrono::steady_clock::now().time_since_epoch().count()); } -LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, - const nlohmann::json &SerializedCG) - : IRDB(IRDB) { - assert(IRDB != nullptr); - - PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG", - "Load precomputed call-graph from JSON"); - - auto It = SerializedCG.find(PhasarConfig::JsonCallGraphID().str()); - - if (It == SerializedCG.end()) { - PHASAR_LOG_LEVEL_CAT(ERROR, "LLVMBasedICFG", - "Cannot deserialize call-graph from JSON: No key '" - << PhasarConfig::JsonCallGraphID() << "' present"); - return; +LLVMBasedICFG::LLVMBasedICFG(CallGraph CG, LLVMProjectIRDB *IRDB, + LLVMTypeHierarchy *TH) + : CG(std::move(CG)), IRDB(IRDB), TH(TH) { + if (!TH) { + this->TH = std::make_unique(*IRDB); } +} - const auto &Edges = It.value(); - - CallersOf.reserve(Edges.size()); - CalleesAt.reserve(Edges.size()); - VertexFunctions.reserve(Edges.size()); - - for (const auto &[FunName, CallerIDs] : Edges.items()) { - const auto *Fun = IRDB->getFunction(FunName); - if (!Fun) { - PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG", - "Invalid function name: " << FunName); - continue; - } - auto *CEdges = addFunctionVertex(Fun); - CEdges->reserve(CallerIDs.size()); - - for (const auto &JId : CallerIDs) { - auto Id = JId.get(); - const auto *CS = IRDB->getInstruction(Id); - if (!CS) { - PHASAR_LOG_LEVEL_CAT(WARNING, "LLVMBasedICFG", - "Invalid CAll-Instruction Id: " << Id); - } - - addCallEdge(CS, Fun); - } +LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, + const nlohmann::json &SerializedCG, + LLVMTypeHierarchy *TH) + : CG(CallGraph::deserialize( + SerializedCG, + [IRDB](llvm::StringRef Name) { return IRDB->getFunction(Name); }, + [IRDB](size_t Id) { return IRDB->getInstruction(Id); })), + IRDB(IRDB) { + if (!TH) { + this->TH = std::make_unique(*IRDB); } } @@ -476,31 +408,6 @@ LLVMBasedICFG::~LLVMBasedICFG() = default; return NonCallStartNodes; } -[[nodiscard]] auto -LLVMBasedICFG::getCalleesOfCallAtImpl(n_t Inst) const noexcept - -> llvm::ArrayRef { - if (!llvm::isa(Inst)) { - return {}; - } - - auto MapEntry = CalleesAt.find(Inst); - if (MapEntry == CalleesAt.end()) { - return {}; - } - - return *MapEntry->second; -} - -[[nodiscard]] auto LLVMBasedICFG::getCallersOfImpl(f_t Fun) const noexcept - -> llvm::ArrayRef { - auto MapEntry = CallersOf.find(Fun); - if (MapEntry == CallersOf.end()) { - return {}; - } - - return *MapEntry->second; -} - [[nodiscard]] auto LLVMBasedICFG::getCallsFromWithinImpl(f_t Fun) const -> llvm::SmallVector { llvm::SmallVector CallSites; @@ -521,49 +428,16 @@ LLVMBasedICFG::getCalleesOfCallAtImpl(n_t Inst) const noexcept } void LLVMBasedICFG::printImpl(llvm::raw_ostream &OS) const { - OS << "digraph CallGraph{\n"; - scope_exit CloseBrace = [&OS] { OS << "}\n"; }; - - for (const auto *Fun : VertexFunctions) { - OS << uintptr_t(Fun) << "[label=\""; - OS.write_escaped(Fun->getName()); - OS << "\"];\n"; - for (const auto &Inst : llvm::instructions(Fun)) { - if (!llvm::isa(Inst)) { - continue; - } - - if (auto It = CalleesAt.find(&Inst); It != CalleesAt.end()) { - for (const auto *Succ : *It->second) { - assert(CallersOf.count(Succ)); - OS << uintptr_t(Fun) << "->" << uintptr_t(Succ) << "[label=\""; - OS.write_escaped(llvmIRToStableString(&Inst)); - OS << "\"]\n;"; - } - } - } - OS << '\n'; - } + CG.printAsDot( + OS, [](f_t Fun) { return Fun->getName(); }, + [](n_t CS) { return CS->getFunction(); }, + [](n_t CS) { return llvmIRToStableString(CS); }); } [[nodiscard]] nlohmann::json LLVMBasedICFG::getAsJsonImpl() const { - nlohmann::json J; - - auto &Edges = J[PhasarConfig::JsonCallGraphID().str()]; - for (const auto &[Fun, Callers] : CallersOf) { - auto &JCallers = Edges[Fun->getName().str()]; - - for (const auto *CS : *Callers) { - JCallers.push_back(IRDB->getInstructionId(CS)); - } - } - - return J; -} - -auto LLVMBasedICFG::getAllVertexFunctions() const noexcept - -> llvm::ArrayRef { - return VertexFunctions; + return CG.getAsJson( + [](f_t F) { return F->getName().str(); }, + [this](n_t Inst) { return IRDB->getInstructionId(Inst); }); } } // namespace psr diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp index ec1d476da..35619ce5a 100644 --- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGSerializationTest.cpp @@ -26,8 +26,8 @@ class LLVMBasedICFGGSerializationTest : public ::testing::Test { void compareResults(const psr::LLVMBasedICFG &Orig, const psr::LLVMBasedICFG &Deser) { - EXPECT_EQ(Orig.getAllVertexFunctions().size(), - Deser.getAllVertexFunctions().size()); + + EXPECT_EQ(Orig.getNumVertexFunctions(), Deser.getNumVertexFunctions()); { llvm::DenseSet DeserFuns( From 4f568a7bfb9c2bf0bca6e0821ac4a803e69e6588 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Mon, 5 Jun 2023 17:47:07 +0200 Subject: [PATCH 10/59] Phasar DynLib and LTO (#621) * Add consolidated header files * Add build rules for building a fat lib * Some docs * Follow new practices in myphasartool * Update docs * minor in docs + pre-commit * Changes according to review * Add CG to ControlFlow.h --------- Co-authored-by: Martin Mory --- BreakingChanges.md | 32 +-- CMakeLists.txt | 43 +++- README.md | 184 +++++++++++------- cmake/phasar_macros.cmake | 19 +- examples/use-phasar-as-library/CMakeLists.txt | 1 - examples/use-phasar-as-library/README.md | 7 +- include/phasar.h | 27 +++ include/phasar/AnalysisStrategy.h | 20 ++ include/phasar/Config.h | 16 ++ include/phasar/ControlFlow.h | 20 ++ include/phasar/Controller.h | 16 ++ include/phasar/DB.h | 17 ++ include/phasar/DataFlow.h | 36 ++++ include/phasar/Domain.h | 17 ++ include/phasar/PhasarClang.h | 18 ++ include/phasar/PhasarLLVM.h | 26 +++ include/phasar/PhasarLLVM/ControlFlow.h | 23 +++ include/phasar/PhasarLLVM/DB.h | 15 ++ include/phasar/PhasarLLVM/DataFlow.h | 33 ++++ include/phasar/PhasarLLVM/Domain.h | 15 ++ include/phasar/PhasarLLVM/Passes.h | 17 ++ include/phasar/PhasarLLVM/Pointer.h | 22 +++ .../Pointer/TypeGraphs/CachedTypeGraph.h | 5 +- .../Pointer/TypeGraphs/LazyTypeGraph.h | 1 - include/phasar/PhasarLLVM/TaintConfig.h | 17 ++ include/phasar/PhasarLLVM/TypeHierarchy.h | 16 ++ .../TypeHierarchy/LLVMTypeHierarchy.h | 6 +- include/phasar/PhasarLLVM/Utils.h | 21 ++ include/phasar/PhasarPass.h | 18 ++ include/phasar/Pointer.h | 22 +++ include/phasar/TypeHierarchy.h | 16 ++ include/phasar/Utils.h | 37 ++++ lib/CMakeLists.txt | 48 +++++ lib/LibPhasar.cpp | 10 + tools/example-tool/CMakeLists.txt | 29 +-- tools/example-tool/myphasartool.cpp | 12 +- .../TypeHierarchy/TypeGraphTest.cpp | 4 +- 37 files changed, 724 insertions(+), 162 deletions(-) create mode 100644 include/phasar.h create mode 100644 include/phasar/AnalysisStrategy.h create mode 100644 include/phasar/Config.h create mode 100644 include/phasar/ControlFlow.h create mode 100644 include/phasar/Controller.h create mode 100644 include/phasar/DB.h create mode 100644 include/phasar/DataFlow.h create mode 100644 include/phasar/Domain.h create mode 100644 include/phasar/PhasarClang.h create mode 100644 include/phasar/PhasarLLVM.h create mode 100644 include/phasar/PhasarLLVM/ControlFlow.h create mode 100644 include/phasar/PhasarLLVM/DB.h create mode 100644 include/phasar/PhasarLLVM/DataFlow.h create mode 100644 include/phasar/PhasarLLVM/Domain.h create mode 100644 include/phasar/PhasarLLVM/Passes.h create mode 100644 include/phasar/PhasarLLVM/Pointer.h create mode 100644 include/phasar/PhasarLLVM/TaintConfig.h create mode 100644 include/phasar/PhasarLLVM/TypeHierarchy.h create mode 100644 include/phasar/PhasarLLVM/Utils.h create mode 100644 include/phasar/PhasarPass.h create mode 100644 include/phasar/Pointer.h create mode 100644 include/phasar/TypeHierarchy.h create mode 100644 include/phasar/Utils.h create mode 100644 lib/LibPhasar.cpp diff --git a/BreakingChanges.md b/BreakingChanges.md index 2d73d94c6..477de93b7 100644 --- a/BreakingChanges.md +++ b/BreakingChanges.md @@ -1,29 +1,33 @@ # Breaking Changes +## Development HEAD + +- Default build mode is no longer `SHARED` but `STATIC`. To build in shared mode, use the cmake option `BUILD_SHARED_LIBS` which we don't recommend anymore. Consider using `PHASAR_BUILD_DYNLIB` instead to build one big libphasar.so. + ## v0323 - `EdgeFunctionPtrType` is no longer a `std::shared_ptr`. Instead `EdgeFunction` should be used directly. `EdgeFunction` is now a *value-type* that encapsulates its memory management by itself. - Concrete `EdgeFunction` types no longer derive from any base-class. Instead they just need to implement the required API functions. `EdgeFunction` implementations should me move-constructible and can be implicitly cast to `EdgeFunction`. To verify that your type implements the edge function interface use the `IsEdgeFunction` type trait. The API functions have been changed as follows: - - All API functions of `EdgeFunction` must be `const` qualified. - - `EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction)` and `EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction)` have been changed to `static EdgeFunction compose(EdgeFunctionRef This, const EdgeFunction& SecondFunction)` and `static EdgeFunction join(EdgeFunctionRef This, const EdgeFunction& OtherFunction)` respectively. Here, the `This` parameter models the former `shared_from_this()`. - - `bool equal_to(EdgeFunctionPtrType Other)const` has been changed to `bool operator==(const T &Other)const noexcept`, where `T` is your concrete edge function type. - - `void print(llvm::raw_ostream &OS, bool IsForDebug)` has been changed to `friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const T& EF)`. + - All API functions of `EdgeFunction` must be `const` qualified. + - `EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction)` and `EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction)` have been changed to `static EdgeFunction compose(EdgeFunctionRef This, const EdgeFunction& SecondFunction)` and `static EdgeFunction join(EdgeFunctionRef This, const EdgeFunction& OtherFunction)` respectively. Here, the `This` parameter models the former `shared_from_this()`. + - `bool equal_to(EdgeFunctionPtrType Other)const` has been changed to `bool operator==(const T &Other)const noexcept`, where `T` is your concrete edge function type. + - `void print(llvm::raw_ostream &OS, bool IsForDebug)` has been changed to `friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const T& EF)`. - `EdgeFunction` is tagged with `[[clang::trivial_abi]]`. Hence, you should not rely on any destruction order within a top-level statement that uses temporary `EdgeFunction` objects. - `EdgeFunctionSingletonFactory` has been removed. Use `EdgeFunctionSingletonCache` instead. - `TaintConfig` has been renamed to `LLVMTaintConfig`. For generic code you may want to use the LLVM-independent `TaintConfigBase` CRTP interface instead. - Renamed `phasar/PhasarLLVM/DataFlowSolver/` to either `phasar/DataFlow/` or `phasar/PhasarLLVM/DataFlow/` depending on whether the components need LLVMCore. Analoguous changes in `lib/` and `unittests/`. An incomplete list of moved/renamed files: - - `phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/*` => `phasar/DataFlow/IfdsIde/Solver/*` - - `phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h` => `phasar/DataFlow/IfdsIde/IDETabulationProblem.h` - - `phasar/DB/LLVMProjectIRDB.h` => `phasar/PhasarLLVM/DB/LLVMProjectIRDB.h` - - ... + - `phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/*` => `phasar/DataFlow/IfdsIde/Solver/*` + - `phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h` => `phasar/DataFlow/IfdsIde/IDETabulationProblem.h` + - `phasar/DB/LLVMProjectIRDB.h` => `phasar/PhasarLLVM/DB/LLVMProjectIRDB.h` + - ... - Renamed and split up some libraries: - - `phasar_phasarllvm_utils` => `phasar_llvm_utils` - - `phasar_typehierarchy` => `phasar_llvm_typehierarchy` - - `phasar_ifdside` => `phasar_llvm_ifdside` - - `phasar_controlflow` has its LLVM dependent stuff moved to `phasar_llvm_controlflow` - - `phasar_db` has its LLVM dependent stuff moved to `phasar_llvm_db` - - `phasar_pointer` has its LLVM dependent stuff moved to `phasar_llvm_pointer` + - `phasar_phasarllvm_utils` => `phasar_llvm_utils` + - `phasar_typehierarchy` => `phasar_llvm_typehierarchy` + - `phasar_ifdside` => `phasar_llvm_ifdside` + - `phasar_controlflow` has its LLVM dependent stuff moved to `phasar_llvm_controlflow` + - `phasar_db` has its LLVM dependent stuff moved to `phasar_llvm_db` + - `phasar_pointer` has its LLVM dependent stuff moved to `phasar_llvm_pointer` - Renamed the phasar tool `phasar-llvm` to `phasar-cli` - `LLVMPointsTo[.*]` has been renamed to `LLVMAlias[.*]` - The ctor of `LLVMAliasSet` now takes the `LLVMProjectIRDB` as pointer instead of a reference to better document that it may capture the IRDB by reference. diff --git a/CMakeLists.txt b/CMakeLists.txt index f447abe60..42e842e31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,8 @@ -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required (VERSION 3.9) + +# Avoid IPO/LTO Warnings: +cmake_policy(SET CMP0069 NEW) +set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Check if we build within the llvm source tree if (DEFINED LLVM_MAIN_SRC_DIR) @@ -10,7 +14,7 @@ if (NOT PHASAR_IN_TREE) set(CMAKE_PROJECT_NAME "phasar") endif () -option(PHASAR_EXPERIMENTAL_CXX20 "Build phasar in C++20 mode. THis is an experimental feature" OFF) +option(PHASAR_EXPERIMENTAL_CXX20 "Build phasar in C++20 mode. This is an experimental feature" OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS YES) if(PHASAR_EXPERIMENTAL_CXX20) @@ -38,7 +42,21 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -fvisibility-inlines-hidden -fstack-protector-strong -ffunction-sections -fdata-sections -pipe -g") else() message(STATUS "Selected Release Build") + + include(CheckIPOSupported) + check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_SUPPORT_ERROR) + + + if(LTO_SUPPORTED) + message(STATUS "IPO/LTO enabled") + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) # LTO + else() + message(STATUS "IPO/LTO not supported: ${LTO_SUPPORT_ERROR}") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -fvisibility-inlines-hidden -fstack-protector-strong -ffunction-sections -fdata-sections -pipe") + endif() # Enable testing @@ -77,7 +95,12 @@ option(PHASAR_BUILD_DOC "Build documentation" OFF) option(PHASAR_DEBUG_LIBDEPS "Debug internal library dependencies (private linkage)" OFF) -option(BUILD_SHARED_LIBS "Build shared libraries (default is ON)" ON) +#option(BUILD_SHARED_LIBS "Build shared libraries (default is ON)" ON) +option(PHASAR_BUILD_DYNLIB "Build one fat shared library. Requires BUILD_SHARED_LIBS to be turned OFF (default is OFF)" OFF) + +if(PHASAR_BUILD_DYNLIB AND BUILD_SHARED_LIBS) + message(FATAL_ERROR "PHASAR_BUILD_DYNLIB is incompatible with BUILD_SHARED_LIBS") +endif() option(PHASAR_ENABLE_WARNINGS "Enable warnings" ON) if (PHASAR_ENABLE_WARNINGS) @@ -156,7 +179,7 @@ find_package(Threads) # Boost find_package(Boost 1.65.1 COMPONENTS graph ${BOOST_THREAD} REQUIRED) #find_package(Boost 1.72.0 COMPONENTS graph ${BOOST_THREAD} REQUIRED) -include_directories(${Boost_INCLUDE_DIRS}) +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) # Disable clang-tidy for the external projects set(CMAKE_CXX_CLANG_TIDY "") @@ -184,7 +207,7 @@ set(nlohmann_json_DIR ${PHASAR_SRC_DIR}/external/json/single_include/) # Json Schema Validator set(JSON_VALIDATOR_INSTALL ON) add_subdirectory(external/json-schema-validator) -include_directories(external/json-schema-validator/src/) +include_directories(SYSTEM external/json-schema-validator/src/) # now we finally add the subdirectory set(JSON_BuildTests OFF) @@ -194,8 +217,8 @@ add_subdirectory(external/json) # Googletest if (NOT PHASAR_IN_TREE) add_subdirectory(external/googletest EXCLUDE_FROM_ALL) - include_directories(external/googletest/googletest/include) - include_directories(external/googletest/googlemock/include) + include_directories(SYSTEM external/googletest/googletest/include) + include_directories(SYSTEM external/googletest/googlemock/include) else() # Set llvm distributed includes for gtest header include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include) @@ -205,13 +228,13 @@ endif() # SQL find_path(SQLITE3_INCLUDE_DIR NAMES sqlite3.h) find_library(SQLITE3_LIBRARY NAMES sqlite3) -include_directories(${SQLITE3_INCLUDE_DIR}) +include_directories(SYSTEM ${SQLITE3_INCLUDE_DIR}) # LLVM 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}) + include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) link_directories(${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS}) endif() @@ -265,7 +288,7 @@ endif() if (PHASAR_IN_TREE) # Phasar needs clang headers, specificaly some that are generated by clangs table-gen - include_directories( + include_directories(SYSTEM ${CLANG_INCLUDE_DIR} ${PHASAR_SRC_DIR}/../clang/include ${PROJECT_BINARY_DIR}/tools/clang/include diff --git a/README.md b/README.md index 1c82c87c5..8e27e018a 100644 --- a/README.md +++ b/README.md @@ -1,138 +1,145 @@ ![PhASAR logo](img/Logo_RGB/Phasar_Logo.png) -PhASAR a LLVM-based Static Analysis Framework -============================================= +# PhASAR a LLVM-based Static Analysis Framework [![C++ Standard](https://img.shields.io/badge/C++_Standard-C%2B%2B17-blue.svg?style=flat&logo=c%2B%2B)](https://isocpp.org/) [![GitHub license](https://img.shields.io/badge/license-MIT-blueviolet.svg)](https://raw.githubusercontent.com/secure-software-engineering/phasar/master/LICENSE.txt) Version 0323 -Secure Software Engineering Group ---------------------------------- +## Secure Software Engineering Group -+ Fabian Schiebel (fabian.schiebel@iem.fraunhofer.de), Martin Mory (martin.mory@upb.de), Philipp Dominik Schubert (philipp.schubert@upb.de) and others -+ Please also refer to https://phasar.org/ +PhASAR is primarily developed and maintained by the Secure Software Engineering Group at Heinz Nixdorf Institute (University of Paderborn) and Fraunhofer IEM. + +Lead developers of PhASAR are: Fabian Schiebel (@fabianbs96)(), Martin Mory (@MMory)(), Philipp Dominik Schubert (@pdschubert)() and others. + + + +## Required version of the C++ standard -Required version of the C++ standard ------------------------------------- PhASAR requires C++-17. -Currently supported version of LLVM ------------------------------------ -PhASAR is currently set up to support LLVM-14.0. +However, building in C++20 mode is supported as an experimental feature. You may enable this by turning the cmake option `PHASAR_EXPERIMENTAL_CXX20` on. +Although phasar currently does not make use of C++20 features (except for some `concept`s behind an #ifdef border), your client application that just *uses* phasar as a library may want to use C++20 ealier. + +## Currently supported version of LLVM + +PhASAR is currently set up to support LLVM-14.0.* + +## What is PhASAR? -What is PhASAR? ---------------- PhASAR is a LLVM-based static analysis framework written in C++. It allows users to specify arbitrary data-flow problems which are then solved in a fully-automated manner on the specified LLVM IR target code. Computing points-to information, call-graph(s), etc. is done by the framework, thus you can focus on what matters. -Breaking Changes ----------------- +## Breaking Changes + To keep PhASAR in a state that it is well suited for state-of-the-art research in static analysis, as well as for productive use, we have to make breaking changes. Please refer to [Breaking Changes](./BreakingChanges.md) for detailed information on what was broken recently and how to migrate. -How do I get started with PhASAR? ---------------------------------- -We have some documentation on PhASAR in our [_**Wiki**_](https://github.com/secure-software-engineering/phasar/wiki). You probably would like to read -this README first and then have a look on the material provided on https://phasar.org/ -as well. Please also have a look on PhASAR's project directory and notice the project directory -examples/ as well as the custom tool tools/myphasartool.cpp. +## How do I get started with PhASAR? + +We have some documentation on PhASAR in our [***Wiki***](https://github.com/secure-software-engineering/phasar/wiki). You probably would like to read +this README first. + +Please also have a look on PhASAR's project directory and notice the project directory `examples/` as well as the custom tool `tools/example-tool/myphasartool.cpp`. + +## Building PhASAR -Building PhASAR ---------------- -If you cannot work with one of the pre-built versions of PhASAR and would like to -compile PhASAR yourself, then please check the wiki for installing the -prerequisites and compilation. It is recommended to compile PhASAR yourself in -order to get the full C++ experience and to have full control over the build -mode. +It is recommended to compile PhASAR yourself in order to get the full C++ experience and to have full control over the build mode. +However, you may also want to try out one of the pre-built versions of PhASAR or the Docker container. -As a shortcut for the very first PhASAR build on your system, you can use our [bootstrap](./bootstrap.sh) script: +As a shortcut for the very first PhASAR build on your system, you can use our [bootstrap](./bootstrap.sh) script. +Please note that you must have python installed for the script to work properly. ```bash -$ ./bootstrap.sh +./bootstrap.sh ``` Note: If you want to do changes within PhASAR, it is recommended to build it in Debug mode: + ```bash -$ ./bootstrap.sh -DCMAKE_BUILD_TYPE=Debug +./bootstrap.sh -DCMAKE_BUILD_TYPE=Debug ``` The bootstrap script may ask for superuser permissions (to install the dependencies); however it is not recommended to start the whole script with `sudo`. For subsequent builds, see [Compiling PhASAR](#compiling-phasar-if-not-already-done-using-the-installation-scripts). -Please help us to improve PhASAR --------------------------------- +## Please help us to improve PhASAR + You are using PhASAR and would like to help us in the future? Then please support us by filling out this [web form](https://goo.gl/forms/YG6m3M7sxeUJmKyi1). By giving us feedback you help to decide in what direction PhASAR should stride in the future and give us clues about our user base. Thank you very much! +## Installation -Installation ------------- PhASAR can be installed using the installer scripts as explained in the following. - ### Installing PhASAR on an Ubuntu system + In the following, we would like to give an complete example of how to install PhASAR using an Ubuntu or Unix-like system. Therefore, we provide an installation script. To install PhASAR, just navigate to the top-level directory of PhASAR and use the following command: + ```bash -$ ./bootstrap.sh --install +./bootstrap.sh --install ``` The bootstrap script may ask for superuser permissions. Done! - ### Installing PhASAR a MacOS system + Due to unfortunate updates to MacOS and the handling of C++, especially on the newer M1 processors, we can't support native development on Mac. The easiest solution to develop PhASAR on a Mac right now is to use [dockers development environments](https://docs.docker.com/desktop/dev-environments/). Clone this repository as described in their documentation. Afterwards, you have to login once manually, as a root user by running `docker exec -it -u root /bin/bash` to complete the rest of the install process as described in this readme (install submodules, run bootstrap.sh, ...). Now you can just attach your docker container to VS Code or any other IDE, which supports remote development. ### Compiling PhASAR (if not already done using the installation scripts) + Set the system's variables for the C and C++ compiler to clang: + +```bash +export CC=/usr/local/bin/clang +export CXX=/usr/local/bin/clang++ ``` -$ export CC=/usr/local/bin/clang -$ export CXX=/usr/local/bin/clang++ -``` + You may need to adjust the paths according to your system. When you cloned PhASAR from Github you need to initialize PhASAR's submodules before building it: -``` -$ git submodule update --init +```bash +git submodule update --init ``` If you downloaded PhASAR as a compressed release (e.g. .zip or .tar.gz) you can use the `init-submodules-release.sh` script that manually clones the required submodules: -``` -$ utils/init-submodules-release.sh +```bash +utils/init-submodules-release.sh ``` Navigate into the PhASAR directory. The following commands will do the job and compile the PhASAR framework: -``` -$ mkdir build -$ cd build/ -$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. -$ ninja -j $(nproc) # or use a different number of cores to compile it -$ sudo ninja install # only if you wish to install PhASAR system wide +```bash +mkdir build +cd build/ +cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. +ninja -j $(nproc) # or use a different number of cores to compile it +sudo ninja install # only if you wish to install PhASAR system wide ``` When you have used the `bootstrap.sh` script to install PhASAR, the above steps are already done. Use them as a reference if you wish to modify PhASAR and recompile it. -After compilation using cmake the following two binaries can be found in the build/ directory: +After compilation using cmake the following two binaries can be found in the build/tools directory: -+ phasar-cli - the actual PhASAR command-line tool (previously called `phasar-llvm`) -+ myphasartool - an example tool that shows how tools can be build on top of PhASAR ++ `phasar-cli` - the PhASAR command-line tool (previously called `phasar-llvm`) that provides access to analyses that are already implemented within PhASAR. Use this if you don't want to build an own tool on top of PhASAR. ++ `myphasartool` - an example tool that shows how tools can be build on top of PhASAR Use the command: @@ -146,47 +153,76 @@ When using CMake to compile PhASAR the following optional parameters can be used | Parameter : Type| Effect | |-----------|--------| -| BUILD_SHARED_LIBS : BOOL | Build shared libraries (default is ON) | -| CMAKE_BUILD_TYPE : STRING | Build PhASAR in 'Debug' or 'Release' mode
(default is 'Debug') | -| CMAKE_INSTALL_PREFIX : PATH | Path where PhASAR will be installed if
"ninja install” is invoked or the “install”
target is built (default is /usr/local/phasar) | -| PHASAR_CONFIG_INSTALL_PREFIX : PATH | Path where PhASAR's configuration files will be installed if
ninja install” is invoked or the “install”
target is built. Expression will be evaluated within CMAKE_INSTALL_PREFIX, so prefer absolute paths (default is $(HOME)/.config/) | -| PHASAR_BUILD_DOC : BOOL | Build PhASAR documentation (default is OFF) | -| PHASAR_BUILD_UNITTESTS : BOOL | Build PhASAR unit tests (default is ON) | -| PHASAR_BUILD_IR : BOOL | Build PhASAR IR (required for running the unit tests) (default is ON) | -| PHASAR_BUILD_OPENSSL_TS_UNITTESTS : BOOL | Build PhASAR unit tests that require OpenSSL (default is OFF) | -| PHASAR_ENABLE_PAMM : STRING | Enable the performance measurement mechanism
('Off', 'Core' or 'Full', default is Off) | -| PHASAR_ENABLE_PIC : BOOL | Build Position-Independed Code (default is ON) | -| PHASAR_ENABLE_WARNINGS : BOOL | Enable compiler warnings (default is ON) | +| **BUILD_SHARED_LIBS** : BOOL | Build shared libraries -- Not recommended anymore. You may want to use PHASAR_BUILD_DYNLIB instead (default is OFF) | +| **PHASAR_BUILD_DYNLIB** : BOOL | Build one fat shared library (default is OFF) | +| **CMAKE_BUILD_TYPE** : STRING | Build PhASAR in 'Debug', 'RelWithDebInfo' or 'Release' mode (default is 'Debug') | +| **CMAKE_INSTALL_PREFIX** : PATH | Path where PhASAR will be installed if "ninja install” is invoked or the “install” target is built (default is /usr/local/phasar) | +| **PHASAR_CUSTOM_CONFIG_INSTALL_DIR** : PATH | If set, customizes the directory, where configuration files for PhASAR are installed (default is /usr/local/.phasar-config)| +| **PHASAR_ENABLE_DYNAMIC_LOG** : BOOL|Makes it possible to switch the logger on and off at runtime (default is ON)| +| **PHASAR_BUILD_DOC** : BOOL | Build PhASAR documentation (default is OFF) | +| **PHASAR_BUILD_UNITTESTS** : BOOL | Build PhASAR unit tests (default is ON) | +| **PHASAR_BUILD_IR** : BOOL | Build PhASAR IR (required for running the unit tests) (default is ON) | +| **PHASAR_BUILD_OPENSSL_TS_UNITTESTS** : BOOL | Build PhASAR unit tests that require OpenSSL (default is OFF) | +| **PHASAR_ENABLE_PAMM** : STRING | Enable the performance measurement mechanism ('Off', 'Core' or 'Full', default is Off) | +| **PHASAR_ENABLE_PIC** : BOOL | Build Position-Independed Code (default is ON) | +| **PHASAR_ENABLE_WARNINGS** : BOOL | Enable compiler warnings (default is ON) | +| **PHASAR_EXPERIMENTAL_CXX20** : BOOL|Build phasar in C++20 mode. This is an experimental feature (default is OFF)| You can use these parameters either directly or modify the installer-script `bootstrap.sh` #### A remark on compile time -C++'s long compile times are always a pain. As shown in the above, when using cmake the compilation can easily be run in parallel, resulting in shorter compilation times. Make use of it! +C++'s long compile times are always a pain. As shown in the above, when using cmake the compilation can easily be run in parallel, resulting in shorter compilation times. Make use of it! ### Running a test solver + To test if everything works as expected please run the following command: -`$ phasar-cli -m test/build_systems_tests/installation_tests/module.ll -D ifds-solvertest` +`$ phasar-cli -m test/llvm_test_code/basic/module_cpp.ll -D ifds-solvertest` If you obtain output other than a segmentation fault or an exception terminating the program abnormally everything works as expected. -How to use PhASAR? ------------------- -Please consult our [PhASAR wiki pages](https://github.com/secure-software-engineering/phasar/wiki). +## How to use PhASAR? + +We recomment using phasar as a library with `cmake`. + +If you already have installed phasar, [Use-PhASAR-as-a-library](https://github.com/secure-software-engineering/phasar/wiki/Using-Phasar-as-a-Library) may be a good start. + +Otherwise, we recommend adding PhASAR as a git submodule to your repository. +In this case, just `add_subdirectory` the phasar submodule directory and add phasar's include folder to your `include_directories` within your `CMakeLists.txt`. +Assuming you have checked out phasar in `external/phasar`, the phasar-related cmake commands may look like this: + +```cmake +set(PHASAR_BUILD_UNITTESTS OFF) # -- Don't build PhASAR's unittests with *your* tool +set(PHASAR_BUILD_IR OFF) # -- +add_subdirectory(external/phasar) # Build phasar with your tool +include_directories(external/phasar/include) # To find PhASAR's headers +link_libraries(nlohmann_json::nlohmann:json) # To find the json headers + +... + +target_link_libraries(yourphasartool + ... + phasar # Make your tool link against phasar +) +``` + +Depending on your use of PhASAR you also may need to add LLVM to your build. + +For more information please consult our [PhASAR wiki pages](https://github.com/secure-software-engineering/phasar/wiki). ### Installing PhASAR's Git pre-commit hook + You are very much welcome to contribute to the PhASAR project. Please make sure that you install our pre-commit hook that ensures your commit adheres to the most important coding rules of the PhASAR project. For more details please consult [Coding Conventions](https://github.com/secure-software-engineering/phasar/wiki/Coding-Conventions) and [Contributing to PhASAR](https://github.com/secure-software-engineering/phasar/wiki/Contributing-to-PhASAR). To install the pre-commit hook, please run the following commands in PhASAR's root directory: -``` -$ pip install pre-commit -$ pre-commit install - +```bash +pip install pre-commit +pre-commit install ``` Thanks. And have fun with the project. diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index 9fe7102f9..db0096471 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -14,24 +14,7 @@ function(add_phasar_unittest test_name) target_link_libraries(${test} LINK_PUBLIC - phasar_config - phasar_controller - phasar_llvm_controlflow - phasar_controlflow - phasar_llvm_utils - phasar_analysis_strategy - phasar_llvm_ifdside - phasar_utils - phasar_mono - phasar_llvm_db - phasar_db - # phasar_clang - phasar_passes - phasar_llvm_pointer - phasar_pointer - phasar_llvm_typehierarchy - phasar_llvm - phasar_taintconfig + phasar nlohmann_json_schema_validator ${SQLITE3_LIBRARY} ${Boost_LIBRARIES} diff --git a/examples/use-phasar-as-library/CMakeLists.txt b/examples/use-phasar-as-library/CMakeLists.txt index 6a2ac73bf..bba4e8e6d 100644 --- a/examples/use-phasar-as-library/CMakeLists.txt +++ b/examples/use-phasar-as-library/CMakeLists.txt @@ -19,7 +19,6 @@ link_directories(${PHASAR_LIBRARY_DIR}) phasar_config(myphasartool) - install(TARGETS myphasartool RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/examples/use-phasar-as-library/README.md b/examples/use-phasar-as-library/README.md index 46aa31cb6..44dbce6ea 100644 --- a/examples/use-phasar-as-library/README.md +++ b/examples/use-phasar-as-library/README.md @@ -1 +1,6 @@ -This is a demo tool that uses PhASAR as a library. The number of phasar libraries explicitly stated in CMakeLists.txt can be further reduced by stating the non-transitive dependencies of phasar libraries. This is pending work on the PhASAR side. +# Use PhASAR as a Library + +This small example shows how you can setup a CMake project that uses PhASAR as a library. +This guide assumes that you have installed PhASAR such that the `find_package` cmake command can find it. + +You can choose the PhASAR components that you need in the `find_package` command. diff --git a/include/phasar.h b/include/phasar.h new file mode 100644 index 000000000..d7ccfd4be --- /dev/null +++ b/include/phasar.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_H +#define PHASAR_H + +#include "phasar/AnalysisStrategy.h" +#include "phasar/Config.h" +#include "phasar/ControlFlow.h" +#include "phasar/Controller.h" +#include "phasar/DB.h" +#include "phasar/DataFlow.h" +#include "phasar/Domain.h" +#include "phasar/PhasarClang.h" +#include "phasar/PhasarLLVM.h" +#include "phasar/PhasarPass.h" +#include "phasar/Pointer.h" +#include "phasar/TypeHierarchy.h" +#include "phasar/Utils.h" + +#endif // PHASAR_H diff --git a/include/phasar/AnalysisStrategy.h b/include/phasar/AnalysisStrategy.h new file mode 100644 index 000000000..6471b2e23 --- /dev/null +++ b/include/phasar/AnalysisStrategy.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_ANALYSISSTRATEGY_H +#define PHASAR_ANALYSISSTRATEGY_H + +#include "phasar/AnalysisStrategy/AnalysisSetup.h" +#include "phasar/AnalysisStrategy/DemandDrivenAnalysis.h" +#include "phasar/AnalysisStrategy/IncrementalUpdateAnalysis.h" +#include "phasar/AnalysisStrategy/ModuleWiseAnalysis.h" +#include "phasar/AnalysisStrategy/Strategies.h" +#include "phasar/AnalysisStrategy/VariationalAnalysis.h" + +#endif // PHASAR_ANALYSISSTRATEGY_H diff --git a/include/phasar/Config.h b/include/phasar/Config.h new file mode 100644 index 000000000..81df120eb --- /dev/null +++ b/include/phasar/Config.h @@ -0,0 +1,16 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_CONFIG_H +#define PHASAR_CONFIG_H + +#include "phasar/Config/Configuration.h" +#include "phasar/Config/Version.h" + +#endif // PHASAR_CONFIG_H diff --git a/include/phasar/ControlFlow.h b/include/phasar/ControlFlow.h new file mode 100644 index 000000000..b820c0ec0 --- /dev/null +++ b/include/phasar/ControlFlow.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_CONTROLFLOW_H +#define PHASAR_CONTROLFLOW_H + +#include "phasar/ControlFlow/CFGBase.h" +#include "phasar/ControlFlow/CallGraph.h" +#include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/ControlFlow/CallGraphBase.h" +#include "phasar/ControlFlow/ICFGBase.h" +#include "phasar/ControlFlow/SpecialMemberFunctionType.h" + +#endif // PHASAR_CONTROLFLOW_H diff --git a/include/phasar/Controller.h b/include/phasar/Controller.h new file mode 100644 index 000000000..92d4c2202 --- /dev/null +++ b/include/phasar/Controller.h @@ -0,0 +1,16 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_CONTROLLER_H +#define PHASAR_CONTROLLER_H + +#include "phasar/Controller/AnalysisController.h" +#include "phasar/Controller/AnalysisControllerEmitterOptions.h" + +#endif // PHASAR_CONTROLLER_H diff --git a/include/phasar/DB.h b/include/phasar/DB.h new file mode 100644 index 000000000..f77b88f01 --- /dev/null +++ b/include/phasar/DB.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_DB_H +#define PHASAR_DB_H + +#include "phasar/DB/Hexastore.h" +#include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/DB/Queries.h" + +#endif // PHASAR_DB_H diff --git a/include/phasar/DataFlow.h b/include/phasar/DataFlow.h new file mode 100644 index 000000000..a642ae484 --- /dev/null +++ b/include/phasar/DataFlow.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_DATAFLOW_H +#define PHASAR_DATAFLOW_H + +#include "phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" +#include "phasar/DataFlow/IfdsIde/EntryPointUtils.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/InitialSeeds.h" +#include "phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h" +#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/PathEdge.h" +#include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/DataFlow/IfdsIde/SpecialSummaries.h" +#include "phasar/DataFlow/Mono/Contexts/CallStringCTX.h" +#include "phasar/DataFlow/Mono/InterMonoProblem.h" +#include "phasar/DataFlow/Mono/IntraMonoProblem.h" +#include "phasar/DataFlow/Mono/Solver/InterMonoSolver.h" +#include "phasar/DataFlow/Mono/Solver/IntraMonoSolver.h" + +#endif // PHASAR_DATAFLOW_H diff --git a/include/phasar/Domain.h b/include/phasar/Domain.h new file mode 100644 index 000000000..33adee8fc --- /dev/null +++ b/include/phasar/Domain.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_DOMAIN_H +#define PHASAR_DOMAIN_H + +#include "phasar/Domain/AnalysisDomain.h" +#include "phasar/Domain/BinaryDomain.h" +#include "phasar/Domain/LatticeDomain.h" + +#endif // PHASAR_DOMAIN_H diff --git a/include/phasar/PhasarClang.h b/include/phasar/PhasarClang.h new file mode 100644 index 000000000..1ff5571f6 --- /dev/null +++ b/include/phasar/PhasarClang.h @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_PHASARCLANG_H +#define PHASAR_PHASARCLANG_H + +#include "PhasarClang/ClangController.h" +#include "PhasarClang/RandomChangeASTConsumer.h" +#include "PhasarClang/RandomChangeFrontendAction.h" +#include "PhasarClang/RandomChangeVisitor.h" + +#endif // PHASAR_PHASARCLANG_H diff --git a/include/phasar/PhasarLLVM.h b/include/phasar/PhasarLLVM.h new file mode 100644 index 000000000..051d89822 --- /dev/null +++ b/include/phasar/PhasarLLVM.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_H +#define PHASAR_PHASARLLVM_H + +#include "PhasarLLVM/ControlFlow.h" +#include "PhasarLLVM/DB.h" +#include "PhasarLLVM/DataFlow.h" +#include "PhasarLLVM/Domain.h" +#include "PhasarLLVM/HelperAnalyses.h" +#include "PhasarLLVM/HelperAnalysisConfig.h" +#include "PhasarLLVM/Passes.h" +#include "PhasarLLVM/Pointer.h" +#include "PhasarLLVM/SimpleAnalysisConstructor.h" +#include "PhasarLLVM/TaintConfig.h" +#include "PhasarLLVM/TypeHierarchy.h" +#include "PhasarLLVM/Utils.h" + +#endif // PHASAR_PHASARLLVM_H diff --git a/include/phasar/PhasarLLVM/ControlFlow.h b/include/phasar/PhasarLLVM/ControlFlow.h new file mode 100644 index 000000000..0f4b30135 --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2023 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_CONTROLFLOW_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_H + +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_H diff --git a/include/phasar/PhasarLLVM/DB.h b/include/phasar/PhasarLLVM/DB.h new file mode 100644 index 000000000..e164ece2f --- /dev/null +++ b/include/phasar/PhasarLLVM/DB.h @@ -0,0 +1,15 @@ +/****************************************************************************** + * Copyright (c) 2023 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_DB_H +#define PHASAR_PHASARLLVM_DB_H + +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" + +#endif // PHASAR_PHASARLLVM_DB_H diff --git a/include/phasar/PhasarLLVM/DataFlow.h b/include/phasar/PhasarLLVM/DataFlow.h new file mode 100644 index 000000000..abae6a208 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2023 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_H +#define PHASAR_PHASARLLVM_DATAFLOW_H + +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h" +#include "phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h" +#include "phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h" +#include "phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h" +#include "phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h" +#include "phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h" + +#endif // PHASAR_PHASARLLVM_DATAFLOW_H diff --git a/include/phasar/PhasarLLVM/Domain.h b/include/phasar/PhasarLLVM/Domain.h new file mode 100644 index 000000000..db363c242 --- /dev/null +++ b/include/phasar/PhasarLLVM/Domain.h @@ -0,0 +1,15 @@ +/****************************************************************************** + * Copyright (c) 2023 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_DOMAIN_H +#define PHASAR_PHASARLLVM_DOMAIN_H + +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + +#endif // PHASAR_PHASARLLVM_DOMAIN_H diff --git a/include/phasar/PhasarLLVM/Passes.h b/include/phasar/PhasarLLVM/Passes.h new file mode 100644 index 000000000..9c65ea033 --- /dev/null +++ b/include/phasar/PhasarLLVM/Passes.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * Copyright (c) 2023 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_PASSES_H +#define PHASAR_PHASARLLVM_PASSES_H + +#include "phasar/PhasarLLVM/Passes/ExampleModulePass.h" +#include "phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h" +#include "phasar/PhasarLLVM/Passes/ValueAnnotationPass.h" + +#endif // PHASAR_PHASARLLVM_PASSES_H diff --git a/include/phasar/PhasarLLVM/Pointer.h b/include/phasar/PhasarLLVM/Pointer.h new file mode 100644 index 000000000..220567251 --- /dev/null +++ b/include/phasar/PhasarLLVM/Pointer.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2023 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_POINTER_H +#define PHASAR_PHASARLLVM_POINTER_H + +#include "phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" +#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" +#include "phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h" +#include "phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h" +#include "phasar/PhasarLLVM/Pointer/TypeGraphs/TypeGraph.h" + +#endif // PHASAR_PHASARLLVM_POINTER_H diff --git a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h index 1931705cf..3759c704c 100644 --- a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h @@ -22,12 +22,15 @@ #include "boost/graph/adjacency_list.hpp" #include "boost/graph/graph_traits.hpp" #include "boost/graph/reverse_graph.hpp" -#include "gtest/gtest_prod.h" #include #include #include +#ifndef FRIEND_TEST +#define FRIEND_TEST(TEST, CLASS) +#endif + namespace llvm { class StructType; } // namespace llvm diff --git a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h index 025a4ffd6..a29e6a45e 100644 --- a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h @@ -22,7 +22,6 @@ #include "boost/graph/adjacency_list.hpp" #include "boost/graph/graph_traits.hpp" #include "boost/graph/reverse_graph.hpp" -#include "gtest/gtest_prod.h" #include #include diff --git a/include/phasar/PhasarLLVM/TaintConfig.h b/include/phasar/PhasarLLVM/TaintConfig.h new file mode 100644 index 000000000..5335aaf59 --- /dev/null +++ b/include/phasar/PhasarLLVM/TaintConfig.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * Copyright (c) 2023 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_TAINTCONFIG_H +#define PHASAR_PHASARLLVM_TAINTCONFIG_H + +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" +#include "phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h" +#include "phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h" + +#endif // PHASAR_PHASARLLVM_TAINTCONFIG_H diff --git a/include/phasar/PhasarLLVM/TypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy.h new file mode 100644 index 000000000..a8a9b4d12 --- /dev/null +++ b/include/phasar/PhasarLLVM/TypeHierarchy.h @@ -0,0 +1,16 @@ +/****************************************************************************** + * Copyright (c) 2023 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_TYPEHIERARCHY_H +#define PHASAR_PHASARLLVM_TYPEHIERARCHY_H + +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" + +#endif // PHASAR_PHASARLLVM_TYPEHIERARCHY_H diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h index 6024792d8..51b0e853f 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h @@ -24,7 +24,6 @@ #include "boost/graph/adjacency_list.hpp" #include "boost/graph/graph_traits.hpp" -#include "gtest/gtest_prod.h" #include "nlohmann/json.hpp" #include @@ -34,6 +33,10 @@ #include #include +#ifndef FRIEND_TEST +#define FRIEND_TEST(TEST, CLASS) +#endif + namespace llvm { class Module; class StructType; @@ -132,7 +135,6 @@ class LLVMTypeHierarchy std::vector getVirtualFunctions(const llvm::Module &M, const llvm::StructType &Type); - // FRIEND_TEST(VTableTest, SameTypeDifferentVTables); FRIEND_TEST(LTHTest, GraphConstruction); FRIEND_TEST(LTHTest, HandleLoadAndPrintOfNonEmptyGraph); diff --git a/include/phasar/PhasarLLVM/Utils.h b/include/phasar/PhasarLLVM/Utils.h new file mode 100644 index 000000000..cda1b77dc --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2023 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_UTILS_H +#define PHASAR_PHASARLLVM_UTILS_H + +#include "phasar/PhasarLLVM/Utils/Annotation.h" +#include "phasar/PhasarLLVM/Utils/BasicBlockOrdering.h" +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" +#include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" +#include "phasar/PhasarLLVM/Utils/LLVMCXXShorthands.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + +#endif // PHASAR_PHASARLLVM_UTILS_H diff --git a/include/phasar/PhasarPass.h b/include/phasar/PhasarPass.h new file mode 100644 index 000000000..aa8eb9b98 --- /dev/null +++ b/include/phasar/PhasarPass.h @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_PHASARPASS_H +#define PHASAR_PHASARPASS_H + +#include "PhasarPass/Options.h" +#include "PhasarPass/PhasarPass.h" +#include "PhasarPass/PhasarPrinterPass.h" +#include "PhasarPass/RegisterPasses.h" + +#endif // PHASAR_PHASARPASS_H diff --git a/include/phasar/Pointer.h b/include/phasar/Pointer.h new file mode 100644 index 000000000..def25c239 --- /dev/null +++ b/include/phasar/Pointer.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_POINTER_H +#define PHASAR_POINTER_H + +#include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/AliasInfo.h" +#include "phasar/Pointer/AliasInfoBase.h" +#include "phasar/Pointer/AliasInfoTraits.h" +#include "phasar/Pointer/AliasResult.h" +#include "phasar/Pointer/AliasSetOwner.h" +#include "phasar/Pointer/PointsToInfo.h" +#include "phasar/Pointer/PointsToInfoBase.h" + +#endif // PHASAR_POINTER_H diff --git a/include/phasar/TypeHierarchy.h b/include/phasar/TypeHierarchy.h new file mode 100644 index 000000000..d49fab367 --- /dev/null +++ b/include/phasar/TypeHierarchy.h @@ -0,0 +1,16 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_TYPEHIERARCHY_H +#define PHASAR_TYPEHIERARCHY_H + +#include "phasar/TypeHierarchy/TypeHierarchy.h" +#include "phasar/TypeHierarchy/VFTable.h" + +#endif // PHASAR_TYPEHIERARCHY_H diff --git a/include/phasar/Utils.h b/include/phasar/Utils.h new file mode 100644 index 000000000..f120b4faa --- /dev/null +++ b/include/phasar/Utils.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_H +#define PHASAR_UTILS_H + +#include "phasar/Utils/AnalysisProperties.h" +#include "phasar/Utils/BitVectorSet.h" +#include "phasar/Utils/BoxedPointer.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/DOTGraph.h" +#include "phasar/Utils/DebugOutput.h" +#include "phasar/Utils/EnumFlags.h" +#include "phasar/Utils/EquivalenceClassMap.h" +#include "phasar/Utils/ErrorHandling.h" +#include "phasar/Utils/IO.h" +#include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/Logger.h" +#include "phasar/Utils/MaybeUniquePtr.h" +#include "phasar/Utils/MemoryResource.h" +#include "phasar/Utils/NlohmannLogging.h" +#include "phasar/Utils/Nullable.h" +#include "phasar/Utils/PAMMMacros.h" +#include "phasar/Utils/Printer.h" +#include "phasar/Utils/Soundness.h" +#include "phasar/Utils/StableVector.h" +#include "phasar/Utils/Table.h" +#include "phasar/Utils/TypeTraits.h" +#include "phasar/Utils/Utilities.h" + +#endif // PHASAR_UTILS_H diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c484c6e63..2045abbfe 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -8,3 +8,51 @@ add_subdirectory(Utils) add_subdirectory(Controller) add_subdirectory(Pointer) add_subdirectory(ControlFlow) + +set(PHASAR_LINK_LIBS + phasar_utils + phasar_passes + phasar_config + phasar_db + phasar_pointer + phasar_controlflow + + phasar_llvm_utils + phasar_llvm_db + phasar_llvm_pointer + phasar_llvm_typehierarchy + phasar_llvm_controlflow + + phasar_taintconfig + phasar_mono + phasar_llvm + phasar_llvm_ifdside + phasar_analysis_strategy + phasar_controller + ${Boost_LIBRARIES} +) + +set(LLVM_LINK_COMPONENTS + Core + Support + BitWriter + Analysis + Passes + Demangle +) + +# The fat lib relies on transitive dependencies... +set(PHASAR_DEBUG_LIBDEPS_SAVE ${PHASAR_DEBUG_LIBDEPS}) +set(PHASAR_DEBUG_LIBDEPS OFF) + +if(BUILD_SHARED_LIBS OR PHASAR_BUILD_DYNLIB) + add_phasar_library(phasar SHARED + LibPhasar.cpp + ) +else() + add_phasar_library(phasar STATIC + LibPhasar.cpp + ) +endif() + +set(PHASAR_DEBUG_LIBDEPS ${PHASAR_DEBUG_LIBDEPS_SAVE}) diff --git a/lib/LibPhasar.cpp b/lib/LibPhasar.cpp new file mode 100644 index 000000000..97bbc811c --- /dev/null +++ b/lib/LibPhasar.cpp @@ -0,0 +1,10 @@ +/****************************************************************************** + * Copyright (c) 2023 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 + *****************************************************************************/ + +#include "phasar.h" diff --git a/tools/example-tool/CMakeLists.txt b/tools/example-tool/CMakeLists.txt index 60cfbe1e8..aab2a9a7d 100644 --- a/tools/example-tool/CMakeLists.txt +++ b/tools/example-tool/CMakeLists.txt @@ -11,40 +11,13 @@ else() ) endif() -find_package(Boost COMPONENTS graph ${BOOST_THREAD} REQUIRED) target_link_libraries(myphasartool LINK_PUBLIC - phasar_config - phasar_controller - phasar_db - phasar_llvm_db - phasar_llvm_controlflow - phasar_controlflow - phasar_llvm_ifdside - phasar_mono - phasar_passes - phasar_llvm_pointer - phasar_pointer - phasar_llvm_typehierarchy - phasar_llvm - phasar_llvm_utils - phasar_utils - ${Boost_LIBRARIES} - ${CMAKE_DL_LIBS} - ${CMAKE_THREAD_LIBS_INIT} + phasar LINK_PRIVATE ${PHASAR_STD_FILESYSTEM} ) -if(USE_LLVM_FAT_LIB) - llvm_config(myphasartool USE_SHARED ${LLVM_LINK_COMPONENTS}) -else() - llvm_config(myphasartool ${LLVM_LINK_COMPONENTS}) -endif() - -set(LLVM_LINK_COMPONENTS -) - install(TARGETS myphasartool RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/tools/example-tool/myphasartool.cpp b/tools/example-tool/myphasartool.cpp index fbfc269c6..02ee6b2fc 100644 --- a/tools/example-tool/myphasartool.cpp +++ b/tools/example-tool/myphasartool.cpp @@ -7,17 +7,7 @@ * Philipp Schubert and others *****************************************************************************/ -#include "phasar/ControlFlow/CallGraphAnalysisType.h" -#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" -#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" -#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h" -#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h" -#include "phasar/PhasarLLVM/HelperAnalyses.h" -#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" -#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" -#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar.h" #include #include diff --git a/unittests/PhasarLLVM/TypeHierarchy/TypeGraphTest.cpp b/unittests/PhasarLLVM/TypeHierarchy/TypeGraphTest.cpp index 8f2f088e5..6fdc22e50 100644 --- a/unittests/PhasarLLVM/TypeHierarchy/TypeGraphTest.cpp +++ b/unittests/PhasarLLVM/TypeHierarchy/TypeGraphTest.cpp @@ -1,3 +1,6 @@ +#include "gtest/gtest.h" +// -- Need gtest for the FRIEND_TEST macro + #include "phasar/Config/Configuration.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h" @@ -9,7 +12,6 @@ #include "TestConfig.h" #include "boost/graph/isomorphism.hpp" -#include "gtest/gtest.h" using namespace std; using namespace psr; From 2b4ec1cb2e5a5fbd81302af548d8cbe803c0d813 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 15 Jun 2023 13:42:39 +0200 Subject: [PATCH 11/59] Misc Fixes II (#625) * Fix some bugs * Add utils to LLVMIRToSrc * Make the Container type parameter of the flow function templates actually settable * Fix recursive template instantiation in C++20 mode * feat: boolean to toggle trim * Fix fromMetaDataId + add deserialization support for LLVMBasedICFG * pre-commit * IRDB ctor with pre-loaded IR * Add chrono utils for formatting std::chrono::duration * Real constness within SolverResults * Improve Table + minor * Fix crash in LCA * minor * Make myphasartool link properly with BUILD_SHARED_LIBS --------- Co-authored-by: Sriteja Kummita --- .../DataFlow/IfdsIde/EdgeFunctionUtils.h | 6 + .../DataFlow/IfdsIde/Solver/IDESolver.h | 33 ++- .../phasar/DataFlow/IfdsIde/SolverResults.h | 28 +-- .../phasar/PhasarLLVM/DB/LLVMProjectIRDB.h | 5 +- .../DataFlow/IfdsIde/LLVMSolverResults.h | 4 +- include/phasar/Utils/ChronoUtils.h | 55 +++++ include/phasar/Utils/DefaultValue.h | 45 ++++ include/phasar/Utils/EquivalenceClassMap.h | 9 +- include/phasar/Utils/Table.h | 210 +++++++++--------- lib/Controller/AnalysisController.cpp | 10 +- lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp | 24 ++ lib/Utils/ChronoUtils.cpp | 7 + tools/example-tool/CMakeLists.txt | 1 + 13 files changed, 286 insertions(+), 151 deletions(-) create mode 100644 include/phasar/Utils/ChronoUtils.h create mode 100644 include/phasar/Utils/DefaultValue.h create mode 100644 lib/Utils/ChronoUtils.cpp diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h index 7d07cc5fa..5151556a2 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h @@ -425,6 +425,12 @@ ConstantEdgeFunction::join(EdgeFunctionRef This, if (auto Default = defaultJoinOrNull(This, OtherFunction)) { return Default; } + + if (llvm::isa>(OtherFunction)) { + // Prevent endless recursion + return AllBottom{}; + } + if (!OtherFunction.isConstant()) { // do not know how to join; hence ask other function to decide on this return OtherFunction.joinWith(This); diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 4564a2489..79831d811 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -1213,7 +1213,6 @@ class IDESolver { } void printIncomingTab() const { -#ifdef DYNAMIC_LOG IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Start of incomingtab entry"); for (const auto &Cell @@ -1231,29 +1230,27 @@ class IDESolver { } PHASAR_LOG_LEVEL(DEBUG, "---------------"); } PHASAR_LOG_LEVEL(DEBUG, "End of incomingtab entry");) -#endif } void printEndSummaryTab() const { -#ifdef DYNAMIC_LOG IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Start of endsummarytab entry"); - for (const auto &Cell - : EndsummaryTab.cellVec()) { - PHASAR_LOG_LEVEL(DEBUG, - "sP: " << IDEProblem.NtoString(Cell.getRowKey())); - PHASAR_LOG_LEVEL(DEBUG, - "d1: " << IDEProblem.DtoString(Cell.getColumnKey())); - for (const auto &InnerCell : Cell.getValue().cellVec()) { - PHASAR_LOG_LEVEL( - DEBUG, " eP: " << IDEProblem.NtoString(InnerCell.getRowKey())); - PHASAR_LOG_LEVEL(DEBUG, " d2: " << IDEProblem.DtoString( - InnerCell.getColumnKey())); - PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerCell.getValue()); - } + + EndsummaryTab.foreachCell([this](const auto &Row, const auto &Col, + const auto &Val) { + PHASAR_LOG_LEVEL(DEBUG, "sP: " << IDEProblem.NtoString(Row)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(Col)); + + Val.foreachCell([this](const auto &InnerRow, const auto &InnerCol, + const auto &InnerVal) { + PHASAR_LOG_LEVEL(DEBUG, " eP: " << IDEProblem.NtoString(InnerRow)); + PHASAR_LOG_LEVEL(DEBUG, " d2: " << IDEProblem.DtoString(InnerCol)); + PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerVal); + }); PHASAR_LOG_LEVEL(DEBUG, "---------------"); - } PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry");) -#endif + }); + + PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry");) } void printComputedPathEdges() { diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 6a5671a50..67d855dea 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 { @@ -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,15 +179,11 @@ 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); } private: - [[nodiscard]] Derived &self() noexcept { - static_assert(std::is_base_of_v); - return static_cast(*this); - } [[nodiscard]] const Derived &self() const noexcept { static_assert(std::is_base_of_v); return static_cast(*this); @@ -206,12 +202,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; }; @@ -229,16 +225,20 @@ class OwningSolverResults OwningSolverResults(Table ResTab, D ZV) noexcept(std::is_nothrow_move_constructible_v) - : Results(std::move(ResTab)), ZV(ZV) {} + : Results(std::move(ResTab)), ZV(std::move(ZV)) {} - [[nodiscard]] operator SolverResults() const &noexcept { + [[nodiscard]] SolverResults get() const &noexcept { return {Results, ZV}; } + SolverResults get() && = delete; + + [[nodiscard]] operator SolverResults() const &noexcept { + return get(); + } 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/PhasarLLVM/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h index d1b1789d2..c3abcad87 100644 --- a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h +++ b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h @@ -22,6 +22,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/raw_ostream.h" #include @@ -48,10 +49,12 @@ class LLVMProjectIRDB : public ProjectIRDBBase { /// CAUTION: Do not manage the same LLVM Module with multiple LLVMProjectIRDB /// instances at the same time! This will confuse the ModulesToSlotTracker explicit LLVMProjectIRDB(llvm::Module *Mod); - /// Initializes the new ProjectIRDB with the given IR Moduleand takes + /// Initializes the new ProjectIRDB with the given IR Module and takes /// ownership of it explicit LLVMProjectIRDB(std::unique_ptr Mod, bool DoPreprocessing = true); + /// Parses the given LLVM IR file and owns the resulting IR Module + explicit LLVMProjectIRDB(llvm::MemoryBufferRef Buf); LLVMProjectIRDB(const LLVMProjectIRDB &) = delete; LLVMProjectIRDB &operator=(LLVMProjectIRDB &) = delete; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h index 0e334cb33..d789958cc 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/include/phasar/Utils/ChronoUtils.h b/include/phasar/Utils/ChronoUtils.h new file mode 100644 index 000000000..d6acbf718 --- /dev/null +++ b/include/phasar/Utils/ChronoUtils.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_UTILS_CHRONO_UTILS_H +#define PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H + +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { + +/// Simple struct that allows formatting of time-durations as +/// hours:minutes:seconds.microseconds. +/// +/// \remark This feature may come into C++23, so until then, use this one. +struct hms { // NOLINT + std::chrono::hours Hours{}; + std::chrono::minutes Minutes{}; + std::chrono::seconds Seconds{}; + std::chrono::microseconds Micros{}; + + hms() noexcept = default; + hms(std::chrono::nanoseconds NS) noexcept { + using namespace std::chrono; + + Hours = duration_cast(NS); + NS -= Hours; + Minutes = duration_cast(NS); + NS -= Minutes; + Seconds = duration_cast(NS); + NS -= Seconds; + Micros = duration_cast(NS); + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const hms &HMS); + + [[nodiscard]] std::string str() const { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + OS << *this; + return Ret; + } +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H diff --git a/include/phasar/Utils/DefaultValue.h b/include/phasar/Utils/DefaultValue.h new file mode 100644 index 000000000..ad2afaf32 --- /dev/null +++ b/include/phasar/Utils/DefaultValue.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_UTILS_DEFAULTVALUE_H +#define PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H + +#include "phasar/Utils/ByRef.h" + +#include + +namespace psr { + +/// Gets a (cached) reference to the default-constructed value of type T. If T +/// is small and trivially default constructible, creates a temporary instead. +/// Useful for getters that return ByConstRef but need to handle the +/// non-existing-T case +template >> +[[nodiscard]] ByConstRef +getDefaultValue() noexcept(std::is_nothrow_default_constructible_v) { + auto DefaultConstruct = [] { + if constexpr (std::is_aggregate_v) { + return T{}; + } else { + return T(); + } + }; + + if constexpr (CanEfficientlyPassByValue) { + return DefaultConstruct(); + } else { + static T DefaultVal = DefaultConstruct(); + return DefaultVal; + } +} + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H diff --git a/include/phasar/Utils/EquivalenceClassMap.h b/include/phasar/Utils/EquivalenceClassMap.h index 7c84a168d..c93508fe3 100644 --- a/include/phasar/Utils/EquivalenceClassMap.h +++ b/include/phasar/Utils/EquivalenceClassMap.h @@ -10,6 +10,7 @@ #ifndef PHASAR_UTILS_EQUIVALENCECLASSMAP_H #define PHASAR_UTILS_EQUIVALENCECLASSMAP_H +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/iterator_range.h" #include @@ -148,10 +149,10 @@ template struct EquivalenceClassMap { } [[nodiscard]] const_iterator find(key_type Key) const { - return find_if(StoredData.begin(), StoredData.end(), - [&Key](const EquivalenceClassBucketT &Val) -> bool { - return Val.first.count(Key) >= 1; - }); + return llvm::find_if(StoredData, + [&Key](const EquivalenceClassBucketT &Val) -> bool { + return Val.first.count(Key) >= 1; + }); } [[nodiscard]] std::optional findValue(key_type Key) const { diff --git a/include/phasar/Utils/Table.h b/include/phasar/Utils/Table.h index 6b5511f64..24ac50ac0 100644 --- a/include/phasar/Utils/Table.h +++ b/include/phasar/Utils/Table.h @@ -17,10 +17,14 @@ #ifndef PHASAR_UTILS_TABLE_H_ #define PHASAR_UTILS_TABLE_H_ +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/DefaultValue.h" + #include "llvm/Support/raw_ostream.h" #include #include +#include #include #include @@ -29,62 +33,54 @@ namespace psr { template class Table { -private: - std::unordered_map> Tab; - public: struct Cell { - Cell() = default; - Cell(R Row, C Col, const V Val) - : Row(Row), Column(Col), Val(std::move(Val)) {} - ~Cell() = default; - Cell(const Cell &) = default; - Cell &operator=(const Cell &) = default; - Cell(Cell &&) noexcept = default; - Cell &operator=(Cell &&) noexcept = default; - - [[nodiscard]] R getRowKey() const { return Row; } - [[nodiscard]] C getColumnKey() const { return Column; } - [[nodiscard]] V getValue() const { return Val; } + Cell() noexcept = default; + Cell(R Row, C Col, V Val) noexcept + : Row(std::move(Row)), Column(std::move(Col)), Value(std::move(Val)) {} + + [[nodiscard]] ByConstRef getRowKey() const noexcept { return Row; } + [[nodiscard]] ByConstRef getColumnKey() const noexcept { return Column; } + [[nodiscard]] ByConstRef getValue() const noexcept { return Value; } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Cell &Cell) { return OS << "Cell: " << Cell.r << ", " << Cell.c << ", " << Cell.v; } - friend bool operator<(const Cell &Lhs, const Cell &Rhs) { - return std::tie(Lhs.Row, Lhs.Column, Lhs.Val) < - std::tie(Rhs.Row, Rhs.Column, Rhs.Val); + friend bool operator<(const Cell &Lhs, const Cell &Rhs) noexcept { + return std::tie(Lhs.Row, Lhs.Column, Lhs.Value) < + std::tie(Rhs.Row, Rhs.Column, Rhs.Value); } - friend bool operator==(const Cell &Lhs, const Cell &Rhs) { - return std::tie(Lhs.Row, Lhs.Column, Lhs.Val) == - std::tie(Rhs.Row, Rhs.Column, Rhs.Val); + friend bool operator==(const Cell &Lhs, const Cell &Rhs) noexcept { + return std::tie(Lhs.Row, Lhs.Column, Lhs.Value) == + std::tie(Rhs.Row, Rhs.Column, Rhs.Value); } - private: - R Row; - C Column; - V Val; + R Row{}; + C Column{}; + V Value{}; }; - Table() = default; - Table(const Table &T) = default; - Table &operator=(const Table &T) = default; + Table() noexcept = default; + + explicit Table(const Table &T) = default; + Table &operator=(const Table &T) = delete; + Table(Table &&T) noexcept = default; Table &operator=(Table &&T) noexcept = default; + ~Table() = default; void insert(R Row, C Column, V Val) { // Associates the specified value with the specified keys. - Tab[Row][Column] = std::move(Val); + Tab[std::move(Row)][std::move(Column)] = std::move(Val); } - void insert(const Table &T) { Tab.insert(T.table.begin(), T.table.end()); } - - void clear() { Tab.clear(); } + void clear() noexcept { Tab.clear(); } - [[nodiscard]] bool empty() const { return Tab.empty(); } + [[nodiscard]] bool empty() const noexcept { return Tab.empty(); } - [[nodiscard]] size_t size() const { return Tab.size(); } + [[nodiscard]] size_t size() const noexcept { return Tab.size(); } [[nodiscard]] std::set cellSet() const { // Returns a set of all row key / column key / value triplets. @@ -97,9 +93,25 @@ template class Table { return Result; } + template void foreachCell(Fn Handler) const { + for (const auto &M1 : Tab) { + for (const auto &M2 : M1.second) { + std::invoke(Handler, M1.first, M2.first, M2.second); + } + } + } + template void foreachCell(Fn Handler) { + for (auto &M1 : Tab) { + for (auto &M2 : M1.second) { + std::invoke(Handler, M1.first, M2.first, M2.second); + } + } + } + [[nodiscard]] std::vector cellVec() const { // Returns a vector of all row key / column key / value triplets. std::vector Result; + Result.reserve(Tab.size()); // better than nothing... for (const auto &M1 : Tab) { for (const auto &M2 : M1.second) { Result.emplace_back(M1.first, M2.first, M2.second); @@ -108,7 +120,7 @@ template class Table { return Result; } - [[nodiscard]] std::unordered_map column(C ColumnKey) const { + [[nodiscard]] std::unordered_map column(ByConstRef ColumnKey) const { // Returns a view of all mappings that have the given column key. std::unordered_map Column; for (const auto &Row : Tab) { @@ -119,31 +131,8 @@ template class Table { return Column; } - [[nodiscard]] std::multiset columnKeySet() const { - // Returns a set of column keys that have one or more values in the table. - std::multiset Result; - for (const auto &M1 : Tab) { - for (const auto &M2 : M1.second) { - Result.insert(M2.first); - } - } - return Result; - } - - [[nodiscard]] std::unordered_map> - columnMap() const { - // Returns a view that associates each column key with the corresponding map - // from row keys to values. - std::unordered_map> Result; - for (const auto &M1 : Tab) { - for (const auto &M2 : Tab.second) { - Result[M2.first][M1.first] = M2.second; - } - } - return Result; - } - - [[nodiscard]] bool contains(R RowKey, C ColumnKey) const { + [[nodiscard]] bool contains(ByConstRef RowKey, + ByConstRef ColumnKey) const noexcept { // Returns true if the table contains a mapping with the specified row and // column keys. if (auto RowIter = Tab.find(RowKey); RowIter != Tab.end()) { @@ -152,7 +141,7 @@ template class Table { return false; } - [[nodiscard]] bool containsColumn(C ColumnKey) const { + [[nodiscard]] bool containsColumn(ByConstRef ColumnKey) const noexcept { // Returns true if the table contains a mapping with the specified column. for (const auto &M1 : Tab) { if (M1.second.count(ColumnKey)) { @@ -162,80 +151,92 @@ template class Table { return false; } - [[nodiscard]] bool containsRow(R RowKey) const { + [[nodiscard]] bool containsRow(ByConstRef RowKey) const noexcept { // Returns true if the table contains a mapping with the specified row key. return Tab.count(RowKey); } - [[nodiscard]] bool containsValue(const V &Value) const { - // Returns true if the table contains a mapping with the specified value. - for (const auto &M1 : Tab) { - for (const auto &M2 : M1.second) { - if (Value == M2.second) { - return true; - } - } - } - return false; + [[nodiscard]] V &get(R RowKey, C ColumnKey) { + // Returns the value corresponding to the given row and column keys, or V() + // if no such mapping exists. + return Tab[std::move(RowKey)][std::move(ColumnKey)]; } - [[nodiscard]] V &get(R RowKey, C ColumnKey) { - // Returns the value corresponding to the given row and column keys, or null + [[nodiscard]] ByConstRef get(ByConstRef RowKey, + ByConstRef ColumnKey) const noexcept { + // Returns the value corresponding to the given row and column keys, or V() // if no such mapping exists. - return Tab[RowKey][ColumnKey]; + auto OuterIt = Tab.find(RowKey); + if (OuterIt == Tab.end()) { + return getDefaultValue(); + } + + auto It = OuterIt->second.find(ColumnKey); + if (It == OuterIt->second.end()) { + return getDefaultValue(); + } + + return It->second; } - V remove(R RowKey, C ColumnKey) { + V remove(ByConstRef RowKey, ByConstRef ColumnKey) { // Removes the mapping, if any, associated with the given keys. - V Val = Tab[RowKey][ColumnKey]; - Tab[RowKey].erase(ColumnKey); - return Val; + + auto OuterIt = Tab.find(RowKey); + if (OuterIt == Tab.end()) { + return V(); + } + + auto It = OuterIt->second.find(ColumnKey); + if (It == OuterIt->second.end()) { + return V(); + } + + auto Ret = std::move(It->second); + + OuterIt->second.erase(It); + if (OuterIt->second.empty()) { + Tab.erase(OuterIt); + } + + return Ret; } - void remove(R RowKey) { Tab.erase(RowKey); } + void remove(ByConstRef RowKey) { Tab.erase(RowKey); } [[nodiscard]] std::unordered_map &row(R RowKey) { // Returns a view of all mappings that have the given row key. return Tab[RowKey]; } - [[nodiscard]] std::multiset rowKeySet() const { - // Returns a set of row keys that have one or more values in the table. - std::multiset Result; - for (const auto &M1 : Tab) { - Result.insert(M1.first); + [[nodiscard]] ByConstRef> + row(ByConstRef RowKey) const noexcept { + // Returns a view of all mappings that have the given row key. + auto It = Tab.find(RowKey); + if (It == Tab.end()) { + return getDefaultValue>(); } - return Result; + return It->second; } - [[nodiscard]] std::unordered_map> rowMap() const { + [[nodiscard]] const std::unordered_map> & + rowMap() const noexcept { // Returns a view that associates each row key with the corresponding map // from column keys to values. return Tab; } - [[nodiscard]] std::multiset values() const { - // Returns a collection of all values, which may contain duplicates. - std::multiset Result; - for (const auto &M1 : Tab) { - for (const auto &M2 : M1.second) { - Result.insert(M2.second); - } - } - return Result; + bool operator==(const Table &Other) noexcept { + return Tab == Other.Tab; } - friend bool operator==(const Table &Lhs, const Table &Rhs) { - return Lhs.table == Rhs.table; - } - - friend bool operator<(const Table &Lhs, const Table &Rhs) { - return Lhs.table < Rhs.table; + bool operator<(const Table &Other) noexcept { + return Tab < Other.Tab; } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Table &Tab) { - for (const auto &M1 : Tab.table) { + for (const auto &M1 : Tab.Tab) { for (const auto &M2 : M1.second) { OS << "< " << M1.first << " , " << M2.first << " , " << M2.second << " >\n"; @@ -243,6 +244,9 @@ template class Table { } return OS; } + +private: + std::unordered_map> Tab{}; }; } // namespace psr diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index 8406720ef..1341319a0 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -200,15 +200,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 & diff --git a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp index d06b52acc..c498c2c91 100644 --- a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp +++ b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp @@ -107,6 +107,30 @@ LLVMProjectIRDB::LLVMProjectIRDB(std::unique_ptr Mod, } } +LLVMProjectIRDB::LLVMProjectIRDB(llvm::MemoryBufferRef Buf) { + llvm::SMDiagnostic Diag; + std::unique_ptr M = llvm::parseIR(Buf, Diag, Ctx); + bool BrokenDebugInfo = false; + if (M == nullptr) { + Diag.print(nullptr, llvm::errs()); + return; + } + + if (llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) { + PHASAR_LOG_LEVEL(ERROR, Buf.getBufferIdentifier() + << " could not be parsed correctly!"); + return; + } + if (BrokenDebugInfo) { + PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!"); + } + + auto *NonConst = M.get(); + Mod = std::move(M); + ModulesToSlotTracker::setMSTForModule(Mod.get()); + preprocessModule(NonConst); +} + LLVMProjectIRDB::~LLVMProjectIRDB() { if (Mod) { ModulesToSlotTracker::deleteMSTForModule(Mod.get()); diff --git a/lib/Utils/ChronoUtils.cpp b/lib/Utils/ChronoUtils.cpp new file mode 100644 index 000000000..6540baf96 --- /dev/null +++ b/lib/Utils/ChronoUtils.cpp @@ -0,0 +1,7 @@ +#include "phasar/Utils/ChronoUtils.h" + +llvm::raw_ostream &psr::operator<<(llvm::raw_ostream &OS, const hms &HMS) { + return OS << llvm::format("%.2ld:%.2ld:%.2ld:%.6ld", HMS.Hours.count(), + HMS.Minutes.count(), HMS.Seconds.count(), + HMS.Micros.count()); +} diff --git a/tools/example-tool/CMakeLists.txt b/tools/example-tool/CMakeLists.txt index aab2a9a7d..c5aa75c2a 100644 --- a/tools/example-tool/CMakeLists.txt +++ b/tools/example-tool/CMakeLists.txt @@ -14,6 +14,7 @@ endif() target_link_libraries(myphasartool LINK_PUBLIC phasar + LLVM LINK_PRIVATE ${PHASAR_STD_FILESYSTEM} ) From 263ef58cff935158d8ea2d35e6f0effd5693c924 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 15 Jun 2023 14:25:41 +0200 Subject: [PATCH 12/59] Small refactoring of LLVMBasedAliasAnalysis + allow disabling the CFL-based alias analyses (#626) --- .../ControlFlow/CallGraphAnalysisType.def | 2 +- .../Pointer/LLVMBasedAliasAnalysis.h | 45 +++++++----- .../PhasarLLVM/Utils/BasicBlockOrdering.h | 1 + include/phasar/Pointer/AliasAnalysisType.def | 3 +- lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp | 3 +- .../Pointer/LLVMBasedAliasAnalysis.cpp | 69 ++++++++++++------- lib/PhasarLLVM/Utils/BasicBlockOrdering.cpp | 1 - 7 files changed, 77 insertions(+), 47 deletions(-) diff --git a/include/phasar/ControlFlow/CallGraphAnalysisType.def b/include/phasar/ControlFlow/CallGraphAnalysisType.def index c136232c0..3430b21c0 100644 --- a/include/phasar/ControlFlow/CallGraphAnalysisType.def +++ b/include/phasar/ControlFlow/CallGraphAnalysisType.def @@ -16,6 +16,6 @@ CALL_GRAPH_ANALYSIS_TYPE(CHA, "cha", "Class hierarchy analysis") CALL_GRAPH_ANALYSIS_TYPE(RTA, "rta", "Rapid type analysis") CALL_GRAPH_ANALYSIS_TYPE(DTA, "dta", "Declared type analysis") CALL_GRAPH_ANALYSIS_TYPE(VTA, "vta", "Variable type analysis") -CALL_GRAPH_ANALYSIS_TYPE(OTF, "otf", "On-the-fly analysis based on points-to info") +CALL_GRAPH_ANALYSIS_TYPE(OTF, "otf", "On-the-fly analysis based on points-to info (default)") #undef CALL_GRAPH_ANALYSIS_TYPE diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h b/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h index e724a0c4d..c37cfda21 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h @@ -13,8 +13,6 @@ #include "phasar/Pointer/AliasAnalysisType.h" #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/IR/PassManager.h" -#include "llvm/Passes/PassBuilder.h" namespace llvm { class Value; @@ -27,23 +25,19 @@ namespace psr { class LLVMProjectIRDB; class LLVMBasedAliasAnalysis { -private: - llvm::PassBuilder PB; - llvm::AAManager AA; - llvm::FunctionAnalysisManager FAM; - llvm::FunctionPassManager FPM; - llvm::DenseMap AAInfos; - AliasAnalysisType PATy; - - [[nodiscard]] bool hasAliasInfo(const llvm::Function &Fun) const; - - void computeAliasInfo(llvm::Function &Fun); public: - LLVMBasedAliasAnalysis(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, - AliasAnalysisType PATy = AliasAnalysisType::CFLAnders); + explicit LLVMBasedAliasAnalysis( + LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, + AliasAnalysisType PATy = AliasAnalysisType::Basic); - ~LLVMBasedAliasAnalysis() = default; + LLVMBasedAliasAnalysis(LLVMBasedAliasAnalysis &&) noexcept = default; + LLVMBasedAliasAnalysis & + operator=(LLVMBasedAliasAnalysis &&) noexcept = default; + + LLVMBasedAliasAnalysis(const LLVMBasedAliasAnalysis &) = delete; + LLVMBasedAliasAnalysis &operator=(const LLVMBasedAliasAnalysis &) = delete; + ~LLVMBasedAliasAnalysis(); void print(llvm::raw_ostream &OS = llvm::outs()) const; @@ -54,13 +48,26 @@ class LLVMBasedAliasAnalysis { return AAInfos.lookup(F); }; - void erase(llvm::Function *F); + void erase(llvm::Function *F) noexcept; - void clear(); + void clear() noexcept; - [[nodiscard]] inline AliasAnalysisType getPointerAnalysisType() const { + [[nodiscard]] inline AliasAnalysisType + getPointerAnalysisType() const noexcept { return PATy; }; + +private: + [[nodiscard]] bool hasAliasInfo(const llvm::Function &Fun) const; + + void computeAliasInfo(llvm::Function &Fun); + + // -- data members + + struct Impl; + std::unique_ptr PImpl; + AliasAnalysisType PATy; + llvm::DenseMap AAInfos; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h b/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h index 664f28304..4ec3570b5 100644 --- a/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h +++ b/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h @@ -12,6 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FunctionExtras.h" +#include "llvm/IR/Dominators.h" #include #include diff --git a/include/phasar/Pointer/AliasAnalysisType.def b/include/phasar/Pointer/AliasAnalysisType.def index 23fbe08c7..93c3599d7 100644 --- a/include/phasar/Pointer/AliasAnalysisType.def +++ b/include/phasar/Pointer/AliasAnalysisType.def @@ -11,8 +11,9 @@ #define ALIAS_ANALYSIS_TYPE(NAME, CMDFLAG, DESC) #endif +ALIAS_ANALYSIS_TYPE(Basic, "basic", "Basic LLVM alias resolving based on simple, local properties") ALIAS_ANALYSIS_TYPE(CFLSteens, "cflsteens", "Steensgaard-style alias analysis (equality-based)") -ALIAS_ANALYSIS_TYPE(CFLAnders, "cflanders", "Andersen-style alias analysis (subset-based)") +ALIAS_ANALYSIS_TYPE(CFLAnders, "cflanders", "Andersen-style alias analysis (subset-based) (default)") ALIAS_ANALYSIS_TYPE(PointsTo, "points-to", "Alias-information based on (external) points-to information") #undef ALIAS_ANALYSIS_TYPE diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp index b50121f61..07902f06c 100644 --- a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp @@ -13,6 +13,7 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Pointer/AliasAnalysisType.h" #include "phasar/Utils/BoxedPointer.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/NlohmannLogging.h" @@ -96,7 +97,7 @@ LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB, bool UseLazyEvaluation, LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB, const nlohmann::json &SerializedPTS) - : PTA(*IRDB) { + : PTA(*IRDB, true) { assert(IRDB != nullptr); // Assume, we already have validated the json schema diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp index 116fc022c..319dbc4b7 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp @@ -11,6 +11,7 @@ #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" +#include "phasar/Pointer/AliasAnalysisType.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" @@ -19,6 +20,7 @@ #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/CFLAndersAliasAnalysis.h" #include "llvm/Analysis/CFLSteensAliasAnalysis.h" +#include "llvm/Analysis/ScopedNoAliasAA.h" #include "llvm/Analysis/TypeBasedAliasAnalysis.h" #include "llvm/IR/Argument.h" #include "llvm/IR/BasicBlock.h" @@ -28,11 +30,18 @@ #include "llvm/IR/PassManager.h" #include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" +#include "llvm/Passes/PassBuilder.h" using namespace psr; namespace psr { +struct LLVMBasedAliasAnalysis::Impl { + llvm::PassBuilder PB{}; + llvm::FunctionAnalysisManager FAM{}; + llvm::FunctionPassManager FPM{}; +}; + static void printResults(llvm::AliasResult AR, bool P, const llvm::Value *V1, const llvm::Value *V2, const llvm::Module *M) { if (P) { @@ -88,44 +97,54 @@ bool LLVMBasedAliasAnalysis::hasAliasInfo(const llvm::Function &Fun) const { } void LLVMBasedAliasAnalysis::computeAliasInfo(llvm::Function &Fun) { - llvm::PreservedAnalyses PA = FPM.run(Fun, FAM); - llvm::AAResults &AAR = FAM.getResult(Fun); + assert(PImpl != nullptr); + llvm::PreservedAnalyses PA = PImpl->FPM.run(Fun, PImpl->FAM); + llvm::AAResults &AAR = PImpl->FAM.getResult(Fun); AAInfos.insert(std::make_pair(&Fun, &AAR)); } -void LLVMBasedAliasAnalysis::erase(llvm::Function *F) { +void LLVMBasedAliasAnalysis::erase(llvm::Function *F) noexcept { // after we clear all stuff, we need to set it up for the next function-wise // analysis AAInfos.erase(F); - FAM.clear(*F, F->getName()); + PImpl->FAM.clear(*F, F->getName()); } -void LLVMBasedAliasAnalysis::clear() { +void LLVMBasedAliasAnalysis::clear() noexcept { AAInfos.clear(); - FAM.clear(); + PImpl->FAM.clear(); } LLVMBasedAliasAnalysis::LLVMBasedAliasAnalysis(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy) - : PATy(PATy) { - AA.registerFunctionAnalysis(); - switch (PATy) { - case AliasAnalysisType::CFLAnders: - AA.registerFunctionAnalysis(); - break; - case AliasAnalysisType::CFLSteens: - AA.registerFunctionAnalysis(); - break; - default: - break; - } - AA.registerFunctionAnalysis(); - FAM.registerPass([&] { return std::move(AA); }); - PB.registerFunctionAnalyses(FAM); - llvm::FunctionPassManager FPM; - // Always verify the input. - FPM.addPass(llvm::VerifierPass()); + : PImpl(new Impl{}), PATy(PATy) { + + PImpl->FAM.registerPass([&] { + llvm::AAManager AA; + switch (PATy) { + case AliasAnalysisType::CFLAnders: + AA.registerFunctionAnalysis(); + break; + case AliasAnalysisType::CFLSteens: + AA.registerFunctionAnalysis(); + break; + case AliasAnalysisType::Basic: + [[fallthrough]]; + default: + break; + } + // Note: The order of the alias analyses is important. See LLVM's source + // code for reference (e.g. registerAAAnalyses() in + // llvm/CodeGen/CodeGenPassBuilder.h) + // + AA.registerFunctionAnalysis(); + AA.registerFunctionAnalysis(); + AA.registerFunctionAnalysis(); + return AA; + }); + PImpl->PB.registerFunctionAnalyses(PImpl->FAM); + if (!UseLazyEvaluation) { for (auto &F : *IRDB.getModule()) { if (!F.isDeclaration()) { @@ -135,6 +154,8 @@ LLVMBasedAliasAnalysis::LLVMBasedAliasAnalysis(LLVMProjectIRDB &IRDB, } } +LLVMBasedAliasAnalysis::~LLVMBasedAliasAnalysis() = default; + void LLVMBasedAliasAnalysis::print(llvm::raw_ostream &OS) const { OS << "Points-to Info:\n"; for (const auto &[Fn, AA] : AAInfos) { diff --git a/lib/PhasarLLVM/Utils/BasicBlockOrdering.cpp b/lib/PhasarLLVM/Utils/BasicBlockOrdering.cpp index 89a5f386a..ee642b6e1 100644 --- a/lib/PhasarLLVM/Utils/BasicBlockOrdering.cpp +++ b/lib/PhasarLLVM/Utils/BasicBlockOrdering.cpp @@ -2,7 +2,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" From 57dd51ae18cb98235ba928baf1e05d53f9f37e5f Mon Sep 17 00:00:00 2001 From: Martin Mory Date: Thu, 15 Jun 2023 18:30:56 +0200 Subject: [PATCH 13/59] Use temp databases in HexastoreTest to avoid IO (#628) Co-authored-by: Fabian Schiebel --- unittests/DB/HexastoreTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unittests/DB/HexastoreTest.cpp b/unittests/DB/HexastoreTest.cpp index 07e772dc1..06bc7ff83 100644 --- a/unittests/DB/HexastoreTest.cpp +++ b/unittests/DB/HexastoreTest.cpp @@ -11,7 +11,7 @@ using namespace psr; using namespace std; TEST(HexastoreTest, QueryBlankFieldEntries) { - Hexastore H("QueryBlankFieldEntries.sqlite"); + Hexastore H(""); H.put({{"one", "", ""}}); H.put({{"two", "", ""}}); H.put({{"", "three", ""}}); @@ -32,7 +32,7 @@ TEST(HexastoreTest, QueryBlankFieldEntries) { } TEST(HexastoreTest, AllQueryTypes) { - Hexastore H("AllQueryTypes.sqlite"); + Hexastore H(""); H.put({{"mary", "likes", "hexastores"}}); H.put({{"mary", "likes", "apples"}}); H.put({{"mary", "hates", "oranges"}}); @@ -143,7 +143,7 @@ TEST(HexastoreTest, StoreGraphNoEdgeLabels) { // llvm::outs() << "Graph G:" << std::endl; // boost::print_graph(G, boost::get(&Vertex::name, G)); - Hexastore HS("StoreGraphNoEdgeLabels.sqlite"); + Hexastore HS(""); // serialize graph G for (tie(EiStart, EEnd) = boost::edges(G); EiStart != EEnd; ++EiStart) { @@ -230,7 +230,7 @@ TEST(HexastoreTest, StoreGraphWithEdgeLabels) { // cout << boost::get(&Edge::edge_name, I, *ei_start) << endl; // } - Hexastore HS("StoreGraphWithEdgeLabels.sqlite"); + Hexastore HS(""); // serialize graph I for (tie(EiStart, EEnd) = boost::edges(I); EiStart != EEnd; ++EiStart) { From 6d1ef70658060d86c8a82621f90d20338795858e Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sun, 18 Jun 2023 13:11:43 +0200 Subject: [PATCH 14/59] Fix InitialSeeds for IFDS (#632) * Initialize IFDS edge values with bottom to ensure they are propagated in IDE Phase II * Add FIXME --- include/phasar/DataFlow/IfdsIde/InitialSeeds.h | 4 ++-- .../phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h index d12fca954..4273e43eb 100644 --- a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h +++ b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h @@ -32,7 +32,7 @@ template class InitialSeeds { InitialSeeds(const std::map> &Seeds) { for (const auto &[Node, Facts] : Seeds) { for (const auto &Fact : Facts) { - this->Seeds[Node][Fact] = BinaryDomain::TOP; + this->Seeds[Node][Fact] = BinaryDomain::BOTTOM; } } } @@ -42,7 +42,7 @@ template class InitialSeeds { template >> void addSeed(N Node, D Fact) { - addSeed(Node, Fact, BinaryDomain::TOP); + addSeed(Node, Fact, BinaryDomain::BOTTOM); } void addSeed(N Node, D Fact, L Value) { diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h index d789958cc..4d17597b7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h @@ -21,6 +21,10 @@ namespace psr::detail { +/// FIXME: This is not entirely correct: Does not skip ignored statements and +/// does not work for backwards analyses. +/// The right way would be to ask the ICFG, but we don't have a reference to it +/// here yet (TODO!) template template auto SolverResultsBase::resultsAtInLLVMSSA( From 0605f7b65bbee9521da784e1aa46a83c98bc020a Mon Sep 17 00:00:00 2001 From: Martin Mory Date: Sun, 18 Jun 2023 13:31:22 +0200 Subject: [PATCH 15/59] Bump dependencies (#627) * Bump json + json-schema-validator * bump gtest --------- Co-authored-by: Fabian Schiebel Co-authored-by: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> --- CMakeLists.txt | 17 +++++++---------- external/googletest | 2 +- external/json | 2 +- external/json-schema-validator | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42e842e31..cec3c6243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,6 +184,13 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) # Disable clang-tidy for the external projects set(CMAKE_CXX_CLANG_TIDY "") +# Nlohmann JSON + +set(JSON_BuildTests OFF) +set(JSON_Install ON) +add_subdirectory(external/json) +include_directories(SYSTEM external/json/include/) + # We need to work around the behavior of nlohmann_json_schema_validator and nlohmann_json here # The validator needs the json part, but if you include it, the library of nlohmann_json_schema_validator # is not installed, leading to linker error. But just including nlohmann_json is not sufficient, as @@ -195,25 +202,15 @@ set(CMAKE_CXX_CLANG_TIDY "") #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(SYSTEM external/json/single_include/) - if (PHASAR_IN_TREE) set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json_schema_validator) endif() -set(nlohmann_json_DIR ${PHASAR_SRC_DIR}/external/json/single_include/) - # Json Schema Validator set(JSON_VALIDATOR_INSTALL ON) add_subdirectory(external/json-schema-validator) include_directories(SYSTEM external/json-schema-validator/src/) -# now we finally add the subdirectory -set(JSON_BuildTests OFF) -set(JSON_Install ON) -add_subdirectory(external/json) - # Googletest if (NOT PHASAR_IN_TREE) add_subdirectory(external/googletest EXCLUDE_FROM_ALL) diff --git a/external/googletest b/external/googletest index e2239ee60..b796f7d44 160000 --- a/external/googletest +++ b/external/googletest @@ -1 +1 @@ -Subproject commit e2239ee6043f73722e7aa812a459f54a28552929 +Subproject commit b796f7d44681514f58a683a3a71ff17c94edb0c1 diff --git a/external/json b/external/json index 4f8fba140..bc889afb4 160000 --- a/external/json +++ b/external/json @@ -1 +1 @@ -Subproject commit 4f8fba14066156b73f1189a2b8bd568bde5284c5 +Subproject commit bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d diff --git a/external/json-schema-validator b/external/json-schema-validator index 27fc1d094..6b17782d6 160000 --- a/external/json-schema-validator +++ b/external/json-schema-validator @@ -1 +1 @@ -Subproject commit 27fc1d094503623dfe39365ba82581507524545c +Subproject commit 6b17782d6a5d1dee5d2c4fc5d25ffb1123913431 From 6ef25f463ba15ef4ed81eb3f54c5d0c6a6a8e4e8 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sun, 18 Jun 2023 14:01:29 +0200 Subject: [PATCH 16/59] Worklist for IDESolver (#630) * Add worklist for Phase I in IDESolver * Add worklist for Phase II in IDESolver * Remove out-commented recursive calls in IDESolver * Remove unused variable --------- --- .../DataFlow/IfdsIde/Solver/IDESolver.h | 190 ++++++++++-------- .../phasar/DataFlow/IfdsIde/Solver/PathEdge.h | 17 +- 2 files changed, 116 insertions(+), 91 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 79831d811..79046f443 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -19,6 +19,8 @@ #include "phasar/Config/Configuration.h" #include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" @@ -154,6 +156,16 @@ class IDESolver { START_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); // We start our analysis and construct exploded supergraph submitInitialSeeds(); + + while (!WorkList.empty()) { + auto [Edge, EF] = std::move(WorkList.back()); + WorkList.pop_back(); + + auto [SourceVal, Target, TargetVal] = Edge.consume(); + propagate(std::move(SourceVal), std::move(Target), std::move(TargetVal), + std::move(EF)); + } + STOP_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); if (SolverConfig.computeValues()) { START_TIMER("DFA Phase II", PAMM_SEVERITY_LEVEL::Full); @@ -303,44 +315,6 @@ class IDESolver { } protected: - // have a shared point to allow for a copy constructor of IDESolver - IDETabulationProblem &IDEProblem; - d_t ZeroValue; - const i_t *ICF; - IFDSIDESolverConfig &SolverConfig; - unsigned PathEdgeCount = 0; - - FlowEdgeFunctionCache CachedFlowEdgeFunctions; - - Table> ComputedIntraPathEdges; - - Table> ComputedInterPathEdges; - - EdgeFunction AllTop; - - std::shared_ptr> JumpFn; - - std::map, std::vector>> - IntermediateEdgeFunctions; - - // stores summaries that were queried before they were computed - // see CC 2010 paper by Naeem, Lhotak and Rodriguez - Table>> EndsummaryTab; - - // edges going along calls - // see CC 2010 paper by Naeem, Lhotak and Rodriguez - Table> IncomingTab; - - // stores the return sites (inside callers) to which we have unbalanced - // returns if SolverConfig.followReturnPastSeeds is enabled - std::set UnbalancedRetSites; - - InitialSeeds Seeds; - - Table ValTab; - - std::map, size_t> FSummaryReuse; - /// Lines 13-20 of the algorithm; processing a call site in the caller's /// context. /// @@ -408,7 +382,8 @@ class IDESolver { DEBUG, "Queried Summary Edge Function: " << SumEdgFnE); PHASAR_LOG_LEVEL(DEBUG, "Compose: " << SumEdgFnE << " * " << f << '\n')); - propagate(d1, ReturnSiteN, d3, f.composeWith(SumEdgFnE), n, false); + WorkList.emplace_back(PathEdge(d1, ReturnSiteN, std::move(d3)), + f.composeWith(SumEdgFnE)); } } } else { @@ -435,10 +410,10 @@ class IDESolver { // create initial self-loop PHASAR_LOG_LEVEL(DEBUG, "Create initial self-loop with D: " << IDEProblem.DtoString(d3)); - propagate(d3, SP, d3, EdgeIdentity{}, n, - false); // line 15 - // register the fact that has an incoming edge from - // line 15.1 of Naeem/Lhotak/Rodriguez + WorkList.emplace_back(PathEdge(d3, SP, d3), + EdgeIdentity{}); // line 15 + // register the fact that has an incoming edge from + // line 15.1 of Naeem/Lhotak/Rodriguez addIncoming(SP, d3, n, d2); // line 15.2, copy to avoid concurrent modification exceptions by // other threads @@ -506,8 +481,9 @@ class IDESolver { d_t d5_restoredCtx = restoreContextOnReturnedFact(n, d2, d5); // propagte the effects of the entire call PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f); - propagate(d1, RetSiteN, d5_restoredCtx, f.composeWith(fPrime), - n, false); + WorkList.emplace_back( + PathEdge(d1, RetSiteN, std::move(d5_restoredCtx)), + f.composeWith(fPrime)); } } } @@ -541,7 +517,8 @@ class IDESolver { auto fPrime = f.composeWith(EdgeFnE); PHASAR_LOG_LEVEL(DEBUG, "Compose: " << EdgeFnE << " * " << f << " = " << fPrime); - propagate(d1, ReturnSiteN, d3, fPrime, n, false); + WorkList.emplace_back(PathEdge(d1, ReturnSiteN, std::move(d3)), + std::move(fPrime)); } } } @@ -550,15 +527,14 @@ class IDESolver { /// Simply propagate normal, intra-procedural flows. /// @param edge /// - virtual void processNormalFlow(const PathEdge Edge) { + virtual void processNormalFlow(PathEdge Edge) { PAMM_GET_INSTANCE; INC_COUNTER("Process Normal", 1, PAMM_SEVERITY_LEVEL::Full); PHASAR_LOG_LEVEL(DEBUG, "Process normal at target: " << IDEProblem.NtoString(Edge.getTarget())); - d_t d1 = Edge.factAtSource(); - n_t n = Edge.getTarget(); - d_t d2 = Edge.factAtTarget(); EdgeFunction f = jumpFunction(Edge); + auto [d1, n, d2] = Edge.consume(); + for (const auto nPrime : ICF->getSuccsOf(n)) { FlowFunctionPtrType FlowFunc = CachedFlowEdgeFunctions.getNormalFlowFunction(n, nPrime); @@ -579,7 +555,8 @@ class IDESolver { PHASAR_LOG_LEVEL(DEBUG, "Compose: " << g << " * " << f << " = " << fPrime); INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); - propagate(d1, nPrime, d3, fPrime, nullptr, false); + WorkList.emplace_back(PathEdge(d1, nPrime, std::move(d3)), + std::move(fPrime)); } } } @@ -637,7 +614,7 @@ class IDESolver { l_t LPrime = joinValueAt(NHashN, NHashD, ValNHash, L); if (!(LPrime == ValNHash)) { setVal(NHashN, NHashD, std::move(LPrime)); - valuePropagationTask(std::pair(NHashN, NHashD)); + ValuePropWL.emplace_back(std::move(NHashN), std::move(NHashD)); } } @@ -703,7 +680,7 @@ class IDESolver { } // should be made a callable at some point - void pathEdgeProcessingTask(const PathEdge Edge) { + void pathEdgeProcessingTask(PathEdge Edge) { PAMM_GET_INSTANCE; INC_COUNTER("JumpFn Construction", 1, PAMM_SEVERITY_LEVEL::Full); IF_LOG_ENABLED( @@ -730,15 +707,15 @@ class IDESolver { processExit(Edge); } if (!ICF->getSuccsOf(Edge.getTarget()).empty()) { - processNormalFlow(Edge); + processNormalFlow(std::move(Edge)); } } else { - processCall(Edge); + processCall(std::move(Edge)); } } // should be made a callable at some point - void valuePropagationTask(const std::pair NAndD) { + void valuePropagationTask(std::pair NAndD) { n_t n = NAndD.first; // our initial seeds are not necessarily method-start points but here they // should be treated as such the same also for unbalanced return sites in @@ -789,10 +766,7 @@ class IDESolver { DestVals.end()); } - /// Computes the final values for edge functions. - void computeValues() { - PHASAR_LOG_LEVEL(DEBUG, "Start computing values"); - // Phase II(i) + void submitInitialValues() { std::map> AllSeeds = Seeds.getSeeds(); for (n_t UnbalancedRetSite : UnbalancedRetSites) { if (AllSeeds.find(UnbalancedRetSite) == AllSeeds.end()) { @@ -811,9 +785,22 @@ class IDESolver { // information at the beginning of the value computation problem setVal(StartPoint, Fact, Value); std::pair SuperGraphNode(StartPoint, Fact); - valuePropagationTask(SuperGraphNode); + valuePropagationTask(std::move(SuperGraphNode)); } } + } + + /// Computes the final values for edge functions. + void computeValues() { + PHASAR_LOG_LEVEL(DEBUG, "Start computing values"); + // Phase II(i) + submitInitialValues(); + while (!ValuePropWL.empty()) { + auto NAndD = std::move(ValuePropWL.back()); + ValuePropWL.pop_back(); + valuePropagationTask(std::move(NAndD)); + } + // Phase II(ii) // we create an array of all nodes and then dispatch fractions of this // array to multiple threads @@ -861,8 +848,8 @@ class IDESolver { if (!IDEProblem.isZeroValue(Fact)) { INC_COUNTER("Gen facts", 1, PAMM_SEVERITY_LEVEL::Core); } - propagate(Fact, StartPoint, Fact, EdgeIdentity{}, nullptr, false); - JumpFn->addFunction(Fact, StartPoint, Fact, EdgeIdentity{}); + WorkList.emplace_back(PathEdge(Fact, StartPoint, Fact), + EdgeIdentity{}); } } } @@ -956,8 +943,9 @@ class IDESolver { d_t d3 = ValAndFunc.first; d_t d5_restoredCtx = restoreContextOnReturnedFact(c, d4, d5); PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f3); - propagate(d3, RetSiteC, d5_restoredCtx, - f3.composeWith(fPrime), c, false); + WorkList.emplace_back(PathEdge(std::move(d3), RetSiteC, + std::move(d5_restoredCtx)), + f3.composeWith(fPrime)); } } } @@ -1019,9 +1007,10 @@ class IDESolver { void propagteUnbalancedReturnFlow(n_t RetSiteC, d_t TargetVal, EdgeFunction EdgeFunc, - n_t RelatedCallSite) { - propagate(ZeroValue, RetSiteC, TargetVal, std::move(EdgeFunc), - RelatedCallSite, true); + n_t /*RelatedCallSite*/) { + WorkList.emplace_back( + PathEdge(ZeroValue, std::move(RetSiteC), std::move(TargetVal)), + std::move(EdgeFunc)); } /// This method will be called for each incoming edge and can be used to @@ -1124,11 +1113,7 @@ class IDESolver { /// but may be useful for subclasses of {@link IDESolver}) /// void propagate(d_t SourceVal, n_t Target, d_t TargetVal, - const EdgeFunction &f, - /* deliberately exposed to clients */ - n_t /*RelatedCallSite*/, - /* deliberately exposed to clients */ - bool /*IsUnbalancedReturn*/) { + EdgeFunction f) { PHASAR_LOG_LEVEL(DEBUG, "Propagate flow"); PHASAR_LOG_LEVEL(DEBUG, "Source value : " << IDEProblem.DtoString(SourceVal)); @@ -1166,9 +1151,9 @@ class IDESolver { PHASAR_LOG_LEVEL(DEBUG, ' ')); if (NewFunction) { JumpFn->addFunction(SourceVal, Target, TargetVal, fPrime); - const PathEdge Edge(SourceVal, Target, TargetVal); + PathEdge Edge(SourceVal, Target, TargetVal); PathEdgeCount++; - pathEdgeProcessingTask(Edge); + pathEdgeProcessingTask(std::move(Edge)); IF_LOG_ENABLED(if (!IDEProblem.isZeroValue(TargetVal)) { PHASAR_LOG_LEVEL( @@ -1332,7 +1317,6 @@ class IDESolver { // key std::unordered_map> ValidInCallerContext; size_t NumGenFacts = 0; - size_t NumKillFacts = 0; size_t NumIntraPathEdges = 0; size_t NumInterPathEdges = 0; // --- Intra-procedural Path Edges --- @@ -1353,10 +1337,6 @@ class IDESolver { // Case 2 else { NumGenFacts += D2s.size(); - // We ignore the zero value - if (!IDEProblem.isZeroValue(D1)) { - NumKillFacts++; - } } // Store all valid facts after call-to-return flow if (ICF->isCallSite(Edge.first)) { @@ -1414,10 +1394,6 @@ class IDESolver { NumGenFacts += SummaryDSet.size() - 1; } else { NumGenFacts += SummaryDSet.size(); - // We ignore the zero value - if (!IDEProblem.isZeroValue(D1)) { - NumKillFacts++; - } } } else { ProcessSummaryFacts.emplace(Edge.second, D2); @@ -1446,9 +1422,6 @@ class IDESolver { } PHASAR_LOG_LEVEL(DEBUG, "d2: " << IDEProblem.DtoString(D2)); } - if (!IDEProblem.isZeroValue(D1)) { - NumKillFacts++; - } PHASAR_LOG_LEVEL(DEBUG, "----"); } } @@ -1732,6 +1705,49 @@ class IDESolver { return StrIDLess(ICF->getStatementId(Lhs), ICF->getStatementId(Rhs)); } }; + + /// -- Data members + + IDETabulationProblem &IDEProblem; + d_t ZeroValue; + const i_t *ICF; + IFDSIDESolverConfig &SolverConfig; + + std::vector, EdgeFunction>> WorkList; + std::vector> ValuePropWL; + + size_t PathEdgeCount = 0; + + FlowEdgeFunctionCache CachedFlowEdgeFunctions; + + Table> ComputedIntraPathEdges; + + Table> ComputedInterPathEdges; + + EdgeFunction AllTop; + + std::shared_ptr> JumpFn; + + std::map, std::vector>> + IntermediateEdgeFunctions; + + // stores summaries that were queried before they were computed + // see CC 2010 paper by Naeem, Lhotak and Rodriguez + Table>> EndsummaryTab; + + // edges going along calls + // see CC 2010 paper by Naeem, Lhotak and Rodriguez + Table> IncomingTab; + + // stores the return sites (inside callers) to which we have unbalanced + // returns if SolverConfig.followReturnPastSeeds is enabled + std::set UnbalancedRetSites; + + InitialSeeds Seeds; + + Table ValTab; + + std::map, size_t> FSummaryReuse; }; template diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h b/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h index d5bfffb60..874d82184 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h @@ -24,15 +24,24 @@ template class PathEdge { PathEdge(D DSource, N Target, D DTarget) noexcept(std::is_nothrow_move_constructible_v &&std::is_nothrow_move_constructible_v) - : Target(std::move(Target)), DSource(std::move(DSource)), + : DSource(std::move(DSource)), Target(std::move(Target)), DTarget(std::move(DTarget)) {} - [[nodiscard]] ByConstRef getTarget() const noexcept { return Target; } - [[nodiscard]] ByConstRef factAtSource() const noexcept { return DSource; } + [[nodiscard]] ByConstRef getTarget() const noexcept { return Target; } + [[nodiscard]] ByConstRef factAtTarget() const noexcept { return DTarget; } + [[nodiscard]] std::tuple, ByConstRef, ByConstRef> + get() const noexcept { + return {DSource, Target, DTarget}; + } + + [[nodiscard]] std::tuple consume() noexcept { + return {std::move(DSource), std::move(Target), std::move(DTarget)}; + } + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const PathEdge &Edge) { return OS << "<" << Edge.DSource << "> -> <" << Edge.Target << "," @@ -40,8 +49,8 @@ template class PathEdge { } private: - N Target; D DSource; + N Target; D DTarget; }; From 1386d910d9e1c0d7ade77752537bbbf5d5cc4f83 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Wed, 21 Jun 2023 08:52:30 +0200 Subject: [PATCH 17/59] Skip debug instructions in TaintConfig initial seeds (#635) --- lib/PhasarLLVM/TaintConfig/CMakeLists.txt | 2 ++ lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/PhasarLLVM/TaintConfig/CMakeLists.txt b/lib/PhasarLLVM/TaintConfig/CMakeLists.txt index f795ea837..81d9ad6a8 100644 --- a/lib/PhasarLLVM/TaintConfig/CMakeLists.txt +++ b/lib/PhasarLLVM/TaintConfig/CMakeLists.txt @@ -5,6 +5,8 @@ set(PHASAR_LINK_LIBS phasar_db phasar_llvm_db phasar_llvm_utils + phasar_controlflow + phasar_llvm_controlflow ) set(LLVM_LINK_COMPONENTS diff --git a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp index b9440815d..06958f7ed 100644 --- a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp +++ b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp @@ -9,6 +9,7 @@ #include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h" #include "phasar/PhasarLLVM/Utils/Annotation.h" @@ -481,8 +482,10 @@ LLVMTaintConfig::makeInitialSeedsImpl() const { InitialSeeds[Inst].insert(Inst); } else if (const auto *Arg = llvm::dyn_cast(SourceValue); Arg && !Arg->getParent()->isDeclaration()) { - const auto *FunFirstInst = &Arg->getParent()->getEntryBlock().front(); - InitialSeeds[FunFirstInst].insert(Arg); + LLVMBasedCFG C; + for (const auto *SP : C.getStartPointsOf(Arg->getParent())) { + InitialSeeds[SP].insert(Arg); + } } } return InitialSeeds; From 3f6436cbb5208d1fdb0c3aad2785182988136ad2 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 22 Jun 2023 17:59:27 +0200 Subject: [PATCH 18/59] Bump json-schema-validator to fix build on ARM (#636) Co-authored-by: Martin Mory --- external/json-schema-validator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/json-schema-validator b/external/json-schema-validator index 6b17782d6..491ac4402 160000 --- a/external/json-schema-validator +++ b/external/json-schema-validator @@ -1 +1 @@ -Subproject commit 6b17782d6a5d1dee5d2c4fc5d25ffb1123913431 +Subproject commit 491ac44026e08f31790f5cacffa62e168bb35e32 From c6417d95ee10173b2d5fe118fc89e12d73bf1af9 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 29 Jun 2023 13:54:35 +0200 Subject: [PATCH 19/59] Lock-step Solving and Timeout for IDE Solver (#638) * Add worklist for Phase I in IDESolver * Add worklist for Phase II in IDESolver * Remove out-commented recursive calls in IDESolver * Add IDE solving kind that allows interrupting the analysis or injecting code * Comments + some minor refactoring * Add unittest * Generalize the IDESolver mixin + more comments * Add async cancellation * Adding continuations * Make the PAMM tests sleep less * Add tests for async cancellation and continuing * Update comments * Apply review comments --- .../DataFlow/IfdsIde/Solver/IDESolver.h | 139 +++-- .../IfdsIde/Solver/IDESolverAPIMixin.h | 536 ++++++++++++++++++ .../phasar/DataFlow/IfdsIde/SolverResults.h | 9 +- tools/example-tool/myphasartool.cpp | 6 +- .../DataFlow/IfdsIde/CMakeLists.txt | 1 + .../IfdsIde/InteractiveIDESolverTest.cpp | 194 +++++++ 6 files changed, 822 insertions(+), 63 deletions(-) create mode 100644 include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h create mode 100644 unittests/PhasarLLVM/DataFlow/IfdsIde/InteractiveIDESolverTest.cpp diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 79046f443..87731e1fb 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -27,6 +27,7 @@ #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/DataFlow/IfdsIde/InitialSeeds.h" #include "phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h" +#include "phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h" #include "phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h" #include "phasar/DataFlow/IfdsIde/Solver/PathEdge.h" #include "phasar/DataFlow/IfdsIde/SolverResults.h" @@ -59,7 +60,10 @@ namespace psr { /// can then be queried by using resultAt() and resultsAt(). template > -class IDESolver { +class IDESolver + : public IDESolverAPIMixin> { + friend IDESolverAPIMixin>; + public: using ProblemTy = IDETabulationProblem; using container_type = typename ProblemTy::container_type; @@ -127,63 +131,6 @@ class IDESolver { return J; } - /// \brief Runs the solver on the configured problem. This can take some time. - virtual void solve() { - PAMM_GET_INSTANCE; - REG_COUNTER("Gen facts", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Kill facts", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Summary-reuse", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Intra Path Edges", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Inter Path Edges", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("FF Queries", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("EF Queries", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Value Propagation", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Value Computation", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("SpecialSummary-FF Application", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("SpecialSummary-EF Queries", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("JumpFn Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Process Call", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Process Normal", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Process Exit", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("[Calls] getAliasSet", 0, PAMM_SEVERITY_LEVEL::Full); - REG_HISTOGRAM("Data-flow facts", PAMM_SEVERITY_LEVEL::Full); - REG_HISTOGRAM("Points-to", PAMM_SEVERITY_LEVEL::Full); - - PHASAR_LOG_LEVEL(INFO, "IDE solver is solving the specified problem"); - PHASAR_LOG_LEVEL(INFO, - "Submit initial seeds, construct exploded super graph"); - // computations starting here - START_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); - // We start our analysis and construct exploded supergraph - submitInitialSeeds(); - - while (!WorkList.empty()) { - auto [Edge, EF] = std::move(WorkList.back()); - WorkList.pop_back(); - - auto [SourceVal, Target, TargetVal] = Edge.consume(); - propagate(std::move(SourceVal), std::move(Target), std::move(TargetVal), - std::move(EF)); - } - - STOP_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); - if (SolverConfig.computeValues()) { - START_TIMER("DFA Phase II", PAMM_SEVERITY_LEVEL::Full); - // Computing the final values for the edge functions - PHASAR_LOG_LEVEL( - INFO, "Compute the final values according to the edge functions"); - computeValues(); - STOP_TIMER("DFA Phase II", PAMM_SEVERITY_LEVEL::Full); - } - PHASAR_LOG_LEVEL(INFO, "Problem solved"); - if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::Core) { - computeAndPrintStatistics(); - } - if (SolverConfig.emitESG()) { - emitESGAsDot(); - } - } - /// Returns the L-type result for the given value at the given statement. [[nodiscard]] l_t resultAt(n_t Stmt, d_t Value) { return getSolverResults().resultAt(Stmt, Value); @@ -1696,6 +1643,7 @@ class IDESolver { OS << G; } +private: /// @brief: Allows less-than comparison based on the statement ID. struct StmtLess { const i_t *ICF; @@ -1706,6 +1654,81 @@ class IDESolver { } }; + /// -- InteractiveIDESolverMixin implementation + + bool doInitialize() { + PAMM_GET_INSTANCE; + REG_COUNTER("Gen facts", 0, PAMM_SEVERITY_LEVEL::Core); + REG_COUNTER("Kill facts", 0, PAMM_SEVERITY_LEVEL::Core); + REG_COUNTER("Summary-reuse", 0, PAMM_SEVERITY_LEVEL::Core); + REG_COUNTER("Intra Path Edges", 0, PAMM_SEVERITY_LEVEL::Core); + REG_COUNTER("Inter Path Edges", 0, PAMM_SEVERITY_LEVEL::Core); + REG_COUNTER("FF Queries", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("EF Queries", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Value Propagation", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Value Computation", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("SpecialSummary-FF Application", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("SpecialSummary-EF Queries", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("JumpFn Construction", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Process Call", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Process Normal", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Process Exit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("[Calls] getAliasSet", 0, PAMM_SEVERITY_LEVEL::Full); + REG_HISTOGRAM("Data-flow facts", PAMM_SEVERITY_LEVEL::Full); + REG_HISTOGRAM("Points-to", PAMM_SEVERITY_LEVEL::Full); + + PHASAR_LOG_LEVEL(INFO, "IDE solver is solving the specified problem"); + PHASAR_LOG_LEVEL(INFO, + "Submit initial seeds, construct exploded super graph"); + // computations starting here + START_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); + + // We start our analysis and construct exploded supergraph + submitInitialSeeds(); + return !WorkList.empty(); + } + + bool doNext() { + assert(!WorkList.empty()); + auto [Edge, EF] = std::move(WorkList.back()); + WorkList.pop_back(); + + auto [SourceVal, Target, TargetVal] = Edge.consume(); + propagate(std::move(SourceVal), std::move(Target), std::move(TargetVal), + std::move(EF)); + + return !WorkList.empty(); + } + + void finalizeInternal() { + STOP_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); + if (SolverConfig.computeValues()) { + START_TIMER("DFA Phase II", PAMM_SEVERITY_LEVEL::Full); + // Computing the final values for the edge functions + PHASAR_LOG_LEVEL( + INFO, "Compute the final values according to the edge functions"); + computeValues(); + STOP_TIMER("DFA Phase II", PAMM_SEVERITY_LEVEL::Full); + } + PHASAR_LOG_LEVEL(INFO, "Problem solved"); + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::Core) { + computeAndPrintStatistics(); + } + if (SolverConfig.emitESG()) { + emitESGAsDot(); + } + } + + SolverResults doFinalize() & { + finalizeInternal(); + return getSolverResults(); + } + + OwningSolverResults doFinalize() && { + finalizeInternal(); + return consumeSolverResults(); + } + /// -- Data members IDETabulationProblem &IDEProblem; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h new file mode 100644 index 000000000..65ae8a890 --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h @@ -0,0 +1,536 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_DATAFLOW_IFDSIDE_SOLVER_IDESOLVERAPIMIXIN_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_IDESOLVERAPIMIXIN_H + +#include "phasar/Utils/Logger.h" + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace psr { +template class IDESolverAPIMixin { +public: + /// Initialize the IDE solver for step-wise solving (iteratively calling + /// next() or nextN()). + /// For a more high-level API use solveUntil() or solveTimeout(). + /// + /// \returns True, iff it is valid to call next() or nextN() afterwards. + [[nodiscard]] bool initialize() { return self().doInitialize(); } + + /// Performs one tiny step towards the analysis' fixpoint. For a + /// more high-level API use solveUntil() or solveTimeout(). + /// + /// Requires that initialize() has been called before once and returned true + /// and that all previous next() or nextN() calls returned true as well. + /// + /// \returns True, iff there are more steps to process before calling + /// finalize() + [[nodiscard]] bool next() { return self().doNext(); } + + /// Performs N tiny steps towards the analysis' fixpoint. + /// For a more high-level API use solveUntil() or solveTimeout(). + /// + /// Requires that initialize() has been called before once and returned true + /// and that all previous next() or nextN() calls returned true as well. + /// + /// \returns True, iff there are more steps to process before calling + /// finalize() + [[nodiscard]] bool nextN(size_t MaxNumIterations) { + PHASAR_LOG_LEVEL(DEBUG, + "[nextN]: Next " << MaxNumIterations << " Iterations"); + + for (size_t I = 0; I != MaxNumIterations; ++I) { + if (!next()) { + PHASAR_LOG_LEVEL(DEBUG, "[nextN]: > done after " << I << " iterations"); + return false; + } + } + PHASAR_LOG_LEVEL(DEBUG, "[nextN]: > has next"); + return true; + } + + /// Computes the final analysis results after the analysis has reached its + /// fixpoint, i.e. either initialize() returned false or the last next() or + /// nextN() call returned false. + /// + /// \returns A view into the computed analysis results + decltype(auto) finalize() & { return self().doFinalize(); } + /// Computes the final analysis results after the analysis has reached its + /// fixpoint, i.e. either initialize() returned false or the last next() or + /// nextN() call returned false. + /// + /// \returns The computed analysis results + decltype(auto) finalize() && { return std::move(self()).doFinalize(); } + + /// Runs the solver on the configured problem. This can take some time and + /// cannot be interrupted. If you need the ability to interrupt the solving + /// process consider using solveUntil() or solveTimeout(). + /// + /// \returns A view into the computed analysis results + decltype(auto) solve() & { + solveImpl(); + return finalize(); + } + + /// Runs the solver on the configured problem. This can take some time and + /// cannot be interrupted. If you need the ability to interrupt the solving + /// process consider using solveUntil() or solveTimeout(). + /// + /// \returns The computed analysis results + decltype(auto) solve() && { + solveImpl(); + return std::move(*this).finalize(); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. This can take some time and cannot be + /// interrupted. If you need the ability to interrupt the solving process + /// consider using solveUntil() or solveTimeout(). + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// \returns A view into the computed analysis results + decltype(auto) continueSolving() & { + continueImpl(); + return finalize(); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. This can take some time and cannot be + /// interrupted. If you need the ability to interrupt the solving process + /// consider using solveUntil() or solveTimeout(). + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// \returns The computed analysis results + decltype(auto) continueSolving() && { + continueImpl(); + return std::move(*this).finalize(); + } + + /// Solves the analysis problem and periodically checks every Interval whether + /// CancellationRequested evaluates to true. + /// + /// Note: Shortening the cancellation-check interval will make the + /// cancellation-time more precise (by having more frequent calls to + /// CancellationRequested) but also have negative impact on the solver's + /// performance. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + template || + std::is_invocable_r_v>> + auto + solveUntil(CancellationRequest CancellationRequested, + std::chrono::milliseconds Interval = std::chrono::seconds{1}) & { + using RetTy = std::optional>; + return [&]() -> RetTy { + if (solveUntilImpl(std::move(CancellationRequested), Interval)) { + return finalize(); + } + return std::nullopt; + }(); + } + + /// Solves the analysis problem and periodically checks every Interval whether + /// CancellationRequested evaluates to true. + /// + /// Note: Shortening the cancellation-check interval will make the + /// cancellation-time more precise (by having more frequent calls to + /// CancellationRequested) but also have negative impact on the solver's + /// performance. + /// + /// \returns An std::optional holding the analysis results or std::nullopt if + /// the analysis was cancelled. + template || + std::is_invocable_r_v>> + auto + solveUntil(CancellationRequest CancellationRequested, + std::chrono::milliseconds Interval = std::chrono::seconds{1}) && { + using RetTy = + std::optional>; + return [&]() -> RetTy { + if (solveUntilImpl(std::move(CancellationRequested), Interval)) { + return std::move(*this).finalize(); + } + return std::nullopt; + }(); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. Periodically checks every Interval whether + /// CancellationRequested evaluates to true. + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// Note: Shortening the cancellation-check interval will make the + /// cancellation-time more precise (by having more frequent calls to + /// CancellationRequested) but also have negative impact on the solver's + /// performance. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + template || + std::is_invocable_r_v>> + auto continueUntil(CancellationRequest CancellationRequested, + std::chrono::milliseconds Interval = std::chrono::seconds{ + 1}) & { + using RetTy = std::optional>; + return [&]() -> RetTy { + if (continueUntilImpl(std::move(CancellationRequested), Interval)) { + return finalize(); + } + return std::nullopt; + }(); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. Periodically checks every Interval whether + /// CancellationRequested evaluates to true. + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// Note: Shortening the cancellation-check interval will make the + /// cancellation-time more precise (by having more frequent calls to + /// CancellationRequested) but also have negative impact on the solver's + /// performance. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + template || + std::is_invocable_r_v>> + auto continueUntil(CancellationRequest CancellationRequested, + std::chrono::milliseconds Interval = std::chrono::seconds{ + 1}) && { + using RetTy = + std::optional>; + return [&]() -> RetTy { + if (continueUntilImpl(std::move(CancellationRequested), Interval)) { + return std::move(*this).finalize(); + } + return std::nullopt; + }(); + } + + /// Solves the analysis problem and periodically checks every Interval whether + /// the Timeout has been exceeded. + /// + /// Note: Shortening the timeout-check interval will make the timeout more + /// precise but also have negative impact on the solver's performance. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + auto solveWithTimeout(std::chrono::milliseconds Timeout, + std::chrono::milliseconds Interval) & { + auto CancellationRequested = + [Timeout, Start = std::chrono::steady_clock::now()]( + std::chrono::steady_clock::time_point TimeStamp) { + return TimeStamp - Start >= Timeout; + }; + + return solveUntil(CancellationRequested, Interval); + } + + /// Solves the analysis problem and periodically checks every Interval whether + /// the Timeout has been exceeded. + /// + /// Note: Shortening the timeout-check interval will make the timeout more + /// precise but also have negative impact on the solver's performance. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + auto solveWithTimeout(std::chrono::milliseconds Timeout, + std::chrono::milliseconds Interval) && { + auto CancellatioNRequested = + [Timeout, Start = std::chrono::steady_clock::now()]( + std::chrono::steady_clock::time_point TimeStamp) { + return TimeStamp - Start >= Timeout; + }; + return std::move(*this).solveUntil(CancellatioNRequested, Interval); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. Periodically checks every Interval whether + /// the Timeout has been exceeded. + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// Note: Shortening the timeout-check interval will make the timeout more + /// precise but also have negative impact on the solver's performance. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + auto continueWithTimeout(std::chrono::milliseconds Timeout, + std::chrono::milliseconds Interval) & { + auto CancellationRequested = + [Timeout, Start = std::chrono::steady_clock::now()]( + std::chrono::steady_clock::time_point TimeStamp) { + return TimeStamp - Start >= Timeout; + }; + + return continueUntil(CancellationRequested, Interval); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. Periodically checks every Interval whether + /// the Timeout has been exceeded. + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// Note: Shortening the timeout-check interval will make the timeout more + /// precise but also have negative impact on the solver's performance. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + auto continueWithTimeout(std::chrono::milliseconds Timeout, + std::chrono::milliseconds Interval) && { + auto CancellationRequested = + [Timeout, Start = std::chrono::steady_clock::now()]( + std::chrono::steady_clock::time_point TimeStamp) { + return TimeStamp - Start >= Timeout; + }; + + return std::move(*this).continueUntil(CancellationRequested, Interval); + } + + // -- Async cancellation + + /// Solves the analysis problem and periodically checks whether + /// IsCancelled is true. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + auto solveWithAsyncCancellation(std::atomic_bool &IsCancelled) & { + using RetTy = std::optional>; + return [&]() -> RetTy { + if (solveWithAsyncCancellationImpl(IsCancelled)) { + return finalize(); + } + return std::nullopt; + }(); + } + + /// Solves the analysis problem and periodically checks whether + /// IsCancelled is true. + /// + /// \returns An std::optional holding the analysis results or std::nullopt if + /// the analysis was cancelled. + auto solveWithAsyncCancellation(std::atomic_bool &IsCancelled) && { + using RetTy = + std::optional>; + return [&]() -> RetTy { + if (solveWithAsyncCancellationImpl(IsCancelled)) { + return std::move(*this).finalize(); + } + return std::nullopt; + }(); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. Periodically checks whether + /// IsCancelled is true. + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + auto continueWithAsyncCancellation(std::atomic_bool &IsCancelled) & { + using RetTy = std::optional>; + return [&]() -> RetTy { + if (continueWithAsyncCancellationImpl(IsCancelled)) { + return finalize(); + } + return std::nullopt; + }(); + } + + /// Continues running the solver on the configured problem after it got + /// interrupted in a previous run. Periodically checks whether + /// IsCancelled is true. + /// + /// \remark Please make sure to *only* call this function on an IDESolver + /// where the solving process is interrupted, i.e. one of the interruptable + /// solving methods returned std::nullopt. It is *invalid* to call this + /// function on an IDESolver that has not yet started solving or has already + /// flinalized solving. + /// + /// \returns An std::optional holding a view into the analysis results or + /// std::nullopt if the analysis was cancelled. + auto continueWithAsyncCancellation(std::atomic_bool &IsCancelled) && { + using RetTy = + std::optional>; + return [&]() -> RetTy { + if (continueWithAsyncCancellationImpl(IsCancelled)) { + return std::move(*this).finalize(); + } + return std::nullopt; + }(); + } + +private: + [[nodiscard]] Derived &self() &noexcept { + static_assert(std::is_base_of_v, + "Invalid CRTP instantiation"); + return static_cast(*this); + } + + void continueImpl() { + while (next()) { + // no interrupt in normal solving process + } + } + + void solveImpl() { + if (initialize()) { + continueImpl(); + } + } + + template + [[nodiscard]] bool + continueUntilImpl(CancellationRequest CancellationRequested, + std::chrono::milliseconds Interval) { + auto IsCancellationRequested = + [&CancellationRequested]( + std::chrono::steady_clock::time_point TimeStamp) { + if constexpr (std::is_invocable_r_v< + bool, CancellationRequest, + std::chrono::steady_clock::time_point>) { + return std::invoke(CancellationRequested, TimeStamp); + } else { + return std::invoke(CancellationRequested); + } + }; + + // Some initial number of propagations to get an idea, how long a + // propagation takes. This may be adjusted in the future + size_t NumIterations = Interval.count() * 500; + + auto Start = std::chrono::steady_clock::now(); + + while (nextN(NumIterations)) { + auto End = std::chrono::steady_clock::now(); + using milliseconds_d = std::chrono::duration; + + auto DeltaTime = std::chrono::duration_cast(End - Start); + Start = End; + + if (IsCancellationRequested(End)) { + return false; + } + + // Adjust NumIterations + auto IterationsPerMilli = double(NumIterations) / DeltaTime.count(); + auto NewNumIterations = + size_t(IterationsPerMilli * double(Interval.count())); + NumIterations = (NumIterations + 2 * NewNumIterations) / 3; + } + auto End = std::chrono::steady_clock::now(); + return !IsCancellationRequested(End); + } + + template + [[nodiscard]] bool solveUntilImpl(CancellationRequest CancellationRequested, + std::chrono::milliseconds Interval) { + auto IsCancellationRequested = + [&CancellationRequested]( + std::chrono::steady_clock::time_point TimeStamp) { + if constexpr (std::is_invocable_r_v< + bool, CancellationRequest, + std::chrono::steady_clock::time_point>) { + return std::invoke(CancellationRequested, TimeStamp); + } else { + return std::invoke(CancellationRequested); + } + }; + + bool Initialized = initialize(); + auto TimeStamp = std::chrono::steady_clock::now(); + if (IsCancellationRequested(TimeStamp)) { + return false; + } + + return Initialized + ? continueUntilImpl(std::move(CancellationRequested), Interval) + : true; + } + + [[nodiscard]] bool + continueWithAsyncCancellationImpl(std::atomic_bool &IsCancelled) { + while (next()) { + if (IsCancelled.load()) { + return false; + } + } + return !IsCancelled.load(); + } + + [[nodiscard]] bool + solveWithAsyncCancellationImpl(std::atomic_bool &IsCancelled) { + bool Initialized = initialize(); + if (IsCancelled.load()) { + return false; + } + + return Initialized ? continueWithAsyncCancellationImpl(IsCancelled) : true; + } +}; +} // namespace psr + +#endif // PHASAR_DATAFLOW_IFDSIDE_SOLVER_IDESOLVERAPIMIXIN_H diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 67d855dea..0f1e71f50 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -51,8 +51,8 @@ class SolverResultsBase { return self().Results.get(Stmt, Node); } - [[nodiscard]] std::unordered_map - resultsAt(ByConstRef Stmt, bool StripZero = false) const { + [[nodiscard]] std::unordered_map resultsAt(ByConstRef Stmt, + bool StripZero) const { std::unordered_map Result = self().Results.row(Stmt); if (StripZero) { Result.erase(self().ZV); @@ -60,6 +60,11 @@ class SolverResultsBase { return Result; } + [[nodiscard]] const std::unordered_map & + resultsAt(ByConstRef Stmt) const { + return self().Results.row(Stmt); + } + // this function only exists for IFDS problems which use BinaryDomain as their // value domain L template (HA, EntryPoints); IFDSSolver S(L, &HA.getICFG()); - S.solve(); - S.dumpResults(); + auto IFDSResults = S.solve(); + IFDSResults.dumpResults(HA.getICFG(), L); + // IDE template parametrization test llvm::outs() << "Testing IDE:\n"; auto M = createAnalysisProblem(HA, EntryPoints); - // Alternative way of solving an IFDS/IDEProblem: auto IDEResults = solveIDEProblem(M, HA.getICFG()); IDEResults.dumpResults(HA.getICFG(), M); diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt index c53b41c9d..9ab94b5db 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(Problems) set(IfdsIdeSources EdgeFunctionComposerTest.cpp EdgeFunctionSingletonCacheTest.cpp + InteractiveIDESolverTest.cpp ) foreach(TEST_SRC ${IfdsIdeSources}) diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/InteractiveIDESolverTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/InteractiveIDESolverTest.cpp new file mode 100644 index 000000000..6ff07a20f --- /dev/null +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/InteractiveIDESolverTest.cpp @@ -0,0 +1,194 @@ +#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h" +#include "phasar/PhasarLLVM/HelperAnalyses.h" +#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" +#include "phasar/Utils/TypeTraits.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +#include +#include + +using namespace psr; + +/* ============== TEST FIXTURE ============== */ +class LinearConstant : public ::testing::TestWithParam { +protected: + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("linear_constant/"); + const std::vector EntryPoints = {"main"}; + +}; // Test Fixture + +TEST_P(LinearConstant, ResultsEquivalentSolveUntil) { + HelperAnalyses HA(PathToLlFiles + GetParam(), EntryPoints); + + // Compute the ICFG to possibly create the runtime model + auto &ICFG = HA.getICFG(); + + auto HasGlobalCtor = HA.getProjectIRDB().getFunctionDefinition( + LLVMBasedICFG::GlobalCRuntimeModelName) != nullptr; + + auto LCAProblem = createAnalysisProblem( + HA, + std::vector{HasGlobalCtor ? LLVMBasedICFG::GlobalCRuntimeModelName.str() + : "main"}); + + auto AtomicResults = IDESolver(LCAProblem, &ICFG).solve(); + { + auto InteractiveResults = + IDESolver(LCAProblem, &ICFG).solveUntil(FalseFn{}); + + ASSERT_TRUE(InteractiveResults.has_value()); + for (auto &&Cell : AtomicResults.getAllResultEntries()) { + auto InteractiveRes = + InteractiveResults->resultAt(Cell.getRowKey(), Cell.getColumnKey()); + EXPECT_EQ(InteractiveRes, Cell.getValue()); + } + } + auto InterruptedResults = [&] { + IDESolver Solver(LCAProblem, &ICFG); + auto Result = Solver.solveUntil(TrueFn{}); + EXPECT_EQ(std::nullopt, Result); + if (!Result) { + return std::move(Solver).continueSolving(); + } + return Solver.consumeSolverResults(); + }(); + + for (auto &&Cell : AtomicResults.getAllResultEntries()) { + auto InteractiveRes = + InterruptedResults.resultAt(Cell.getRowKey(), Cell.getColumnKey()); + EXPECT_EQ(InteractiveRes, Cell.getValue()); + } +} + +TEST_P(LinearConstant, ResultsEquivalentSolveUntilAsync) { + HelperAnalyses HA(PathToLlFiles + GetParam(), EntryPoints); + + // Compute the ICFG to possibly create the runtime model + auto &ICFG = HA.getICFG(); + + auto HasGlobalCtor = HA.getProjectIRDB().getFunctionDefinition( + LLVMBasedICFG::GlobalCRuntimeModelName) != nullptr; + + auto LCAProblem = createAnalysisProblem( + HA, + std::vector{HasGlobalCtor ? LLVMBasedICFG::GlobalCRuntimeModelName.str() + : "main"}); + + auto AtomicResults = IDESolver(LCAProblem, &ICFG).solve(); + + { + std::atomic_bool IsCancelled = false; + auto InteractiveResults = + IDESolver(LCAProblem, &ICFG).solveWithAsyncCancellation(IsCancelled); + + ASSERT_TRUE(InteractiveResults.has_value()); + for (auto &&Cell : AtomicResults.getAllResultEntries()) { + auto InteractiveRes = + InteractiveResults->resultAt(Cell.getRowKey(), Cell.getColumnKey()); + EXPECT_EQ(InteractiveRes, Cell.getValue()); + } + } + auto InterruptedResults = [&] { + IDESolver Solver(LCAProblem, &ICFG); + std::atomic_bool IsCancelled = true; + auto Result = Solver.solveWithAsyncCancellation(IsCancelled); + EXPECT_EQ(std::nullopt, Result); + if (!Result) { + IsCancelled = false; + return std::move(Solver).solveWithAsyncCancellation(IsCancelled).value(); + } + return Solver.consumeSolverResults(); + }(); + + for (auto &&Cell : AtomicResults.getAllResultEntries()) { + auto InteractiveRes = + InterruptedResults.resultAt(Cell.getRowKey(), Cell.getColumnKey()); + EXPECT_EQ(InteractiveRes, Cell.getValue()); + } +} + +static constexpr std::string_view LCATestFiles[] = { + "basic_01_cpp_dbg.ll", + "basic_02_cpp_dbg.ll", + "basic_03_cpp_dbg.ll", + "basic_04_cpp_dbg.ll", + "basic_05_cpp_dbg.ll", + "basic_06_cpp_dbg.ll", + "basic_07_cpp_dbg.ll", + "basic_08_cpp_dbg.ll", + "basic_09_cpp_dbg.ll", + "basic_10_cpp_dbg.ll", + "basic_11_cpp_dbg.ll", + "basic_12_cpp_dbg.ll", + + "branch_01_cpp_dbg.ll", + "branch_02_cpp_dbg.ll", + "branch_03_cpp_dbg.ll", + "branch_04_cpp_dbg.ll", + "branch_05_cpp_dbg.ll", + "branch_06_cpp_dbg.ll", + "branch_07_cpp_dbg.ll", + + "while_01_cpp_dbg.ll", + "while_02_cpp_dbg.ll", + "while_03_cpp_dbg.ll", + "while_04_cpp_dbg.ll", + "while_05_cpp_dbg.ll", + "for_01_cpp_dbg.ll", + + "call_01_cpp_dbg.ll", + "call_02_cpp_dbg.ll", + "call_03_cpp_dbg.ll", + "call_04_cpp_dbg.ll", + "call_05_cpp_dbg.ll", + "call_06_cpp_dbg.ll", + "call_07_cpp_dbg.ll", + "call_08_cpp_dbg.ll", + "call_09_cpp_dbg.ll", + "call_10_cpp_dbg.ll", + "call_11_cpp_dbg.ll", + + "recursion_01_cpp_dbg.ll", + "recursion_02_cpp_dbg.ll", + "recursion_03_cpp_dbg.ll", + + "global_01_cpp_dbg.ll", + "global_02_cpp_dbg.ll", + "global_03_cpp_dbg.ll", + "global_04_cpp_dbg.ll", + "global_05_cpp_dbg.ll", + "global_06_cpp_dbg.ll", + "global_07_cpp_dbg.ll", + "global_08_cpp_dbg.ll", + "global_09_cpp_dbg.ll", + "global_10_cpp_dbg.ll", + "global_11_cpp_dbg.ll", + "global_12_cpp_dbg.ll", + "global_13_cpp_dbg.ll", + "global_14_cpp_dbg.ll", + "global_15_cpp_dbg.ll", + "global_16_cpp_dbg.ll", + + "overflow_add_cpp_dbg.ll", + "overflow_sub_cpp_dbg.ll", + "overflow_mul_cpp_dbg.ll", + "overflow_div_min_by_neg_one_cpp_dbg.ll", + + "ub_division_by_zero_cpp_dbg.ll", + "ub_modulo_by_zero_cpp_dbg.ll", +}; + +INSTANTIATE_TEST_SUITE_P(InteractiveIDESolverTest, LinearConstant, + ::testing::ValuesIn(LCATestFiles)); + +// main function for the test case +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} From 349656f4bb97c124c36979cab8dea3e3389bb46e Mon Sep 17 00:00:00 2001 From: Martin Musiol <46841921+Poppeldipop@users.noreply.github.com> Date: Thu, 6 Jul 2023 20:11:51 +0200 Subject: [PATCH 20/59] F clang tidy compliance (#641) * Header Guards changed to preferred style according to Clang-tidy * Changed include order to preffered style and set qualified variables to (const) auto according to Clang-tidy * 'override' functions instead of 'virtual' according to Clang-tidy * Reverted wrong Header Guard --- .../phasar/AnalysisStrategy/AnalysisSetup.h | 4 +- .../AnalysisStrategy/DemandDrivenAnalysis.h | 4 +- .../IncrementalUpdateAnalysis.h | 4 +- .../AnalysisStrategy/ModuleWiseAnalysis.h | 4 +- include/phasar/AnalysisStrategy/Strategies.h | 4 +- .../AnalysisStrategy/VariationalAnalysis.h | 4 +- include/phasar/ControlFlow/CFGBase.h | 6 +-- include/phasar/ControlFlow/CallGraph.h | 6 +-- .../ControlFlow/CallGraphAnalysisType.h | 6 +-- include/phasar/ControlFlow/CallGraphBase.h | 6 +-- include/phasar/ControlFlow/ICFGBase.h | 6 +-- .../ControlFlow/SpecialMemberFunctionType.h | 6 +-- .../DefaultEdgeFunctionSingletonCache.h | 11 +++-- .../phasar/DataFlow/IfdsIde/EdgeFunction.h | 8 ++-- .../IfdsIde/EdgeFunctionSingletonCache.h | 6 +-- .../DataFlow/IfdsIde/EdgeFunctionUtils.h | 6 +-- .../phasar/DataFlow/IfdsIde/EdgeFunctions.h | 4 +- .../phasar/DataFlow/IfdsIde/FlowFunctions.h | 4 +- .../DataFlow/IfdsIde/IDETabulationProblem.h | 2 +- .../DataFlow/IfdsIde/IFDSIDESolverConfig.h | 4 +- .../DataFlow/IfdsIde/IFDSTabulationProblem.h | 4 +- .../phasar/DataFlow/IfdsIde/InitialSeeds.h | 4 +- .../IfdsIde/Solver/FlowEdgeFunctionCache.h | 4 +- .../DataFlow/IfdsIde/Solver/IDESolver.h | 4 +- .../DataFlow/IfdsIde/Solver/IFDSSolver.h | 6 +-- .../DataFlow/IfdsIde/Solver/JumpFunctions.h | 4 +- .../phasar/DataFlow/IfdsIde/Solver/PathEdge.h | 4 +- .../phasar/DataFlow/IfdsIde/SolverResults.h | 4 +- .../DataFlow/IfdsIde/SpecialSummaries.h | 4 +- .../DataFlow/Mono/Contexts/CallStringCTX.h | 4 +- .../phasar/DataFlow/Mono/InterMonoProblem.h | 4 +- .../phasar/DataFlow/Mono/IntraMonoProblem.h | 4 +- .../DataFlow/Mono/Solver/InterMonoSolver.h | 4 +- .../DataFlow/Mono/Solver/IntraMonoSolver.h | 4 +- include/phasar/Domain/AnalysisDomain.h | 4 +- include/phasar/Domain/BinaryDomain.h | 4 +- include/phasar/Domain/LatticeDomain.h | 4 +- .../phasar/PhasarLLVM/DB/LLVMProjectIRDB.h | 6 +-- .../BranchSwitchInstFlowFunction.h | 4 +- .../FlowFunctions/CallToRetFlowFunction.h | 4 +- .../FlowFunctions/CheckOperandsFlowFunction.h | 4 +- .../FlowFunctions/FlowFunctionBase.h | 4 +- .../FlowFunctions/GEPInstFlowFunction.h | 4 +- .../FlowFunctions/GenerateFlowFunction.h | 4 +- .../FlowFunctions/IdentityFlowFunction.h | 4 +- .../FlowFunctions/MapTaintedValuesToCallee.h | 4 +- .../FlowFunctions/MapTaintedValuesToCaller.h | 4 +- .../FlowFunctions/MemSetInstFlowFunction.h | 4 +- .../MemTransferInstFlowFunction.h | 4 +- .../FlowFunctions/PHINodeFlowFunction.h | 4 +- .../FlowFunctions/ReturnInstFlowFunction.h | 4 +- .../FlowFunctions/StoreInstFlowFunction.h | 4 +- .../FlowFunctions/VAEndInstFlowFunction.h | 4 +- .../FlowFunctions/VAStartInstFlowFunction.h | 4 +- .../Stats/LcovRetValWriter.h | 4 +- .../Stats/LcovWriter.h | 4 +- .../Stats/LineNumberEntry.h | 4 +- .../Stats/LineNumberWriter.h | 4 +- .../Stats/TraceStats.h | 4 +- .../Stats/TraceStatsWriter.h | 4 +- .../Utils/DataFlowUtils.h | 4 +- .../Utils/ExtendedValue.h | 4 +- .../IFDSFieldSensTaintAnalysis/Utils/Log.h | 4 +- .../DataFlow/IfdsIde/LLVMFlowFunctions.h | 4 +- .../DataFlow/IfdsIde/LLVMZeroValue.h | 4 +- .../AbstractMemoryLocation.h | 4 +- .../AbstractMemoryLocationFactory.h | 4 +- .../ExtendedTaintAnalysis/AllSanitized.h | 6 +-- .../ComposeEdgeFunction.h | 4 +- .../ExtendedTaintAnalysis/EdgeDomain.h | 4 +- .../ExtendedTaintAnalysis/GenEdgeFunction.h | 4 +- .../Problems/ExtendedTaintAnalysis/Helpers.h | 4 +- .../KillIfSanitizedEdgeFunction.h | 4 +- .../TransferEdgeFunction.h | 4 +- .../XTaintAnalysisBase.h | 4 +- .../XTaintEdgeFunctionBase.h | 4 +- .../Problems/IDEExtendedTaintAnalysis.h | 4 +- .../Problems/IDEGeneralizedLCA/AllBot.h | 4 +- .../IDEGeneralizedLCA/BinaryEdgeFunction.h | 4 +- .../IDEGeneralizedLCA/ConstantHelper.h | 4 +- .../Problems/IDEGeneralizedLCA/EdgeValue.h | 4 +- .../Problems/IDEGeneralizedLCA/EdgeValueSet.h | 4 +- .../Problems/IDEGeneralizedLCA/GenConstant.h | 4 +- .../IDEGeneralizedLCA/IDEGeneralizedLCA.h | 4 +- .../IDEGeneralizedLCADomain.h | 6 +-- .../LCAEdgeFunctionComposer.h | 4 +- .../MapFactsToCalleeFlowFunction.h | 4 +- .../MapFactsToCallerFlowFunction.h | 4 +- .../IDEGeneralizedLCA/TypecastEdgeFunction.h | 4 +- .../Problems/IDEInstInteractionAnalysis.h | 4 +- .../Problems/IDELinearConstantAnalysis.h | 4 +- .../IfdsIde/Problems/IDEProtoAnalysis.h | 4 +- .../Problems/IDESecureHeapPropagation.h | 4 +- .../DataFlow/IfdsIde/Problems/IDESolverTest.h | 4 +- .../IfdsIde/Problems/IDETypeStateAnalysis.h | 4 +- .../IfdsIde/Problems/IFDSConstAnalysis.h | 4 +- .../Problems/IFDSFieldSensTaintAnalysis.h | 4 +- .../IfdsIde/Problems/IFDSProtoAnalysis.h | 4 +- .../IfdsIde/Problems/IFDSSignAnalysis.h | 4 +- .../IfdsIde/Problems/IFDSSolverTest.h | 4 +- .../IfdsIde/Problems/IFDSTaintAnalysis.h | 4 +- .../IfdsIde/Problems/IFDSTypeAnalysis.h | 4 +- .../Problems/IFDSUninitializedVariables.h | 4 +- .../CSTDFILEIOTypeStateDescription.h | 4 +- .../OpenSSLEVPKDFCTXDescription.h | 4 +- .../OpenSSLEVPKDFDescription.h | 4 +- .../OpenSSLSecureHeapDescription.h | 4 +- .../OpenSSLSecureMemoryDescription.h | 4 +- .../TypeStateDescription.h | 4 +- .../InterMonoFullConstantPropagation.h | 4 +- .../Mono/Problems/InterMonoSolverTest.h | 4 +- .../Mono/Problems/InterMonoTaintAnalysis.h | 4 +- .../IntraMonoFullConstantPropagation.h | 4 +- .../Mono/Problems/IntraMonoSolverTest.h | 4 +- .../Mono/Problems/IntraMonoUninitVariables.h | 4 +- include/phasar/PhasarLLVM/HelperAnalyses.h | 6 +-- .../phasar/PhasarLLVM/HelperAnalysisConfig.h | 6 +-- .../PhasarLLVM/SimpleAnalysisConstructor.h | 6 +-- .../TaintConfig/TaintConfigUtilities.h | 6 +-- .../PhasarLLVM/Utils/LLVMCXXShorthands.h | 4 +- include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h | 4 +- .../phasar/PhasarLLVM/Utils/LLVMShorthands.h | 4 +- include/phasar/Pointer/AliasAnalysisType.h | 6 +-- include/phasar/Pointer/AliasInfo.h | 4 +- include/phasar/Pointer/AliasInfoBase.h | 6 +-- include/phasar/Pointer/AliasInfoTraits.h | 6 +-- include/phasar/Pointer/AliasResult.h | 6 +-- include/phasar/Pointer/AliasSetOwner.h | 8 ++-- include/phasar/Pointer/PointsToInfo.h | 6 +-- include/phasar/Pointer/PointsToInfoBase.h | 6 +-- include/phasar/TypeHierarchy/TypeHierarchy.h | 4 +- include/phasar/TypeHierarchy/VFTable.h | 4 +- include/phasar/Utils/ByRef.h | 6 +-- include/phasar/Utils/ChronoUtils.h | 6 +-- include/phasar/Utils/DOTGraph.h | 4 +- include/phasar/Utils/DefaultValue.h | 6 +-- include/phasar/Utils/JoinLattice.h | 4 +- include/phasar/Utils/Printer.h | 4 +- include/phasar/Utils/StableVector.h | 2 +- lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp | 2 +- lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp | 2 +- lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp | 2 +- lib/Utils/DOTGraph.cpp | 2 +- .../LLVMBasedICFGGlobCtorDtorTest.cpp | 46 +++++++++---------- .../Problems/IDEGeneralizedLCATest.cpp | 4 +- 145 files changed, 338 insertions(+), 337 deletions(-) diff --git a/include/phasar/AnalysisStrategy/AnalysisSetup.h b/include/phasar/AnalysisStrategy/AnalysisSetup.h index 51edc8889..dcdfb6ee2 100644 --- a/include/phasar/AnalysisStrategy/AnalysisSetup.h +++ b/include/phasar/AnalysisStrategy/AnalysisSetup.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_ANALYSISSETUP_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_ANALYSISSETUP_H_ +#ifndef PHASAR_ANALYSISSTRATEGY_ANALYSISSETUP_H +#define PHASAR_ANALYSISSTRATEGY_ANALYSISSETUP_H #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" diff --git a/include/phasar/AnalysisStrategy/DemandDrivenAnalysis.h b/include/phasar/AnalysisStrategy/DemandDrivenAnalysis.h index 978a37244..1096f8f64 100644 --- a/include/phasar/AnalysisStrategy/DemandDrivenAnalysis.h +++ b/include/phasar/AnalysisStrategy/DemandDrivenAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_DEMANDDRIVENANALYSIS_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_DEMANDDRIVENANALYSIS_H_ +#ifndef PHASAR_ANALYSISSTRATEGY_DEMANDDRIVENANALYSIS_H +#define PHASAR_ANALYSISSTRATEGY_DEMANDDRIVENANALYSIS_H namespace psr { diff --git a/include/phasar/AnalysisStrategy/IncrementalUpdateAnalysis.h b/include/phasar/AnalysisStrategy/IncrementalUpdateAnalysis.h index b2e9e4b4d..e0aeb2cda 100644 --- a/include/phasar/AnalysisStrategy/IncrementalUpdateAnalysis.h +++ b/include/phasar/AnalysisStrategy/IncrementalUpdateAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_INCREMENTALUPDATEANALYSIS_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_INCREMENTALUPDATEANALYSIS_H_ +#ifndef PHASAR_ANALYSISSTRATEGY_INCREMENTALUPDATEANALYSIS_H +#define PHASAR_ANALYSISSTRATEGY_INCREMENTALUPDATEANALYSIS_H namespace psr { diff --git a/include/phasar/AnalysisStrategy/ModuleWiseAnalysis.h b/include/phasar/AnalysisStrategy/ModuleWiseAnalysis.h index 0fbf1fd86..7bc77acc4 100644 --- a/include/phasar/AnalysisStrategy/ModuleWiseAnalysis.h +++ b/include/phasar/AnalysisStrategy/ModuleWiseAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_MODULEWISEANALYSIS_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_MODULEWISEANALYSIS_H_ +#ifndef PHASAR_ANALYSISSTRATEGY_MODULEWISEANALYSIS_H +#define PHASAR_ANALYSISSTRATEGY_MODULEWISEANALYSIS_H namespace psr { diff --git a/include/phasar/AnalysisStrategy/Strategies.h b/include/phasar/AnalysisStrategy/Strategies.h index 16c17655e..acbf0fc9f 100644 --- a/include/phasar/AnalysisStrategy/Strategies.h +++ b/include/phasar/AnalysisStrategy/Strategies.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_STRATEGIES_H -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_STRATEGIES_H +#ifndef PHASAR_ANALYSISSTRATEGY_STRATEGIES_H +#define PHASAR_ANALYSISSTRATEGY_STRATEGIES_H #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" diff --git a/include/phasar/AnalysisStrategy/VariationalAnalysis.h b/include/phasar/AnalysisStrategy/VariationalAnalysis.h index 3211a0091..24b412213 100644 --- a/include/phasar/AnalysisStrategy/VariationalAnalysis.h +++ b/include/phasar/AnalysisStrategy/VariationalAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_VARIATIONALANALYSIS_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_VARIATIONALANALYSIS_H_ +#ifndef PHASAR_ANALYSISSTRATEGY_VARIATIONALANALYSIS_H +#define PHASAR_ANALYSISSTRATEGY_VARIATIONALANALYSIS_H #include "phasar/AnalysisStrategy/AnalysisSetup.h" diff --git a/include/phasar/ControlFlow/CFGBase.h b/include/phasar/ControlFlow/CFGBase.h index bee58d4d8..57e358225 100644 --- a/include/phasar/ControlFlow/CFGBase.h +++ b/include/phasar/ControlFlow/CFGBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H -#define PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H +#ifndef PHASAR_CONTROLFLOW_CFGBASE_H +#define PHASAR_CONTROLFLOW_CFGBASE_H #include "phasar/Utils/ByRef.h" #include "phasar/Utils/TypeTraits.h" @@ -150,4 +150,4 @@ constexpr bool is_cfg_v = is_crtp_base_of_v } // namespace psr -#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H +#endif // PHASAR_CONTROLFLOW_CFGBASE_H diff --git a/include/phasar/ControlFlow/CallGraph.h b/include/phasar/ControlFlow/CallGraph.h index 973528545..590b16964 100644 --- a/include/phasar/ControlFlow/CallGraph.h +++ b/include/phasar/ControlFlow/CallGraph.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPH_H -#define PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPH_H +#ifndef PHASAR_CONTROLFLOW_CALLGRAPH_H +#define PHASAR_CONTROLFLOW_CALLGRAPH_H #include "phasar/ControlFlow/CallGraphBase.h" #include "phasar/Utils/ByRef.h" @@ -301,4 +301,4 @@ extern template class psr::CallGraph; -#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPH_H +#endif // PHASAR_CONTROLFLOW_CALLGRAPH_H diff --git a/include/phasar/ControlFlow/CallGraphAnalysisType.h b/include/phasar/ControlFlow/CallGraphAnalysisType.h index 31d6193ce..af5ed728b 100644 --- a/include/phasar/ControlFlow/CallGraphAnalysisType.h +++ b/include/phasar/ControlFlow/CallGraphAnalysisType.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H -#define PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H +#ifndef PHASAR_CONTROLFLOW_CALLGRAPHANALYSISTYPE_H +#define PHASAR_CONTROLFLOW_CALLGRAPHANALYSISTYPE_H #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" @@ -30,4 +30,4 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, CallGraphAnalysisType CGA); } // namespace psr -#endif // PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H +#endif // PHASAR_CONTROLFLOW_CALLGRAPHANALYSISTYPE_H diff --git a/include/phasar/ControlFlow/CallGraphBase.h b/include/phasar/ControlFlow/CallGraphBase.h index 9440829d8..e2b1e01e5 100644 --- a/include/phasar/ControlFlow/CallGraphBase.h +++ b/include/phasar/ControlFlow/CallGraphBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHBASE_H -#define PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHBASE_H +#ifndef PHASAR_CONTROLFLOW_CALLGRAPHBASE_H +#define PHASAR_CONTROLFLOW_CALLGRAPHBASE_H #include "phasar/Utils/ByRef.h" #include "phasar/Utils/TypeTraits.h" @@ -56,4 +56,4 @@ template class CallGraphBase { }; } // namespace psr -#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CALLGRAPHBASE_H +#endif // PHASAR_CONTROLFLOW_CALLGRAPHBASE_H diff --git a/include/phasar/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h index 339671fd7..1f62fb69a 100644 --- a/include/phasar/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H -#define PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H +#ifndef PHASAR_CONTROLFLOW_ICFGBASE_H +#define PHASAR_CONTROLFLOW_ICFGBASE_H #include "phasar/ControlFlow/CFGBase.h" #include "phasar/ControlFlow/CallGraphBase.h" @@ -134,4 +134,4 @@ constexpr bool is_icfg_v = is_crtp_base_of_v } // namespace psr -#endif // PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H +#endif // PHASAR_CONTROLFLOW_ICFGBASE_H diff --git a/include/phasar/ControlFlow/SpecialMemberFunctionType.h b/include/phasar/ControlFlow/SpecialMemberFunctionType.h index b6e86f6c2..4b2957ccd 100644 --- a/include/phasar/ControlFlow/SpecialMemberFunctionType.h +++ b/include/phasar/ControlFlow/SpecialMemberFunctionType.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H -#define PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H +#ifndef PHASAR_CONTROLFLOW_SPECIALMEMBERFUNCTIONTYPE_H +#define PHASAR_CONTROLFLOW_SPECIALMEMBERFUNCTIONTYPE_H #include "llvm/ADT/StringRef.h" @@ -40,4 +40,4 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SpecialMemberFunctionType SMFT); } // namespace psr -#endif // PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H +#endif // PHASAR_CONTROLFLOW_SPECIALMEMBERFUNCTIONTYPE_H diff --git a/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h index 4b631fe08..2d05cb54c 100644 --- a/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h +++ b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H +#define PHASAR_DATAFLOW_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h" @@ -68,8 +68,9 @@ class DefaultEdgeFunctionSingletonCache if (LHS == RHS) { return true; } - auto Empty = llvm::DenseMapInfo::getEmptyKey(); - auto Tombstone = + const auto *Empty = + llvm::DenseMapInfo::getEmptyKey(); + const auto *Tombstone = llvm::DenseMapInfo::getTombstoneKey(); if (LHS == Empty || LHS == Tombstone || RHS == Empty || RHS == Tombstone) { @@ -114,4 +115,4 @@ class DefaultEdgeFunctionSingletonCache< } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H +#endif // PHASAR_DATAFLOW_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index 064e21575..1c68c9b34 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTION_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTION_H +#define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTION_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h" #include "phasar/Utils/ByRef.h" @@ -300,7 +300,7 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { new (&Ret) ConcreteEF(std::move(EF.EF)); return Ret; } else { - if (auto Mem = EF.Cache->lookup(EF.EF)) { + if (const auto *Mem = EF.Cache->lookup(EF.EF)) { return static_cast *>(Mem); } @@ -804,4 +804,4 @@ struct CastInfo> #endif } // namespace llvm -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTION_H +#endif // PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTION_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h index d2aadfe6f..53e652c0f 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H +#define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H #include "phasar/Utils/ByRef.h" @@ -72,4 +72,4 @@ CachedEdgeFunction(EdgeFunctionTy, EdgeFunctionSingletonCache *) } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H +#endif // PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h index 5151556a2..018a7849f 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONUTILS_H_ -#define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONUTILS_H_ +#ifndef PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONUTILS_H +#define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONUTILS_H #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/Utils/ByRef.h" @@ -473,4 +473,4 @@ JoinEdgeFunction::join(EdgeFunctionRef This, } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONUTILS_H +#endif // PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONUTILS_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctions.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctions.h index 520cba7b1..3b9034133 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctions.h @@ -14,8 +14,8 @@ * Author: pdschbrt */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ +#ifndef PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONS_H +#define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONS_H #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/Utils/ByRef.h" diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index 0aadfaebf..dda69748e 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -14,8 +14,8 @@ * Author: pdschbrt */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFUNCTIONS_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFUNCTIONS_H_ +#ifndef PHASAR_DATAFLOW_IFDSIDE_FLOWFUNCTIONS_H +#define PHASAR_DATAFLOW_IFDSIDE_FLOWFUNCTIONS_H #include "phasar/Utils/TypeTraits.h" diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index 28bfc76a7..8f79ed8b4 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -66,7 +66,7 @@ class IDETabulationProblem : public FlowFunctions, assert(IRDB != nullptr); } - virtual ~IDETabulationProblem() = default; + ~IDETabulationProblem() override = default; /// Returns an edge function that represents the top element of the analysis. virtual EdgeFunction allTopFunction() = 0; diff --git a/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h b/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h index b3f949364..71dcba326 100644 --- a/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h +++ b/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h @@ -14,8 +14,8 @@ * Author: pdschbrt */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSIDESOLVERCONFIG_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSIDESOLVERCONFIG_H_ +#ifndef PHASAR_DATAFLOW_IFDSIDE_IFDSIDESOLVERCONFIG_H +#define PHASAR_DATAFLOW_IFDSIDE_IFDSIDESOLVERCONFIG_H #include "phasar/Utils/EnumFlags.h" diff --git a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h index 656c80b46..5c6cb2059 100644 --- a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_IFDSTABULATIONPROBLEM_H +#define PHASAR_DATAFLOW_IFDSIDE_IFDSTABULATIONPROBLEM_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" diff --git a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h index 4273e43eb..b5a001031 100644 --- a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h +++ b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_INITIALSEEDS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_INITIALSEEDS_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_INITIALSEEDS_H +#define PHASAR_DATAFLOW_IFDSIDE_INITIALSEEDS_H #include "phasar/Domain/BinaryDomain.h" #include "phasar/Utils/TypeTraits.h" diff --git a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h index 0db214065..23d4b918c 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWEDGEFUNCTIONCACHE_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWEDGEFUNCTIONCACHE_H_ +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_FLOWEDGEFUNCTIONCACHE_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_FLOWEDGEFUNCTIONCACHE_H #include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 87731e1fb..0eb324dc0 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -14,8 +14,8 @@ * Author: pdschbrt */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IDESOLVER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IDESOLVER_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_IDESOLVER_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_IDESOLVER_H #include "phasar/Config/Configuration.h" #include "phasar/DB/ProjectIRDBBase.h" diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h index 60f4bb892..3a5f20d8f 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h @@ -14,8 +14,8 @@ * Author: pdschbrt */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IFDSSOLVER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IFDSSOLVER_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_IFDSSOLVER_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_IFDSSOLVER_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" @@ -45,7 +45,7 @@ class IFDSSolver const i_t *ICF) : IDESolver>(IFDSProblem, ICF) {} - virtual ~IFDSSolver() = default; + ~IFDSSolver() override = default; /// Returns the data-flow results at the given statement. [[nodiscard]] virtual std::set ifdsResultsAt(n_t Inst) { diff --git a/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h index dc3dbac3c..6bb2c6ffa 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h @@ -14,8 +14,8 @@ * Author: pdschbrt */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_JUMPFUNCTIONS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_JUMPFUNCTIONS_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_JUMPFUNCTIONS_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_JUMPFUNCTIONS_H #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/Utils/Logger.h" diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h b/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h index 874d82184..9bbd90c19 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHEDGE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHEDGE_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_PATHEDGE_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_PATHEDGE_H #include "phasar/Utils/ByRef.h" diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 0f1e71f50..fb532a134 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -14,8 +14,8 @@ * Author: rleer */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_SOLVERRESULTS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_SOLVERRESULTS_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVERRESULTS_H +#define PHASAR_DATAFLOW_IFDSIDE_SOLVERRESULTS_H #include "phasar/Domain/BinaryDomain.h" #include "phasar/Utils/ByRef.h" diff --git a/include/phasar/DataFlow/IfdsIde/SpecialSummaries.h b/include/phasar/DataFlow/IfdsIde/SpecialSummaries.h index d02851edf..3154c52b3 100644 --- a/include/phasar/DataFlow/IfdsIde/SpecialSummaries.h +++ b/include/phasar/DataFlow/IfdsIde/SpecialSummaries.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SPECIALSUMMARIES_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SPECIALSUMMARIES_H +#ifndef PHASAR_DATAFLOW_IFDSIDE_SPECIALSUMMARIES_H +#define PHASAR_DATAFLOW_IFDSIDE_SPECIALSUMMARIES_H #include "phasar/Config/Configuration.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" diff --git a/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h b/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h index 07a7693c7..ae813f39f 100644 --- a/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h +++ b/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h @@ -1,5 +1,5 @@ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_CONTEXTS_CALLSTRINGCTX_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_CONTEXTS_CALLSTRINGCTX_H +#ifndef PHASAR_DATAFLOW_MONO_CONTEXTS_CALLSTRINGCTX_H +#define PHASAR_DATAFLOW_MONO_CONTEXTS_CALLSTRINGCTX_H #include "phasar/Utils/Printer.h" diff --git a/include/phasar/DataFlow/Mono/InterMonoProblem.h b/include/phasar/DataFlow/Mono/InterMonoProblem.h index 5d119ac64..9ee1b3298 100644 --- a/include/phasar/DataFlow/Mono/InterMonoProblem.h +++ b/include/phasar/DataFlow/Mono/InterMonoProblem.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTERMONOPROBLEM_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTERMONOPROBLEM_H +#ifndef PHASAR_DATAFLOW_MONO_INTERMONOPROBLEM_H +#define PHASAR_DATAFLOW_MONO_INTERMONOPROBLEM_H #include "phasar/ControlFlow/ICFGBase.h" #include "phasar/DataFlow/Mono/IntraMonoProblem.h" diff --git a/include/phasar/DataFlow/Mono/IntraMonoProblem.h b/include/phasar/DataFlow/Mono/IntraMonoProblem.h index 4f5927d81..8405d2030 100644 --- a/include/phasar/DataFlow/Mono/IntraMonoProblem.h +++ b/include/phasar/DataFlow/Mono/IntraMonoProblem.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTRAMONOPROBLEM_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTRAMONOPROBLEM_H +#ifndef PHASAR_DATAFLOW_MONO_INTRAMONOPROBLEM_H +#define PHASAR_DATAFLOW_MONO_INTRAMONOPROBLEM_H #include "phasar/ControlFlow/CFGBase.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" diff --git a/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h index c1a7285b6..b8785ebe0 100644 --- a/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h +++ b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTERMONOSOLVER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTERMONOSOLVER_H +#ifndef PHASAR_DATAFLOW_MONO_SOLVER_INTERMONOSOLVER_H +#define PHASAR_DATAFLOW_MONO_SOLVER_INTERMONOSOLVER_H #include "phasar/DataFlow/Mono/Contexts/CallStringCTX.h" #include "phasar/DataFlow/Mono/InterMonoProblem.h" diff --git a/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h b/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h index 0283ce9d4..53c26627c 100644 --- a/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h +++ b/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTRAMONOSOLVER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTRAMONOSOLVER_H +#ifndef PHASAR_DATAFLOW_MONO_SOLVER_INTRAMONOSOLVER_H +#define PHASAR_DATAFLOW_MONO_SOLVER_INTRAMONOSOLVER_H #include "phasar/DataFlow/Mono/IntraMonoProblem.h" #include "phasar/Utils/BitVectorSet.h" diff --git a/include/phasar/Domain/AnalysisDomain.h b/include/phasar/Domain/AnalysisDomain.h index 02a76f4a8..bf79fe797 100644 --- a/include/phasar/Domain/AnalysisDomain.h +++ b/include/phasar/Domain/AnalysisDomain.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DOMAIN_ANALYSISDOMAIN_H -#define PHASAR_PHASARLLVM_DOMAIN_ANALYSISDOMAIN_H +#ifndef PHASAR_DOMAIN_ANALYSISDOMAIN_H +#define PHASAR_DOMAIN_ANALYSISDOMAIN_H #include diff --git a/include/phasar/Domain/BinaryDomain.h b/include/phasar/Domain/BinaryDomain.h index 80fe3d8ed..d518120f3 100644 --- a/include/phasar/Domain/BinaryDomain.h +++ b/include/phasar/Domain/BinaryDomain.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ -#define PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ +#ifndef PHASAR_DOMAIN_BINARYDOMAIN_H +#define PHASAR_DOMAIN_BINARYDOMAIN_H #include "phasar/Utils/JoinLattice.h" diff --git a/include/phasar/Domain/LatticeDomain.h b/include/phasar/Domain/LatticeDomain.h index 76dd845bc..b7b7f1540 100644 --- a/include/phasar/Domain/LatticeDomain.h +++ b/include/phasar/Domain/LatticeDomain.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H -#define PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H +#ifndef PHASAR_DOMAIN_LATTICEDOMAIN_H +#define PHASAR_DOMAIN_LATTICEDOMAIN_H #include "phasar/Utils/ByRef.h" #include "phasar/Utils/JoinLattice.h" diff --git a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h index c3abcad87..51285ef8e 100644 --- a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h +++ b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_DB_LLVMPROJECTIRDB_H -#define PHASAR_DB_LLVMPROJECTIRDB_H +#ifndef PHASAR_PHASARLLVM_DB_LLVMPROJECTIRDB_H +#define PHASAR_PHASARLLVM_DB_LLVMPROJECTIRDB_H #include "phasar/DB/ProjectIRDBBase.h" #include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" @@ -168,4 +168,4 @@ const llvm::Value *fromMetaDataId(const LLVMProjectIRDB &IRDB, extern template class ProjectIRDBBase; } // namespace psr -#endif // PHASAR_DB_LLVMPROJECTIRDB_H +#endif // PHASAR_PHASARLLVM_DB_LLVMPROJECTIRDB_H diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h index 75129176f..016030332 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_BRANCHSWITCHINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_BRANCHSWITCHINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_BRANCHSWITCHINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_BRANCHSWITCHINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h index efa2f22b9..01aa4b9b4 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CALLTORETFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CALLTORETFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CALLTORETFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CALLTORETFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h index 2a9f2f5bf..a89c93ad1 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CHECKOPERANDSFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CHECKOPERANDSFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CHECKOPERANDSFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CHECKOPERANDSFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h index 0117e364b..8e1e0db4a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_FLOWFUNCTIONBASE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_FLOWFUNCTIONBASE_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_FLOWFUNCTIONBASE_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_FLOWFUNCTIONBASE_H #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h index 4ebf27b65..0f382d1e4 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GEPINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GEPINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GEPINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GEPINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h index 969e7dd73..e6056f156 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GENERATEFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GENERATEFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GENERATEFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GENERATEFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h index 0aa541206..9f410fd2c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_IDENTITYFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_IDENTITYFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_IDENTITYFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_IDENTITYFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h index fcca65bf6..245108ce7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLEE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLEE_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLEE_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLEE_H #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h index 57477a0ad..050cef273 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLER_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLER_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLER_H #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h index 9c12e828b..c0e7ec30b 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMSETINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMSETINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMSETINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMSETINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h index 7d52a7458..d54375155 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMTRANSFERINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMTRANSFERINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMTRANSFERINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMTRANSFERINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h index 1aa55b8eb..c5df55522 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_PHINODEFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_PHINODEFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_PHINODEFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_PHINODEFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h index 700699152..88785ef91 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_RETURNINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_RETURNINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_RETURNINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_RETURNINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h index c2e121de1..4ffc14e9d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_STOREINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_STOREINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_STOREINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_STOREINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h index 04949dae2..270732856 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VAENDINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VAENDINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VAENDINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VAENDINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h index 3b7980bc5..b59b67ae2 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VASTARTINSTFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VASTARTINSTFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VASTARTINSTFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VASTARTINSTFLOWFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h index 0c5664800..a56be6137 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVRETVALWRITER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVRETVALWRITER_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVRETVALWRITER_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVRETVALWRITER_H #include "TraceStatsWriter.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h index d7e27b295..4b6690102 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVWRITER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVWRITER_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVWRITER_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LCOVWRITER_H #include "TraceStatsWriter.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h index 72a927b63..763fc1879 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERENTRY_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERENTRY_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERENTRY_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERENTRY_H #include diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h index 23fe53f94..d92c5efe3 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERWRITER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERWRITER_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERWRITER_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_LINENUMBERWRITER_H #include "TraceStatsWriter.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h index 5ba0fcd25..2bdb6d59a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATS_H #include "llvm/IR/Instruction.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h index d4d5f599d..5ec4eb8ee 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATSWRITER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATSWRITER_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATSWRITER_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATSWRITER_H #include "../Utils/Log.h" #include "TraceStats.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h index cb936e237..3fa5c74e9 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_DATAFLOWUTILS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_DATAFLOWUTILS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_DATAFLOWUTILS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_DATAFLOWUTILS_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h index 45139ba97..10253527c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DOMAIN_EXTENDEDVALUE_H -#define PHASAR_PHASARLLVM_DOMAIN_EXTENDEDVALUE_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_EXTENDEDVALUE_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_EXTENDEDVALUE_H #include #include diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h index 24ab01522..29b3835b3 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_LOG_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_LOG_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_LOG_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_LOG_H #include "llvm/Support/raw_ostream.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h index ef3dd2c83..f3af3cc81 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMFLOWFUNCTIONS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMFLOWFUNCTIONS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_LLVMFLOWFUNCTIONS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_LLVMFLOWFUNCTIONS_H #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h index c57bfd088..e0f6d8b9e 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMZEROVALUE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMZEROVALUE_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_LLVMZEROVALUE_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_LLVMZEROVALUE_H #include "llvm/ADT/StringRef.h" #include "llvm/IR/GlobalVariable.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h index 5f7dbf727..365036042 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h index aa27ef024..6b6066989 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATIONFACTORY_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATIONFACTORY_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATIONFACTORY_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATIONFACTORY_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h index 2288416f4..0605a9601 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" @@ -32,4 +32,4 @@ struct AllSanitized { }; } // namespace psr::XTaint -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H +#endif // PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h index 981461c48..debf1bf3f 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H #include "phasar//DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h index ad3d9404e..c246c5721 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_EDGEDOMAIN_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_EDGEDOMAIN_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_EDGEDOMAIN_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_EDGEDOMAIN_H #include "phasar/Domain/LatticeDomain.h" #include "phasar/Utils/ByRef.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h index 4376f40eb..98bcc97b4 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h index a4bd479ca..862af3e47 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_HELPERS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_HELPERS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_HELPERS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_HELPERS_H #include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" #include "phasar/Domain/LatticeDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h index 181a9190f..680f0c206 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" #include "phasar/Utils/ByRef.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h index 450a8519e..a5383208d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" #include "phasar/Utils/ByRef.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h index 5263343fb..eda4bd6e4 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTANALYSISBASE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTANALYSISBASE_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTANALYSISBASE_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTANALYSISBASE_H #include "llvm/ADT/SmallPtrSet.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h index 339fa2f81..edd529101 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H_ +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index cb13c7344..8a9979b52 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/Domain/LatticeDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h index 0dd0789a4..fa0984801 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h index d65f87f55..f24453bd1 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h index 34c7ffa45..cceb17979 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_CONSTANTHELPER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_CONSTANTHELPER_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_CONSTANTHELPER_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_CONSTANTHELPER_H namespace llvm { class Value; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h index 1fa752cb9..c26a6191c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h @@ -7,8 +7,8 @@ * Fabian Schiebel, Alexander Meinhold and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUE_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUE_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUE_H #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Twine.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h index 8526c3474..0b8b859bf 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUESET_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUESET_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUESET_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUESET_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h" #include "phasar/Utils/JoinLattice.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h index 50b14da39..4a4246efc 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h index 63949390d..26ea81ca7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h index c4b07728a..fc387e013 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" @@ -23,4 +23,4 @@ struct IDEGeneralizedLCADomain : LLVMAnalysisDomainDefault { } // namespace psr -#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H +#endif // PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h index a0bac57af..e345b9472 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h index f6a11eb95..99f580244 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLEEFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLEEFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLEEFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLEEFLOWFUNCTION_H #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h index 50acbe5c6..b2fc9f691 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLERFLOWFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLERFLOWFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLERFLOWFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLERFLOWFUNCTION_H #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h index 426b4d0b1..c910e2e21 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h @@ -7,8 +7,8 @@ * Fabian Schiebel and Others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index c0824c7a5..ca75d1c12 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONALYSIS_H -#define PHASAR_PHASARLLVM_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONANALYSIS_H #include "phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h index ec1b4beea..14e84327c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDELINEARCONSTANTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDELINEARCONSTANTANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDELINEARCONSTANTANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDELINEARCONSTANTANALYSIS_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/Domain/LatticeDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h index fffad0dd6..9c25256ff 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h index 7bc28bbdf..51663d05c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h index 6ae2e387a..cceb38a9d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESOLVERTEST_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESOLVERTEST_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDESOLVERTEST_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDESOLVERTEST_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 2d46060ed..9339ef91f 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h index 85ca53443..4f11609a4 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h index d64c3993f..62dcd7eb5 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h @@ -2,8 +2,8 @@ * @author Sebastian Roland */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h index ee628992c..16d7b1c59 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSPROTOANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSPROTOANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSPROTOANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSPROTOANALYSIS_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h index a97e4a9c9..67dae0c90 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h index 69c0ea3eb..25b7c28a5 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h index 7054f4165..b39e22a42 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTAINTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTAINTANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSTAINTANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSTAINTANALYSIS_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h index b8b4e060c..9c4b55c9d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h index 46db4b631..24e07c8ff 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSUNINITIALIZEDVARIABLES_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSUNINITIALIZEDVARIABLES_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSUNINITIALIZEDVARIABLES_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IFDSUNINITIALIZEDVARIABLES_H #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h index 88e29ef1a..ef36022a7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h index 580a4011a..0a31b6042 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFCTXDESCRIPTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFCTXDESCRIPTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFCTXDESCRIPTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFCTXDESCRIPTION_H #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/Domain/AnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h index 96bd98864..f038e04a6 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFDESCRIPTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFDESCRIPTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFDESCRIPTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFDESCRIPTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h index ca1205856..f0b0c6ab9 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREHEAPDESCRIPTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREHEAPDESCRIPTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREHEAPDESCRIPTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREHEAPDESCRIPTION_H #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/Domain/AnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h index 9078d0321..5f06867f2 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h @@ -7,8 +7,8 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREMEMORYDESCRIPTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREMEMORYDESCRIPTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREMEMORYDESCRIPTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREMEMORYDESCRIPTION_H #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h index 4302cb0a1..a67b119ba 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H +#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H #include "llvm/IR/InstrTypes.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h index c2ab701a7..4c6e0e798 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h @@ -7,8 +7,8 @@ * Philipp Schubert, Linus Jungemann, and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOFULLCONSTANTPROPAGATION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOFULLCONSTANTPROPAGATION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTERMONOFULLCONSTANTPROPAGATION_H +#define PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTERMONOFULLCONSTANTPROPAGATION_H #include "phasar/DataFlow/Mono/InterMonoProblem.h" #include "phasar/Domain/LatticeDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h index 2c5446829..235d9a31e 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOSOLVERTEST_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOSOLVERTEST_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTERMONOSOLVERTEST_H +#define PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTERMONOSOLVERTEST_H #include "phasar/DataFlow/Mono/InterMonoProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h index 36bcc8439..c155f1b71 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h @@ -14,8 +14,8 @@ * Author: richard leer */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H +#define PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H #include "phasar/DataFlow/Mono/InterMonoProblem.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h index d8b64028e..e62d24369 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOFULLCONSTANTPROPAGATION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOFULLCONSTANTPROPAGATION_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTRAMONOFULLCONSTANTPROPAGATION_H +#define PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTRAMONOFULLCONSTANTPROPAGATION_H #include "phasar/DataFlow/Mono/IntraMonoProblem.h" #include "phasar/Domain/LatticeDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h index cae80de31..05a95b293 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOSOLVERTEST_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOSOLVERTEST_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTRAMONOSOLVERTEST_H +#define PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTRAMONOSOLVERTEST_H #include "phasar/DataFlow/Mono/IntraMonoProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h index c3d4ac5a4..7b1f887b8 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOUNINITVARIABLES_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOUNINITVARIABLES_H +#ifndef PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTRAMONOUNINITVARIABLES_H +#define PHASAR_PHASARLLVM_DATAFLOW_MONO_PROBLEMS_INTRAMONOUNINITVARIABLES_H #include "phasar/DataFlow/Mono/IntraMonoProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" diff --git a/include/phasar/PhasarLLVM/HelperAnalyses.h b/include/phasar/PhasarLLVM/HelperAnalyses.h index ebaabdcbf..39a06ddf9 100644 --- a/include/phasar/PhasarLLVM/HelperAnalyses.h +++ b/include/phasar/PhasarLLVM/HelperAnalyses.h @@ -7,8 +7,8 @@ * Fabian Schiebel, Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ +#ifndef PHASAR_PHASARLLVM_HELPERANALYSES_H +#define PHASAR_PHASARLLVM_HELPERANALYSES_H #include "phasar/ControlFlow/CallGraphAnalysisType.h" #include "phasar/PhasarLLVM/HelperAnalysisConfig.h" @@ -78,4 +78,4 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) }; } // namespace psr -#endif // PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ +#endif // PHASAR_PHASARLLVM_HELPERANALYSES_H diff --git a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h index 21b52a958..4fbd87c62 100644 --- a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h +++ b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSISCONFIG_H -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSISCONFIG_H +#ifndef PHASAR_PHASARLLVM_HELPERANALYSISCONFIG_H +#define PHASAR_PHASARLLVM_HELPERANALYSISCONFIG_H #include "phasar/ControlFlow/CallGraphAnalysisType.h" #include "phasar/Pointer/AliasAnalysisType.h" @@ -35,4 +35,4 @@ struct HelperAnalysisConfig { }; } // namespace psr -#endif // PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSISCONFIG_H +#endif // PHASAR_PHASARLLVM_HELPERANALYSISCONFIG_H diff --git a/include/phasar/PhasarLLVM/SimpleAnalysisConstructor.h b/include/phasar/PhasarLLVM/SimpleAnalysisConstructor.h index 7976a42ac..fce91ea9c 100644 --- a/include/phasar/PhasarLLVM/SimpleAnalysisConstructor.h +++ b/include/phasar/PhasarLLVM/SimpleAnalysisConstructor.h @@ -7,8 +7,8 @@ * Fabian Schiebel, and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_SIMPLEANALYSISCONSTRUCTOR_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_SIMPLEANALYSISCONSTRUCTOR_H_ +#ifndef PHASAR_PHASARLLVM_SIMPLEANALYSISCONSTRUCTOR_H +#define PHASAR_PHASARLLVM_SIMPLEANALYSISCONSTRUCTOR_H #include "phasar/PhasarLLVM/HelperAnalyses.h" @@ -66,4 +66,4 @@ ProblemTy createAnalysisProblem(HelperAnalyses &HA, ArgTys &&...Args) { } // namespace psr -#endif // PHASAR_PHASARLLVM_ANALYSISSTRATEGY_SIMPLEANALYSISCONSTRUCTOR_H_ +#endif // PHASAR_PHASARLLVM_SIMPLEANALYSISCONSTRUCTOR_H diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h index 502b55989..aa7941deb 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIGUTILITIES_H -#define PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIGUTILITIES_H +#ifndef PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGUTILITIES_H +#define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGUTILITIES_H #include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" @@ -87,4 +87,4 @@ void collectSanitizedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, } } // namespace psr -#endif // PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIGUTILITIES_H +#endif // PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGUTILITIES_H diff --git a/include/phasar/PhasarLLVM/Utils/LLVMCXXShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMCXXShorthands.h index b4b3449f9..e5be26d7c 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMCXXShorthands.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMCXXShorthands.h @@ -1,5 +1,5 @@ -#ifndef PHASAR_UTILS_LLVMCXXSHORTHANDS_H -#define PHASAR_UTILS_LLVMCXXSHORTHANDS_H +#ifndef PHASAR_PHASARLLVM_UTILS_LLVMCXXSHORTHANDS_H +#define PHASAR_PHASARLLVM_UTILS_LLVMCXXSHORTHANDS_H // This contains LLVM IR Shorthands specific to C++ // See // https://mapping-high-level-constructs-to-llvm-ir.readthedocs.io/en/latest/object-oriented-constructs/classes.html diff --git a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h index 908481976..17cab3ef9 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h @@ -14,8 +14,8 @@ * Author: rleer */ -#ifndef PHASAR_UTILS_LLVMIRTOSRC_H_ -#define PHASAR_UTILS_LLVMIRTOSRC_H_ +#ifndef PHASAR_PHASARLLVM_UTILS_LLVMIRTOSRC_H +#define PHASAR_PHASARLLVM_UTILS_LLVMIRTOSRC_H #include "nlohmann/json.hpp" diff --git a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h index 5639c7a17..21d2df136 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h @@ -14,8 +14,8 @@ * Author: philipp */ -#ifndef PHASAR_UTILS_LLVMSHORTHANDS_H_ -#define PHASAR_UTILS_LLVMSHORTHANDS_H_ +#ifndef PHASAR_PHASARLLVM_UTILS_LLVMSHORTHANDS_H +#define PHASAR_PHASARLLVM_UTILS_LLVMSHORTHANDS_H #include "phasar/Utils/Utilities.h" diff --git a/include/phasar/Pointer/AliasAnalysisType.h b/include/phasar/Pointer/AliasAnalysisType.h index c05177920..7e8fb61b1 100644 --- a/include/phasar/Pointer/AliasAnalysisType.h +++ b/include/phasar/Pointer/AliasAnalysisType.h @@ -1,5 +1,5 @@ -#ifndef PHASAR_PHASARLLVM_POINTER_ALIASANALYSISTYPE_H_ -#define PHASAR_PHASARLLVM_POINTER_ALIASANALYSISTYPE_H_ +#ifndef PHASAR_POINTER_ALIASANALYSISTYPE_H +#define PHASAR_POINTER_ALIASANALYSISTYPE_H #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" @@ -20,4 +20,4 @@ AliasAnalysisType toAliasAnalysisType(llvm::StringRef S); llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, AliasAnalysisType PA); } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_ALIASANALYSISTYPE_H_ +#endif // PHASAR_POINTER_ALIASANALYSISTYPE_H diff --git a/include/phasar/Pointer/AliasInfo.h b/include/phasar/Pointer/AliasInfo.h index eee1eca61..ba9fa480f 100644 --- a/include/phasar/Pointer/AliasInfo.h +++ b/include/phasar/Pointer/AliasInfo.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_ALIASINFO_H_ -#define PHASAR_PHASARLLVM_POINTER_ALIASINFO_H_ +#ifndef PHASAR_POINTER_ALIASINFO_H +#define PHASAR_POINTER_ALIASINFO_H #include "phasar/Pointer/AliasInfoTraits.h" #include "phasar/Pointer/AliasResult.h" diff --git a/include/phasar/Pointer/AliasInfoBase.h b/include/phasar/Pointer/AliasInfoBase.h index ae0488651..b3bb828c1 100644 --- a/include/phasar/Pointer/AliasInfoBase.h +++ b/include/phasar/Pointer/AliasInfoBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_ALIASINFOBASE_H -#define PHASAR_PHASARLLVM_POINTER_ALIASINFOBASE_H +#ifndef PHASAR_POINTER_ALIASINFOBASE_H +#define PHASAR_POINTER_ALIASINFOBASE_H #include "phasar/Pointer/AliasInfoTraits.h" @@ -79,4 +79,4 @@ static constexpr bool IsAliasInfo = detail::IsAliasInfo::value; } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_ALIASINFOBASE_H +#endif // PHASAR_POINTER_ALIASINFOBASE_H diff --git a/include/phasar/Pointer/AliasInfoTraits.h b/include/phasar/Pointer/AliasInfoTraits.h index ad25d1141..4892db434 100644 --- a/include/phasar/Pointer/AliasInfoTraits.h +++ b/include/phasar/Pointer/AliasInfoTraits.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_ALIASINFOTRAITS_H -#define PHASAR_PHASARLLVM_POINTER_ALIASINFOTRAITS_H +#ifndef PHASAR_POINTER_ALIASINFOTRAITS_H +#define PHASAR_POINTER_ALIASINFOTRAITS_H #include "phasar/Utils/BoxedPointer.h" @@ -35,4 +35,4 @@ template struct DefaultAATraits { }; } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_ALIASINFOTRAITS_H +#endif // PHASAR_POINTER_ALIASINFOTRAITS_H diff --git a/include/phasar/Pointer/AliasResult.h b/include/phasar/Pointer/AliasResult.h index 29e62fff7..825d51ca0 100644 --- a/include/phasar/Pointer/AliasResult.h +++ b/include/phasar/Pointer/AliasResult.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_ALIASRESULT_H_ -#define PHASAR_PHASARLLVM_POINTER_ALIASRESULT_H_ +#ifndef PHASAR_POINTER_ALIASRESULT_H +#define PHASAR_POINTER_ALIASRESULT_H #include "llvm/Support/raw_ostream.h" @@ -27,4 +27,4 @@ AliasResult toAliasResult(llvm::StringRef S); llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, AliasResult AR); } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_ALIASRESULT_H_ +#endif // PHASAR_POINTER_ALIASRESULT_H diff --git a/include/phasar/Pointer/AliasSetOwner.h b/include/phasar/Pointer/AliasSetOwner.h index 5d01d79ba..405fca8c6 100644 --- a/include/phasar/Pointer/AliasSetOwner.h +++ b/include/phasar/Pointer/AliasSetOwner.h @@ -7,8 +7,8 @@ * Fabian Schiebel, Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_ALIASSETOWNER_H -#define PHASAR_PHASARLLVM_POINTER_ALIASSETOWNER_H +#ifndef PHASAR_POINTER_ALIASSETOWNER_H +#define PHASAR_POINTER_ALIASSETOWNER_H #include "phasar/Pointer/AliasInfoTraits.h" #include "phasar/Utils/BoxedPointer.h" @@ -66,7 +66,7 @@ template class AliasSetOwner { AliasSetOwner &operator=(AliasSetOwner &&) = delete; ~AliasSetOwner() { - for (auto PTS : OwnedPTS) { + for (auto *PTS : OwnedPTS) { std::destroy_at(PTS); #if HAS_MEMORY_RESOURCE Alloc.deallocate(PTS, 1); @@ -121,4 +121,4 @@ extern template class AliasSetOwner::AliasSetTy>; } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_ALIASSETOWNER_H +#endif // PHASAR_POINTER_ALIASSETOWNER_H diff --git a/include/phasar/Pointer/PointsToInfo.h b/include/phasar/Pointer/PointsToInfo.h index c5511ec2b..94bae1f3d 100644 --- a/include/phasar/Pointer/PointsToInfo.h +++ b/include/phasar/Pointer/PointsToInfo.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_POINTSTOINFO_H -#define PHASAR_PHASARLLVM_POINTER_POINTSTOINFO_H +#ifndef PHASAR_POINTER_POINTSTOINFO_H +#define PHASAR_POINTER_POINTSTOINFO_H #include "phasar/Pointer/PointsToInfoBase.h" #include "phasar/Utils/ByRef.h" @@ -264,4 +264,4 @@ class [[clang::trivial_abi]] PointsToInfo< } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_POINTSTOINFO_H +#endif // PHASAR_POINTER_POINTSTOINFO_H diff --git a/include/phasar/Pointer/PointsToInfoBase.h b/include/phasar/Pointer/PointsToInfoBase.h index 923429d3c..696065646 100644 --- a/include/phasar/Pointer/PointsToInfoBase.h +++ b/include/phasar/Pointer/PointsToInfoBase.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_POINTSTOINFOBASE_H -#define PHASAR_PHASARLLVM_POINTER_POINTSTOINFOBASE_H +#ifndef PHASAR_POINTER_POINTSTOINFOBASE_H +#define PHASAR_POINTER_POINTSTOINFOBASE_H #include "phasar/Utils/ByRef.h" #include "phasar/Utils/TypeTraits.h" @@ -145,4 +145,4 @@ template class PointsToInfoBase { } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_POINTSTOINFOBASE_H +#endif // PHASAR_POINTER_POINTSTOINFOBASE_H diff --git a/include/phasar/TypeHierarchy/TypeHierarchy.h b/include/phasar/TypeHierarchy/TypeHierarchy.h index db9d9c8db..e3f44e879 100644 --- a/include/phasar/TypeHierarchy/TypeHierarchy.h +++ b/include/phasar/TypeHierarchy/TypeHierarchy.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_TYPEHIERARCHY_H_ -#define PHASAR_PHASARLLVM_TYPEHIERARCHY_TYPEHIERARCHY_H_ +#ifndef PHASAR_TYPEHIERARCHY_TYPEHIERARCHY_H +#define PHASAR_TYPEHIERARCHY_TYPEHIERARCHY_H #include "phasar/TypeHierarchy/VFTable.h" diff --git a/include/phasar/TypeHierarchy/VFTable.h b/include/phasar/TypeHierarchy/VFTable.h index bfbd615e0..56334171b 100644 --- a/include/phasar/TypeHierarchy/VFTable.h +++ b/include/phasar/TypeHierarchy/VFTable.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_VFTABLE_H_ -#define PHASAR_PHASARLLVM_TYPEHIERARCHY_VFTABLE_H_ +#ifndef PHASAR_TYPEHIERARCHY_VFTABLE_H +#define PHASAR_TYPEHIERARCHY_VFTABLE_H #include "llvm/Support/raw_ostream.h" diff --git a/include/phasar/Utils/ByRef.h b/include/phasar/Utils/ByRef.h index 4cd72f550..4e0f21bed 100644 --- a/include/phasar/Utils/ByRef.h +++ b/include/phasar/Utils/ByRef.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_UTILS_BYREF_H -#define PHASAR_PHASARLLVM_UTILS_BYREF_H +#ifndef PHASAR_UTILS_BYREF_H +#define PHASAR_UTILS_BYREF_H #include @@ -26,4 +26,4 @@ using ByMoveRef = std::conditional_t, T, T &&>; } // namespace psr -#endif // PHASAR_PHASARLLVM_UTILS_BYREF_H +#endif // PHASAR_UTILS_BYREF_H diff --git a/include/phasar/Utils/ChronoUtils.h b/include/phasar/Utils/ChronoUtils.h index d6acbf718..ca4f4092f 100644 --- a/include/phasar/Utils/ChronoUtils.h +++ b/include/phasar/Utils/ChronoUtils.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H -#define PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H +#ifndef PHASAR_UTILS_CHRONOUTILS_H +#define PHASAR_UTILS_CHRONOUTILS_H #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -52,4 +52,4 @@ struct hms { // NOLINT } // namespace psr -#endif // PHASAR_PHASARLLVM_UTILS_CHRONO_UTILS_H +#endif // PHASAR_UTILS_CHRONOUTILS_H diff --git a/include/phasar/Utils/DOTGraph.h b/include/phasar/Utils/DOTGraph.h index cae66e6fc..b16777c9f 100644 --- a/include/phasar/Utils/DOTGraph.h +++ b/include/phasar/Utils/DOTGraph.h @@ -14,8 +14,8 @@ * Author: rleer */ -#ifndef PHASAR_PHASARLLVM_UTILS_DOTGRAPH_H_ -#define PHASAR_PHASARLLVM_UTILS_DOTGRAPH_H_ +#ifndef PHASAR_UTILS_DOTGRAPH_H +#define PHASAR_UTILS_DOTGRAPH_H #include "phasar/Config/Configuration.h" #include "phasar/Utils/Utilities.h" diff --git a/include/phasar/Utils/DefaultValue.h b/include/phasar/Utils/DefaultValue.h index ad2afaf32..3dde71aeb 100644 --- a/include/phasar/Utils/DefaultValue.h +++ b/include/phasar/Utils/DefaultValue.h @@ -7,8 +7,8 @@ * Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H -#define PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H +#ifndef PHASAR_UTILS_DEFAULTVALUE_H +#define PHASAR_UTILS_DEFAULTVALUE_H #include "phasar/Utils/ByRef.h" @@ -42,4 +42,4 @@ getDefaultValue() noexcept(std::is_nothrow_default_constructible_v) { } // namespace psr -#endif // PHASAR_PHASARLLVM_UTILS_DEFAULTVALUE_H +#endif // PHASAR_UTILS_DEFAULTVALUE_H diff --git a/include/phasar/Utils/JoinLattice.h b/include/phasar/Utils/JoinLattice.h index 718eaf6f3..8e748cf78 100644 --- a/include/phasar/Utils/JoinLattice.h +++ b/include/phasar/Utils/JoinLattice.h @@ -14,8 +14,8 @@ * Author: pdschbrt */ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_JOINLATTICE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_JOINLATTICE_H +#ifndef PHASAR_UTILS_JOINLATTICE_H +#define PHASAR_UTILS_JOINLATTICE_H #include #include diff --git a/include/phasar/Utils/Printer.h b/include/phasar/Utils/Printer.h index fae88ba2f..c8f70578d 100644 --- a/include/phasar/Utils/Printer.h +++ b/include/phasar/Utils/Printer.h @@ -7,8 +7,8 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_UTILS_PRINTER_H -#define PHASAR_PHASARLLVM_UTILS_PRINTER_H +#ifndef PHASAR_UTILS_PRINTER_H +#define PHASAR_UTILS_PRINTER_H #include "llvm/Support/raw_ostream.h" diff --git a/include/phasar/Utils/StableVector.h b/include/phasar/Utils/StableVector.h index c7e340451..168972d19 100644 --- a/include/phasar/Utils/StableVector.h +++ b/include/phasar/Utils/StableVector.h @@ -508,7 +508,7 @@ class StableVector { End = Blocks.back() + Size; } - auto Ret = Blocks[BlockIdx]; + auto *Ret = Blocks[BlockIdx]; Start = Ret; Pos = Ret + 1; diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp index de04d2865..1179bcb83 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp @@ -252,7 +252,7 @@ detail::LLVMBasedCFGImpl::getSpecialMemberFunctionTypeImpl( {"aSEOS_", SpecialMemberFunctionType::MoveAssignment}}; llvm::SmallVector> Found; std::size_t Blacklist = 0; - auto It = std::begin(Codes); + const auto *It = std::begin(Codes); while (It != std::end(Codes)) { if (std::size_t Index = FunctionName.find(It->first, Blacklist)) { if (Index != llvm::StringRef::npos) { diff --git a/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp b/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp index dc0a8e99e..76c2f7c82 100644 --- a/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp +++ b/lib/PhasarLLVM/TypeHierarchy/LLVMVFTable.cpp @@ -56,7 +56,7 @@ LLVMVFTable::getVFVectorFromIRVTable(const llvm::ConstantStruct &VT) { if (const auto *CA = llvm::dyn_cast(Op)) { // Start iterating at offset 2, because offset 0 is vbase offset, offset 1 // is RTTI - for (auto It = std::next(CA->operands().begin(), 2); + for (const auto *It = std::next(CA->operands().begin(), 2); It != CA->operands().end(); ++It) { const auto &COp = *It; if (const auto *CE = llvm::dyn_cast(COp)) { diff --git a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp index 3f1a3e83b..d32c9a3ad 100644 --- a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp +++ b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp @@ -128,7 +128,7 @@ std::string getFunctionNameFromIR(const llvm::Value *V) { } std::string getFilePathFromIR(const llvm::Value *V) { - if (auto *DIF = getDIFileFromIR(V)) { + if (const auto *DIF = getDIFileFromIR(V)) { std::filesystem::path File(DIF->getFilename().str()); std::filesystem::path Dir(DIF->getDirectory().str()); if (!File.empty()) { diff --git a/lib/Utils/DOTGraph.cpp b/lib/Utils/DOTGraph.cpp index 80c79e0d7..f745336c2 100644 --- a/lib/Utils/DOTGraph.cpp +++ b/lib/Utils/DOTGraph.cpp @@ -256,7 +256,7 @@ void DOTConfig::importDOTConfig(llvm::StringRef ConfigPath) { Ifs.close(); nlohmann::json JDOTConfig; Iss >> JDOTConfig; - for (auto &El : JDOTConfig.items()) { + for (const auto &El : JDOTConfig.items()) { std::stringstream AttrStr; if (El.key().find("Node") != std::string::npos) { AttrStr << "node ["; diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp index 10e0399ca..f4e913c44 100644 --- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp @@ -178,9 +178,9 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, LCATest1) { // Solver.dumpResults(); - auto *FooInit = IRDB.getInstruction(6); - auto *LoadX = IRDB.getInstruction(11); - auto *End = IRDB.getInstruction(13); + const auto *FooInit = IRDB.getInstruction(6); + const auto *LoadX = IRDB.getInstruction(11); + const auto *End = IRDB.getInstruction(13); const auto *Foo = IRDB.getGlobalVariableDefinition("foo"); auto FooValueAfterInit = Solver.resultAt(FooInit, Foo); @@ -213,11 +213,11 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, LCATest2) { // Solver.dumpResults(); - auto *FooInit = IRDB.getInstruction(7); - auto *BarInit = IRDB.getInstruction(11); - auto *LoadX = IRDB.getInstruction(20); - auto *LoadY = IRDB.getInstruction(21); - auto *End = IRDB.getInstruction(23); + const auto *FooInit = IRDB.getInstruction(7); + const auto *BarInit = IRDB.getInstruction(11); + const auto *LoadX = IRDB.getInstruction(20); + const auto *LoadY = IRDB.getInstruction(21); + const auto *End = IRDB.getInstruction(23); const auto *Foo = IRDB.getGlobalVariableDefinition("foo"); const auto *Bar = IRDB.getGlobalVariableDefinition("bar"); @@ -255,12 +255,12 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, LCATest3) { // Solver.dumpResults(); - auto *FooInit = IRDB.getInstruction(7); + const auto *FooInit = IRDB.getInstruction(7); // FIXME Why is 10 missing in the results set? - auto *BarInit = IRDB.getInstruction(11); - auto *LoadX = IRDB.getInstruction(18); - auto *LoadY = IRDB.getInstruction(19); - auto *End = IRDB.getInstruction(21); + const auto *BarInit = IRDB.getInstruction(11); + const auto *LoadX = IRDB.getInstruction(18); + const auto *LoadY = IRDB.getInstruction(19); + const auto *End = IRDB.getInstruction(21); const auto *Foo = IRDB.getGlobalVariableDefinition("foo"); const auto *Bar = IRDB.getGlobalVariableDefinition("bar"); @@ -300,10 +300,10 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, DISABLED_LCATest4) { // Solver.dumpResults(); - auto *FooGet = IRDB.getInstruction(17); - auto *LoadFoo = IRDB.getInstruction(16); - auto *LoadX = IRDB.getInstruction(34); - auto *End = IRDB.getInstruction(36); + const auto *FooGet = IRDB.getInstruction(17); + const auto *LoadFoo = IRDB.getInstruction(16); + const auto *LoadX = IRDB.getInstruction(34); + const auto *End = IRDB.getInstruction(36); auto FooValueAfterGet = Solver.resultAt(FooGet, LoadFoo); @@ -333,10 +333,10 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, LCATest4_1) { Solver.dumpResults(); - auto *FooGet = IRDB.getInstruction(15); - auto *LoadFoo = IRDB.getInstruction(14); - auto *LoadX = IRDB.getInstruction(20); - auto *End = IRDB.getInstruction(22); + const auto *FooGet = IRDB.getInstruction(15); + const auto *LoadFoo = IRDB.getInstruction(14); + const auto *LoadX = IRDB.getInstruction(20); + const auto *End = IRDB.getInstruction(22); auto FooValueAfterGet = Solver.resultAt(FooGet, LoadFoo); @@ -373,8 +373,8 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, LCATest5) { Solver.dumpResults(); // FIXME: Why is the 27 missing in the results set? - auto *AfterGlobalInit = IRDB.getInstruction(4); - auto *AtMainPrintF = IRDB.getInstruction(29); + const auto *AfterGlobalInit = IRDB.getInstruction(4); + const auto *AtMainPrintF = IRDB.getInstruction(29); const auto *Foo = IRDB.getGlobalVariableDefinition("foo"); diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp index 8de73971f..17a74b610 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCATest.cpp @@ -69,8 +69,8 @@ class IDEGeneralizedLCATest : public ::testing::Test { /// alloca, inst) void compareResults(const std::vector &Expected) { for (const auto &[EVal, VrId, InstId] : Expected) { - auto *Vr = HA->getProjectIRDB().getInstruction(VrId); - auto *Inst = HA->getProjectIRDB().getInstruction(InstId); + const auto *Vr = HA->getProjectIRDB().getInstruction(VrId); + const auto *Inst = HA->getProjectIRDB().getInstruction(InstId); ASSERT_NE(nullptr, Vr); ASSERT_NE(nullptr, Inst); auto Result = LCASolver->resultAt(Inst, Vr); From 907d01d792c707f7f97a1c0ed3eb3dd23b0eee87 Mon Sep 17 00:00:00 2001 From: StamesJames Date: Wed, 26 Jul 2023 18:30:49 +0200 Subject: [PATCH 21/59] added descriptions to TaintConfigSchema.json to explain its semantics (#644) * added descriptions to TaintConfigSchema.json to explain its semantics * capitalize first letter of descriptions consistently * Remove parentheses which broke the compilation --------- Co-authored-by: Martin Mory --- config/TaintConfigSchema.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/config/TaintConfigSchema.json b/config/TaintConfigSchema.json index d5599b517..25264e256 100644 --- a/config/TaintConfigSchema.json +++ b/config/TaintConfigSchema.json @@ -14,29 +14,36 @@ R"( "description": "Version of this taint configuration" }, "functions": { + "description": "Array of functions you want to include in your analysis", "type": "array", "properties": { "name": { - "type": "string" + "type": "string", + "description": "Name of the function in the llvm IR, look for possible mangling" }, "ret": { - "enum": ["source", "sink", "sanitizer"] + "enum": ["source", "sink", "sanitizer"], + "description": "Tags the returned value as source sink or sanitizer" }, "params": { + "description": "Tags function parameters as source, sink or sanitizer", "properties": { "source": { + "description": "Zero based indices of source tags", "type": "array", "properties": { "type": ["number", "string"] } }, "sink": { + "description": "Zero based indices of sink tags. A Leak is detected if the function gets called with source taged value in this indices.", "type": "array", "properties": { "type": ["number", "string"] } }, "sanitizer": { + "description": "Zero based indices of sanitizer tags", "type": "array", "properties": { "type": ["number", "string"] From f1c58653fd5eb6b0c050521d5b426f4c015408ed Mon Sep 17 00:00:00 2001 From: Martin Mory Date: Mon, 31 Jul 2023 17:38:21 +0200 Subject: [PATCH 22/59] fix uninitialized pointer that is used for SOO, making valgrind happy (#647) Co-authored-by: Martin Mory --- include/phasar/DataFlow/IfdsIde/EdgeFunction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index 1c68c9b34..72f33565a 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -263,7 +263,7 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { : EdgeFunction( [](auto &&...Args) { if constexpr (IsSOOCandidate>) { - void *Ret; + void *Ret = nullptr; new (&Ret) ConcreteEF(std::forward(Args)...); return Ret; } else { From 49f3310c74970e35b0443a5e9a86cd514d5d6d7c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Wed, 2 Aug 2023 15:28:57 +0200 Subject: [PATCH 23/59] Fix taint analysis (#648) * Move Source/Sink/Sanitizer handling from CTR to Summary FF preventing those functions from being analyzed * Fix TA summary FF * Add insertvalue and bitcast handling * Improve alias-handling in TA * minor style --- .../DataFlow/IfdsIde/LLVMFlowFunctions.h | 6 + .../IfdsIde/Problems/IFDSTaintAnalysis.h | 6 +- .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 307 ++++++++++-------- 3 files changed, 177 insertions(+), 142 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h index f3af3cc81..57bff2b65 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h @@ -179,6 +179,12 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, llvm::Function::const_arg_iterator ParamIt = DestFun->arg_begin(); llvm::Function::const_arg_iterator ParamEnd = DestFun->arg_end(); + if (ParamIt != ParamEnd && (*ParamIt).hasStructRetAttr()) { + // sret parameters are writeonly + ++ParamIt; + ++ArgIt; + } + for (; ParamIt != ParamEnd; ++ParamIt, ++ArgIt) { if (std::invoke(PropArg, ArgIt->get(), Source)) { Res.insert(std::invoke(FactConstructor, &*ParamIt)); diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h index b39e22a42..9df7cf69b 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -98,8 +98,10 @@ class IFDSTaintAnalysis bool isSanitizerCall(const llvm::CallBase *CB, const llvm::Function *Callee) const; - void populateWithMayAliases(std::set &Facts) const; - void populateWithMustAliases(std::set &Facts) const; + void populateWithMayAliases(container_type &Facts, + const llvm::Instruction *Context) const; + void populateWithMustAliases(container_type &Facts, + const llvm::Instruction *Context) const; }; } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index 13fa3aa4b..ddf60d016 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -24,8 +24,13 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Demangle/Demangle.h" #include "llvm/IR/AbstractCallSite.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include @@ -105,66 +110,105 @@ bool IFDSTaintAnalysis::isSanitizerCall(const llvm::CallBase * /*CB*/, [this](const auto &Arg) { return Config->isSanitizer(&Arg); }); } -void IFDSTaintAnalysis::populateWithMayAliases(std::set &Facts) const { - std::set Tmp = Facts; +void IFDSTaintAnalysis::populateWithMayAliases( + container_type &Facts, const llvm::Instruction *Context) const { + container_type Tmp = Facts; for (const auto *Fact : Facts) { auto Aliases = PT.getAliasSet(Fact); - Tmp.insert(Aliases->begin(), Aliases->end()); + for (const auto *Alias : *Aliases) { + if (const auto *Inst = llvm::dyn_cast(Alias)) { + /// Mapping instructions between functions is done via the call-FF and + /// ret-FF + if (Inst->getFunction() != Context->getFunction()) { + continue; + } + if (Inst->getParent() == Context->getParent() && + Context->comesBefore(Inst)) { + // We will see that inst later + continue; + } + } else if (const auto *Glob = + llvm::dyn_cast(Alias)) { + if (Glob != Fact && Glob->isConstant()) { + // Data cannot flow into the readonly-data section + continue; + } + } + + Tmp.insert(Alias); + } } Facts = std::move(Tmp); } -void IFDSTaintAnalysis::populateWithMustAliases(std::set &Facts) const { +void IFDSTaintAnalysis::populateWithMustAliases( + container_type &Facts, const llvm::Instruction *Context) const { /// TODO: Find must-aliases; Currently the AliasSet only contains /// may-aliases } -IFDSTaintAnalysis::FlowFunctionPtrType IFDSTaintAnalysis::getNormalFlowFunction( - IFDSTaintAnalysis::n_t Curr, [[maybe_unused]] IFDSTaintAnalysis::n_t Succ) { +auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, + [[maybe_unused]] n_t Succ) + -> FlowFunctionPtrType { // If a tainted value is stored, the store location must be tainted too if (const auto *Store = llvm::dyn_cast(Curr)) { - struct TAFF : FlowFunction { - const llvm::StoreInst *Store; - TAFF(const llvm::StoreInst *S) : Store(S){}; - std::set - computeTargets(IFDSTaintAnalysis::d_t Source) override { - if (Store->getValueOperand() == Source) { - return std::set{Store->getPointerOperand(), - Source}; - } - if (Store->getValueOperand() != Source && - Store->getPointerOperand() == Source) { - return {}; - } - return {Source}; - } - }; - return std::make_shared(Store); + container_type Gen; + Gen.insert(Store->getPointerOperand()); + populateWithMayAliases(Gen, Store); + Gen.insert(Store->getValueOperand()); + + return lambdaFlow( + [Store, Gen{std::move(Gen)}](d_t Source) -> container_type { + if (Store->getValueOperand() == Source) { + return Gen; + } + if (Store->getPointerOperand() == Source) { + return {}; + } + return {Source}; + }); } // If a tainted value is loaded, the loaded value is of course tainted if (const auto *Load = llvm::dyn_cast(Curr)) { - return generateFlow(Load, Load->getPointerOperand()); + return transferFlow(Load, Load->getPointerOperand()); } // Check if an address is computed from a tainted base pointer of an // aggregated object if (const auto *GEP = llvm::dyn_cast(Curr)) { - return generateFlow(GEP, GEP->getPointerOperand()); + return transferFlow(GEP, GEP->getPointerOperand()); } // Check if a tainted value is extracted and taint the targets of // the extract operation accordingly if (const auto *Extract = llvm::dyn_cast(Curr)) { + return transferFlow(Extract, Extract->getAggregateOperand()); + } + + if (const auto *Insert = llvm::dyn_cast(Curr)) { + return lambdaFlow([Insert](d_t Source) -> container_type { + if (Source == Insert->getAggregateOperand() || + Source == Insert->getInsertedValueOperand()) { + return {Source, Insert}; + } + + if (Source == Insert) { + return {}; + } + + return {Source}; + }); + } - return generateFlow(Extract, Extract->getAggregateOperand()); + if (const auto *Cast = llvm::dyn_cast(Curr)) { + return transferFlow(Cast, Cast->getOperand(0)); } // Otherwise we do not care and leave everything as it is - return Identity::getInstance(); + return Identity::getInstance(); } -IFDSTaintAnalysis::FlowFunctionPtrType -IFDSTaintAnalysis::getCallFlowFunction(IFDSTaintAnalysis::n_t CallSite, - IFDSTaintAnalysis::f_t DestFun) { +auto IFDSTaintAnalysis::getCallFlowFunction(n_t CallSite, f_t DestFun) + -> FlowFunctionPtrType { const auto *CS = llvm::cast(CallSite); // Check if a source or sink function is called: // We then can kill all data-flow facts not following the called function. @@ -178,10 +222,10 @@ IFDSTaintAnalysis::getCallFlowFunction(IFDSTaintAnalysis::n_t CallSite, return mapFactsToCallee(CS, DestFun); } -IFDSTaintAnalysis::FlowFunctionPtrType IFDSTaintAnalysis::getRetFlowFunction( - IFDSTaintAnalysis::n_t CallSite, IFDSTaintAnalysis::f_t /*CalleeFun*/, - IFDSTaintAnalysis::n_t ExitStmt, - [[maybe_unused]] IFDSTaintAnalysis::n_t RetSite) { +auto IFDSTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t /*CalleeFun*/, + n_t ExitStmt, + [[maybe_unused]] n_t RetSite) + -> FlowFunctionPtrType { // We must check if the return value and formal parameter are tainted, if so // we must taint all user's of the function call. We are only interested in // formal parameters of pointer/reference type. @@ -194,74 +238,86 @@ IFDSTaintAnalysis::FlowFunctionPtrType IFDSTaintAnalysis::getRetFlowFunction( // All other stuff is killed at this point } -IFDSTaintAnalysis::FlowFunctionPtrType -IFDSTaintAnalysis::getCallToRetFlowFunction( - IFDSTaintAnalysis::n_t CallSite, - [[maybe_unused]] IFDSTaintAnalysis::n_t RetSite, - llvm::ArrayRef Callees) { +auto IFDSTaintAnalysis::getCallToRetFlowFunction(n_t CallSite, + [[maybe_unused]] n_t RetSite, + llvm::ArrayRef Callees) + -> FlowFunctionPtrType { + const auto *CS = llvm::cast(CallSite); - std::set Gen; - std::set Leak; - std::set Kill; - bool HasBody = false; - // Process the effects of source or sink functions that are called - for (const auto *Callee : Callees) { - if (!Callee->isDeclaration()) { - HasBody = true; - } - collectGeneratedFacts(Gen, *Config, CS, Callee); - collectLeakedFacts(Leak, *Config, CS, Callee); - collectSanitizedFacts(Kill, *Config, CS, Callee); - } - if (HasBody && Gen.empty() && Leak.empty() && Kill.empty()) { - // We have a normal function-call and the ret-FF is responsible for handling - // pointer parameters. So we need to kill them here - for (const auto &Arg : CS->args()) { - if (Arg->getType()->isPointerTy()) { - Kill.insert(Arg.get()); - } - } + bool HasDeclOnly = llvm::any_of( + Callees, [](const auto *DestFun) { return DestFun->isDeclaration(); }); + + return mapFactsAlongsideCallSite(CS, [HasDeclOnly](d_t Arg) { + return HasDeclOnly || !Arg->getType()->isPointerTy(); + }); +} + +auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, + [[maybe_unused]] f_t DestFun) + -> FlowFunctionPtrType { + // $sSS1poiyS2S_SStFZ is Swift's String append method + // if concat a tainted string with something else the + // result should be tainted + if (DestFun->getName().equals("$sSS1poiyS2S_SStFZ")) { + const auto *CS = llvm::cast(CallSite); + + return generateFlowIf(CallSite, [CS](d_t Source) { + return ((Source == CS->getArgOperand(1)) || + (Source == CS->getArgOperand(3))); + }); } - populateWithMayAliases(Gen); - populateWithMayAliases(Leak); + const auto *CS = llvm::cast(CallSite); + container_type Gen; + container_type Leak; + container_type Kill; - Gen.insert(LLVMZeroValue::getInstance()); + // Process the effects of source or sink functions that are called + collectGeneratedFacts(Gen, *Config, CS, DestFun); + collectLeakedFacts(Leak, *Config, CS, DestFun); + collectSanitizedFacts(Kill, *Config, CS, DestFun); + + populateWithMayAliases(Gen, CallSite); + /// We now generate all aliases within the flow functions as facts, so we can + /// safely just check for the sink values here + // populateWithMayAliases(Leak, CallSite); + populateWithMustAliases(Kill, CallSite); + + if (CS->hasStructRetAttr()) { + const auto *SRet = CS->getArgOperand(0); + if (!Gen.count(SRet)) { + // SRet is guaranteed to be written to by the call. If it does not + // generate it, we can freely kill it + Kill.insert(SRet); + } + } - populateWithMustAliases(Kill); + if (Gen.empty()) { + if (!Leak.empty() || !Kill.empty()) { + return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, + this, CallSite](d_t Source) -> container_type { + if (Leak.count(Source)) { + Leaks[CallSite].insert(Source); + } - if (Gen.empty() && (!Leak.empty() || !Kill.empty())) { - return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, this, - CallSite](d_t Source) -> std::set { - if (Leak.count(Source)) { - Leaks[CallSite].insert(Source); - } + if (Kill.count(Source)) { + return {}; + } - if (Kill.count(Source)) { - return {}; - } + return {Source}; + }); + } - return {Source}; - }); + // all empty + return nullptr; } - if (Kill.empty()) { - return lambdaFlow([Gen{std::move(Gen)}, Leak{std::move(Leak)}, this, - CallSite](d_t Source) -> std::set { - if (LLVMZeroValue::isLLVMZeroValue(Source)) { - return Gen; - } - if (Leak.count(Source)) { - Leaks[CallSite].insert(Source); - } + // Gen nonempty - return {Source}; - }); - } - return lambdaFlow([Gen{std::move(Gen)}, Leak{std::move(Leak)}, - Kill{std::move(Kill)}, this, - CallSite](d_t Source) -> std::set { + Gen.insert(LLVMZeroValue::getInstance()); + return lambdaFlow([Gen{std::move(Gen)}, Leak{std::move(Leak)}, this, + CallSite](d_t Source) -> container_type { if (LLVMZeroValue::isLLVMZeroValue(Source)) { return Gen; } @@ -270,38 +326,11 @@ IFDSTaintAnalysis::getCallToRetFlowFunction( Leaks[CallSite].insert(Source); } - if (Kill.count(Source)) { - return {}; - } - return {Source}; }); - - // Otherwise pass everything as it is - return Identity::getInstance(); -} - -IFDSTaintAnalysis::FlowFunctionPtrType -IFDSTaintAnalysis::getSummaryFlowFunction( - [[maybe_unused]] IFDSTaintAnalysis::n_t CallSite, - [[maybe_unused]] IFDSTaintAnalysis::f_t DestFun) { - // $sSS1poiyS2S_SStFZ is Swift's String append method - // if concat a tainted string with something else the - // result should be tainted - if (DestFun->getName().equals("$sSS1poiyS2S_SStFZ")) { - const auto *CS = llvm::cast(CallSite); - - return generateFlowIf(CallSite, [CS](d_t Source) { - return ((Source == CS->getArgOperand(1)) || - (Source == CS->getArgOperand(3))); - }); - } - return nullptr; } -InitialSeeds -IFDSTaintAnalysis::initialSeeds() { +auto IFDSTaintAnalysis::initialSeeds() -> InitialSeeds { PHASAR_LOG_LEVEL(DEBUG, "IFDSTaintAnalysis::initialSeeds()"); // If main function is the entry point, commandline arguments have to be // tainted. Otherwise we just use the zero value to initialize the analysis. @@ -311,7 +340,6 @@ IFDSTaintAnalysis::initialSeeds() { forallStartingPoints(EntryPoints, IRDB, C, [this, &Seeds](n_t SP) { Seeds.addSeed(SP, getZeroValue()); if (SP->getFunction()->getName() == "main") { - std::set CmdArgs; for (const auto &Arg : SP->getFunction()->args()) { Seeds.addSeed(SP, &Arg); } @@ -321,28 +349,26 @@ IFDSTaintAnalysis::initialSeeds() { return Seeds; } -IFDSTaintAnalysis::d_t IFDSTaintAnalysis::createZeroValue() const { +auto IFDSTaintAnalysis::createZeroValue() const -> d_t { PHASAR_LOG_LEVEL(DEBUG, "IFDSTaintAnalysis::createZeroValue()"); // create a special value to represent the zero value! return LLVMZeroValue::getInstance(); } -bool IFDSTaintAnalysis::isZeroValue(IFDSTaintAnalysis::d_t FlowFact) const { +bool IFDSTaintAnalysis::isZeroValue(d_t FlowFact) const { return LLVMZeroValue::isLLVMZeroValue(FlowFact); } -void IFDSTaintAnalysis::printNode(llvm::raw_ostream &Os, - IFDSTaintAnalysis::n_t Inst) const { +void IFDSTaintAnalysis::printNode(llvm::raw_ostream &Os, n_t Inst) const { Os << llvmIRToString(Inst); } -void IFDSTaintAnalysis::printDataFlowFact( - llvm::raw_ostream &Os, IFDSTaintAnalysis::d_t FlowFact) const { +void IFDSTaintAnalysis::printDataFlowFact(llvm::raw_ostream &Os, + d_t FlowFact) const { Os << llvmIRToString(FlowFact); } -void IFDSTaintAnalysis::printFunction(llvm::raw_ostream &Os, - IFDSTaintAnalysis::f_t Fun) const { +void IFDSTaintAnalysis::printFunction(llvm::raw_ostream &Os, f_t Fun) const { Os << Fun->getName(); } @@ -352,21 +378,22 @@ void IFDSTaintAnalysis::emitTextReport( OS << "\n----- Found the following leaks -----\n"; if (Leaks.empty()) { OS << "No leaks found!\n"; - } else { - for (const auto &Leak : Leaks) { - OS << "At instruction\nIR : " << llvmIRToString(Leak.first) << '\n'; - OS << "\n\nLeak(s):\n"; - for (const auto *LeakedValue : Leak.second) { - OS << "IR : "; - // Get the actual leaked alloca instruction if possible - if (const auto *Load = llvm::dyn_cast(LeakedValue)) { - OS << llvmIRToString(Load->getPointerOperand()) << '\n'; - } else { - OS << llvmIRToString(LeakedValue) << '\n'; - } + return; + } + + for (const auto &Leak : Leaks) { + OS << "At instruction\nIR : " << llvmIRToString(Leak.first) << '\n'; + OS << "\nLeak(s):\n"; + for (const auto *LeakedValue : Leak.second) { + OS << "IR : "; + // Get the actual leaked alloca instruction if possible + if (const auto *Load = llvm::dyn_cast(LeakedValue)) { + OS << llvmIRToString(Load->getPointerOperand()) << '\n'; + } else { + OS << llvmIRToString(LeakedValue) << '\n'; } - OS << "-------------------\n"; } + OS << "-------------------\n"; } } From 4a582240aa81ef5ede8853c4e23956f1b2adb15b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 15 Aug 2023 19:36:57 +0200 Subject: [PATCH 24/59] Fix and update PAMM (#655) --- CMakeLists.txt | 14 +- .../IfdsIde/Solver/FlowEdgeFunctionCache.h | 82 ++-- .../DataFlow/IfdsIde/Solver/IDESolver.h | 141 +++--- .../phasar/DataFlow/IfdsIde/SolverResults.h | 4 +- include/phasar/Utils/PAMM.h | 89 ++-- include/phasar/Utils/PAMMMacros.h | 41 +- include/phasar/Utils/TypeTraits.h | 22 + include/phasar/Utils/Utilities.h | 13 + lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp | 9 +- .../IfdsIde/Problems/IFDSConstAnalysis.cpp | 17 +- .../Passes/GeneralStatisticsAnalysis.cpp | 26 +- lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp | 11 +- lib/Utils/PAMM.cpp | 444 ++++++++++-------- unittests/Utils/PAMMTest.cpp | 127 ++--- 14 files changed, 532 insertions(+), 508 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cec3c6243..b9eb75366 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,15 +117,15 @@ if (NOT PHASAR_ENABLE_PAMM) 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") + add_compile_definitions(PAMM_CORE) + message(STATUS "PAMM metric severity level: Core") elseif(PHASAR_ENABLE_PAMM STREQUAL "Full" AND NOT PHASAR_BUILD_UNITTESTS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPAMM_FULL") - message("PAMM metric severity level: Full") -elseif(PHASAR_BUILD_UNITTESTS) - message("PAMM metric severity level: Off (due to unittests)") + add_compile_definitions(PAMM_FULL) + message(STATUS "PAMM metric severity level: Full") +elseif(PHASAR_BUILD_UNITTESTS AND (PHASAR_ENABLE_PAMM STREQUAL "Core" OR PHASAR_ENABLE_PAMM STREQUAL "Full")) + message(WARNING "PAMM metric severity level: Off (due to unittests)") else() - message("PAMM metric severity level: Off") + message(STATUS "PAMM metric severity level: Off") endif() option(PHASAR_ENABLE_DYNAMIC_LOG "Makes it possible to switch the logger on and off at runtime (default is ON)" ON) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h index 23d4b918c..a670a403f 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h @@ -144,35 +144,35 @@ class FlowEdgeFunctionCache { AutoAddZero(Problem.getIFDSIDESolverConfig().autoAddZero()), ZV(Problem.getZeroValue()) { PAMM_GET_INSTANCE; - REG_COUNTER("Normal-FF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Normal-FF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Normal-FF Construction", 0, Full); + REG_COUNTER("Normal-FF Cache Hit", 0, Full); // Counters for the call flow functions - REG_COUNTER("Call-FF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Call-FF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Call-FF Construction", 0, Full); + REG_COUNTER("Call-FF Cache Hit", 0, Full); // Counters for return flow functions - REG_COUNTER("Return-FF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Return-FF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Return-FF Construction", 0, Full); + REG_COUNTER("Return-FF Cache Hit", 0, Full); // Counters for the call to return flow functions - REG_COUNTER("CallToRet-FF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("CallToRet-FF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("CallToRet-FF Construction", 0, Full); + REG_COUNTER("CallToRet-FF Cache Hit", 0, Full); // Counters for the summary flow functions - REG_COUNTER("Summary-FF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Summary-FF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Summary-FF Construction", 0, Full); + REG_COUNTER("Summary-FF Cache Hit", 0, Full); // Counters for the normal edge functions - REG_COUNTER("Normal-EF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Normal-EF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Normal-EF Construction", 0, Full); + REG_COUNTER("Normal-EF Cache Hit", 0, Full); // Counters for the call edge functions - REG_COUNTER("Call-EF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Call-EF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Call-EF Construction", 0, Full); + REG_COUNTER("Call-EF Cache Hit", 0, Full); // Counters for the return edge functions - REG_COUNTER("Return-EF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Return-EF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Return-EF Construction", 0, Full); + REG_COUNTER("Return-EF Cache Hit", 0, Full); // Counters for the call to return edge functions - REG_COUNTER("CallToRet-EF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("CallToRet-EF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("CallToRet-EF Construction", 0, Full); + REG_COUNTER("CallToRet-EF Cache Hit", 0, Full); // Counters for the summary edge functions - REG_COUNTER("Summary-EF Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Summary-EF Cache Hit", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Summary-EF Construction", 0, Full); + REG_COUNTER("Summary-EF Cache Hit", 0, Full); } ~FlowEdgeFunctionCache() = default; @@ -194,7 +194,7 @@ class FlowEdgeFunctionCache { auto SearchNormalFlowFunction = NormalFunctionCache.find(Key); if (SearchNormalFlowFunction != NormalFunctionCache.end()) { PHASAR_LOG_LEVEL(DEBUG, "Flow function fetched from cache"); - INC_COUNTER("Normal-FF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Normal-FF Cache Hit", 1, Full); if (SearchNormalFlowFunction->second.FlowFuncPtr != nullptr) { return SearchNormalFlowFunction->second.FlowFuncPtr; } @@ -205,7 +205,7 @@ class FlowEdgeFunctionCache { SearchNormalFlowFunction->second.FlowFuncPtr = FF; return FF; } - INC_COUNTER("Normal-FF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Normal-FF Construction", 1, Full); auto FF = (AutoAddZero) ? std::make_shared>( Problem.getNormalFlowFunction(Curr, Succ), ZV) @@ -227,10 +227,10 @@ class FlowEdgeFunctionCache { auto SearchCallFlowFunction = CallFlowFunctionCache.find(Key); if (SearchCallFlowFunction != CallFlowFunctionCache.end()) { PHASAR_LOG_LEVEL(DEBUG, "Flow function fetched from cache"); - INC_COUNTER("Call-FF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Call-FF Cache Hit", 1, Full); return SearchCallFlowFunction->second; } - INC_COUNTER("Call-FF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Call-FF Construction", 1, Full); auto FF = (AutoAddZero) ? std::make_shared>( Problem.getCallFlowFunction(CallSite, DestFun), ZV) @@ -257,10 +257,10 @@ class FlowEdgeFunctionCache { auto SearchReturnFlowFunction = ReturnFlowFunctionCache.find(Key); if (SearchReturnFlowFunction != ReturnFlowFunctionCache.end()) { PHASAR_LOG_LEVEL(DEBUG, "Flow function fetched from cache"); - INC_COUNTER("Return-FF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Return-FF Cache Hit", 1, Full); return SearchReturnFlowFunction->second; } - INC_COUNTER("Return-FF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Return-FF Construction", 1, Full); auto FF = (AutoAddZero) ? std::make_shared>( Problem.getRetFlowFunction(CallSite, CalleeFun, @@ -291,10 +291,10 @@ class FlowEdgeFunctionCache { auto SearchCallToRetFlowFunction = CallToRetFlowFunctionCache.find(Key); if (SearchCallToRetFlowFunction != CallToRetFlowFunctionCache.end()) { PHASAR_LOG_LEVEL(DEBUG, "Flow function fetched from cache"); - INC_COUNTER("CallToRet-FF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("CallToRet-FF Cache Hit", 1, Full); return SearchCallToRetFlowFunction->second; } - INC_COUNTER("CallToRet-FF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("CallToRet-FF Construction", 1, Full); auto FF = (AutoAddZero) ? std::make_shared>( @@ -308,7 +308,7 @@ class FlowEdgeFunctionCache { FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) { // PAMM_GET_INSTANCE; - // INC_COUNTER("Summary-FF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + // INC_COUNTER("Summary-FF Construction", 1, Full); IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Summary flow function factory call"); PHASAR_LOG_LEVEL(DEBUG, @@ -338,13 +338,13 @@ class FlowEdgeFunctionCache { auto SearchEdgeFunc = SearchInnerMap->second.EdgeFunctionMap.find( createEdgeFunctionNodeKey(CurrNode, SuccNode)); if (SearchEdgeFunc != SearchInnerMap->second.EdgeFunctionMap.end()) { - INC_COUNTER("Normal-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Normal-EF Cache Hit", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << SearchEdgeFunc->second); return SearchEdgeFunc->second; } - INC_COUNTER("Normal-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Normal-EF Construction", 1, Full); auto EF = Problem.getNormalEdgeFunction(Curr, CurrNode, Succ, SuccNode); SearchInnerMap->second.EdgeFunctionMap.insert( @@ -354,7 +354,7 @@ class FlowEdgeFunctionCache { PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } - INC_COUNTER("Normal-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Normal-EF Construction", 1, Full); auto EF = Problem.getNormalEdgeFunction(Curr, CurrNode, Succ, SuccNode); NormalFunctionCache.try_emplace( @@ -383,13 +383,13 @@ class FlowEdgeFunctionCache { auto Key = std::tie(CallSite, SrcNode, DestinationFunction, DestNode); auto SearchCallEdgeFunction = CallEdgeFunctionCache.find(Key); if (SearchCallEdgeFunction != CallEdgeFunctionCache.end()) { - INC_COUNTER("Call-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Call-EF Cache Hit", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); PHASAR_LOG_LEVEL( DEBUG, "Provide Edge Function: " << SearchCallEdgeFunction->second); return SearchCallEdgeFunction->second; } - INC_COUNTER("Call-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Call-EF Construction", 1, Full); auto EF = Problem.getCallEdgeFunction(CallSite, SrcNode, DestinationFunction, DestNode); CallEdgeFunctionCache.insert(std::make_pair(Key, EF)); @@ -420,13 +420,13 @@ class FlowEdgeFunctionCache { RetNode); auto SearchReturnEdgeFunction = ReturnEdgeFunctionCache.find(Key); if (SearchReturnEdgeFunction != ReturnEdgeFunctionCache.end()) { - INC_COUNTER("Return-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Return-EF Cache Hit", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); PHASAR_LOG_LEVEL( DEBUG, "Provide Edge Function: " << SearchReturnEdgeFunction->second); return SearchReturnEdgeFunction->second; } - INC_COUNTER("Return-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Return-EF Construction", 1, Full); auto EF = Problem.getReturnEdgeFunction(CallSite, CalleeFunction, ExitInst, ExitNode, RetSite, RetNode); ReturnEdgeFunctionCache.insert(std::make_pair(Key, EF)); @@ -462,13 +462,13 @@ class FlowEdgeFunctionCache { auto SearchEdgeFunc = SearchInnerMap->second.find( createEdgeFunctionNodeKey(CallNode, RetSiteNode)); if (SearchEdgeFunc != SearchInnerMap->second.end()) { - INC_COUNTER("CallToRet-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("CallToRet-EF Cache Hit", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << SearchEdgeFunc->second); return SearchEdgeFunc->second; } - INC_COUNTER("CallToRet-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("CallToRet-EF Construction", 1, Full); auto EF = Problem.getCallToRetEdgeFunction(CallSite, CallNode, RetSite, RetSiteNode, Callees); @@ -480,7 +480,7 @@ class FlowEdgeFunctionCache { return EF; } - INC_COUNTER("CallToRet-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("CallToRet-EF Construction", 1, Full); auto EF = Problem.getCallToRetEdgeFunction(CallSite, CallNode, RetSite, RetSiteNode, Callees); @@ -510,13 +510,13 @@ class FlowEdgeFunctionCache { auto Key = std::tie(CallSite, CallNode, RetSite, RetSiteNode); auto SearchSummaryEdgeFunction = SummaryEdgeFunctionCache.find(Key); if (SearchSummaryEdgeFunction != SummaryEdgeFunctionCache.end()) { - INC_COUNTER("Summary-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Summary-EF Cache Hit", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << SearchSummaryEdgeFunction->second); return SearchSummaryEdgeFunction->second; } - INC_COUNTER("Summary-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Summary-EF Construction", 1, Full); auto EF = Problem.getSummaryEdgeFunction(CallSite, CallNode, RetSite, RetSiteNode); SummaryEdgeFunctionCache.insert(std::make_pair(Key, EF)); diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 0eb324dc0..41207a44d 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -281,7 +281,7 @@ class IDESolver /// virtual void processCall(const PathEdge Edge) { PAMM_GET_INSTANCE; - INC_COUNTER("Process Call", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Process Call", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Process call at target: " << IDEProblem.NtoString(Edge.getTarget())); d_t d1 = Edge.factAtSource(); @@ -313,17 +313,14 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "Found and process special summary"); for (n_t ReturnSiteN : ReturnSiteNs) { container_type Res = computeSummaryFlowFunction(SpecialSum, d1, d2); - INC_COUNTER("SpecialSummary-FF Application", 1, - PAMM_SEVERITY_LEVEL::Full); - ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, - PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("SpecialSummary-FF Application", 1, Full); + ADD_TO_HISTOGRAM("Data-flow facts", Res.size(), 1, Full); saveEdges(n, ReturnSiteN, d2, Res, false); for (d_t d3 : Res) { EdgeFunction SumEdgFnE = CachedFlowEdgeFunctions.getSummaryEdgeFunction(n, d2, ReturnSiteN, d3); - INC_COUNTER("SpecialSummary-EF Queries", 1, - PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("SpecialSummary-EF Queries", 1, Full); IF_LOG_ENABLED( PHASAR_LOG_LEVEL( DEBUG, "Queried Summary Edge Function: " << SumEdgFnE); @@ -337,10 +334,9 @@ class IDESolver // compute the call-flow function FlowFunctionPtrType Function = CachedFlowEdgeFunctions.getCallFlowFunction(n, SCalledProcN); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("FF Queries", 1, Full); container_type Res = computeCallFlowFunction(Function, d1, d2); - ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, - PAMM_SEVERITY_LEVEL::Full); + ADD_TO_HISTOGRAM("Data-flow facts", Res.size(), 1, Full); // for each callee's start point(s) auto StartPointsOf = ICF->getStartPointsOf(SCalledProcN); if (StartPointsOf.empty()) { @@ -386,11 +382,11 @@ class IDESolver FlowFunctionPtrType RetFunction = CachedFlowEdgeFunctions.getRetFlowFunction(n, SCalledProcN, eP, RetSiteN); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + 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, - PAMM_SEVERITY_LEVEL::Full); + ADD_TO_HISTOGRAM("Data-flow facts", ReturnedFacts.size(), 1, + Full); saveEdges(eP, RetSiteN, d4, ReturnedFacts, true); // for each target value of the function for (d_t d5 : ReturnedFacts) { @@ -415,7 +411,7 @@ class IDESolver d5)] .push_back(f5); } - INC_COUNTER("EF Queries", 2, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("EF Queries", 2, Full); // compose call * calleeSummary * return edge functions PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5 << " * " << fCalleeSummary << " * " @@ -444,11 +440,10 @@ class IDESolver FlowFunctionPtrType CallToReturnFF = CachedFlowEdgeFunctions.getCallToRetFlowFunction(n, ReturnSiteN, Callees); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("FF Queries", 1, Full); container_type ReturnFacts = computeCallToReturnFlowFunction(CallToReturnFF, d1, d2); - ADD_TO_HISTOGRAM("Data-flow facts", returnFacts.size(), 1, - PAMM_SEVERITY_LEVEL::Full); + ADD_TO_HISTOGRAM("Data-flow facts", ReturnFacts.size(), 1, Full); saveEdges(n, ReturnSiteN, d2, ReturnFacts, false); for (d_t d3 : ReturnFacts) { EdgeFunction EdgeFnE = @@ -460,7 +455,7 @@ class IDESolver IntermediateEdgeFunctions[std::make_tuple(n, d2, ReturnSiteN, d3)] .push_back(EdgeFnE); } - INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("EF Queries", 1, Full); auto fPrime = f.composeWith(EdgeFnE); PHASAR_LOG_LEVEL(DEBUG, "Compose: " << EdgeFnE << " * " << f << " = " << fPrime); @@ -476,7 +471,7 @@ class IDESolver /// virtual void processNormalFlow(PathEdge Edge) { PAMM_GET_INSTANCE; - INC_COUNTER("Process Normal", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Process Normal", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Process normal at target: " << IDEProblem.NtoString(Edge.getTarget())); EdgeFunction f = jumpFunction(Edge); @@ -485,10 +480,9 @@ class IDESolver for (const auto nPrime : ICF->getSuccsOf(n)) { FlowFunctionPtrType FlowFunc = CachedFlowEdgeFunctions.getNormalFlowFunction(n, nPrime); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("FF Queries", 1, Full); const container_type Res = computeNormalFlowFunction(FlowFunc, d1, d2); - ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, - PAMM_SEVERITY_LEVEL::Full); + ADD_TO_HISTOGRAM("Data-flow facts", Res.size(), 1, Full); saveEdges(n, nPrime, d2, Res, false); for (d_t d3 : Res) { EdgeFunction g = @@ -501,7 +495,7 @@ class IDESolver } PHASAR_LOG_LEVEL(DEBUG, "Compose: " << g << " * " << f << " = " << fPrime); - INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("EF Queries", 1, Full); WorkList.emplace_back(PathEdge(d1, nPrime, std::move(d3)), std::move(fPrime)); } @@ -523,7 +517,7 @@ class IDESolver auto fPrime = Entry.second; n_t SP = Stmt; l_t Val = val(SP, Fact); - INC_COUNTER("Value Propagation", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Value Propagation", 1, Full); propagateValue(CallSite, dPrime, fPrime.computeTarget(Val)); } } @@ -535,7 +529,7 @@ class IDESolver for (const f_t Callee : ICF->getCalleesOfCallAt(Stmt)) { FlowFunctionPtrType CallFlowFunction = CachedFlowEdgeFunctions.getCallFlowFunction(Stmt, Callee); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("FF Queries", 1, Full); for (const d_t dPrime : CallFlowFunction->computeTargets(Fact)) { EdgeFunction EdgeFn = CachedFlowEdgeFunctions.getCallEdgeFunction( Stmt, Fact, Callee, dPrime); @@ -546,9 +540,9 @@ class IDESolver .push_back(EdgeFn); } } - INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("EF Queries", 1, Full); for (const n_t StartPoint : ICF->getStartPointsOf(Callee)) { - INC_COUNTER("Value Propagation", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Value Propagation", 1, Full); propagateValue(StartPoint, dPrime, EdgeFn.computeTarget(val(Stmt, Fact))); } @@ -629,7 +623,7 @@ class IDESolver // should be made a callable at some point void pathEdgeProcessingTask(PathEdge Edge) { PAMM_GET_INSTANCE; - INC_COUNTER("JumpFn Construction", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("JumpFn Construction", 1, Full); IF_LOG_ENABLED( PHASAR_LOG_LEVEL( DEBUG, @@ -696,7 +690,7 @@ class IDESolver setVal(n, d, IDEProblem.join(val(n, d), fPrime.computeTarget(std::move(TargetVal)))); - INC_COUNTER("Value Computation", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Value Computation", 1, Full); } } } @@ -793,7 +787,7 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "\tFact: " << IDEProblem.DtoString(Fact)); PHASAR_LOG_LEVEL(DEBUG, "\tValue: " << IDEProblem.LtoString(Value)); if (!IDEProblem.isZeroValue(Fact)) { - INC_COUNTER("Gen facts", 1, PAMM_SEVERITY_LEVEL::Core); + INC_COUNTER("Gen facts", 1, Core); } WorkList.emplace_back(PathEdge(Fact, StartPoint, Fact), EdgeIdentity{}); @@ -811,7 +805,7 @@ class IDESolver /// virtual void processExit(const PathEdge Edge) { PAMM_GET_INSTANCE; - INC_COUNTER("Process Exit", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("Process Exit", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Process exit at target: " << IDEProblem.NtoString(Edge.getTarget())); n_t n = Edge.getTarget(); // an exit node; line 21... @@ -843,13 +837,12 @@ class IDESolver FlowFunctionPtrType RetFunction = CachedFlowEdgeFunctions.getRetFlowFunction( c, FunctionThatNeedsSummary, n, RetSiteC); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("FF Queries", 1, Full); // for each incoming-call value 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, - PAMM_SEVERITY_LEVEL::Full); + ADD_TO_HISTOGRAM("Data-flow facts", Targets.size(), 1, Full); saveEdges(n, RetSiteC, d2, Targets, true); // for each target value at the return site // line 23 @@ -872,7 +865,7 @@ class IDESolver IntermediateEdgeFunctions[std::make_tuple(n, d2, RetSiteC, d5)] .push_back(f5); } - INC_COUNTER("EF Queries", 2, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("EF Queries", 2, Full); // compose call function * function * return function PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5 << " * " << f << " * " << f4); @@ -914,11 +907,10 @@ class IDESolver FlowFunctionPtrType RetFunction = CachedFlowEdgeFunctions.getRetFlowFunction( Caller, FunctionThatNeedsSummary, n, RetSiteC); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + 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, - PAMM_SEVERITY_LEVEL::Full); + ADD_TO_HISTOGRAM("Data-flow facts", Targets.size(), 1, Full); saveEdges(n, RetSiteC, d2, Targets, true); for (d_t d5 : Targets) { EdgeFunction f5 = @@ -929,7 +921,7 @@ class IDESolver IntermediateEdgeFunctions[std::make_tuple(n, d2, RetSiteC, d5)] .push_back(f5); } - INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("EF Queries", 1, Full); PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5 << " * " << f); propagteUnbalancedReturnFlow(RetSiteC, d5, f.composeWith(f5), Caller); @@ -946,7 +938,7 @@ class IDESolver FlowFunctionPtrType RetFunction = CachedFlowEdgeFunctions.getRetFlowFunction( nullptr, FunctionThatNeedsSummary, n, nullptr); - INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("FF Queries", 1, Full); RetFunction->computeTargets(d2); } } @@ -1331,11 +1323,14 @@ class IDESolver // Special case if (ProcessSummaryFacts.find(std::make_pair(Edge.second, D2)) != ProcessSummaryFacts.end()) { - std::multiset SummaryDMultiSet = - EndsummaryTab.get(Edge.second, D2).columnKeySet(); - // remove duplicates from multiset - std::set SummaryDSet(SummaryDMultiSet.begin(), - SummaryDMultiSet.end()); + + std::set SummaryDSet; + EndsummaryTab.get(Edge.second, D2) + .foreachCell([&SummaryDSet](const auto &Row, const auto &Col, + const auto &Val) { + SummaryDSet.insert(Col); + }); + // Process summary just as an intra-procedural edge if (SummaryDSet.find(D2) != SummaryDSet.end()) { NumGenFacts += SummaryDSet.size() - 1; @@ -1384,13 +1379,10 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "#Reuse: " << Entry.second); TotalSummaryReuse += Entry.second; } - INC_COUNTER("Gen facts", NumGenFacts, PAMM_SEVERITY_LEVEL::Core); - INC_COUNTER("Kill facts", NumKillFacts, PAMM_SEVERITY_LEVEL::Core); - INC_COUNTER("Summary-reuse", TotalSummaryReuse, PAMM_SEVERITY_LEVEL::Core); - INC_COUNTER("Intra Path Edges", NumIntraPathEdges, - PAMM_SEVERITY_LEVEL::Core); - INC_COUNTER("Inter Path Edges", NumInterPathEdges, - PAMM_SEVERITY_LEVEL::Core); + INC_COUNTER("Gen facts", NumGenFacts, Core); + INC_COUNTER("Summary-reuse", TotalSummaryReuse, Core); + INC_COUNTER("Intra Path Edges", NumIntraPathEdges, Core); + INC_COUNTER("Inter Path Edges", NumInterPathEdges, Core); PHASAR_LOG_LEVEL(INFO, "----------------------------------------------"); PHASAR_LOG_LEVEL(INFO, "=== Solver Statistics ==="); @@ -1658,30 +1650,30 @@ class IDESolver bool doInitialize() { PAMM_GET_INSTANCE; - REG_COUNTER("Gen facts", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Kill facts", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Summary-reuse", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Intra Path Edges", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("Inter Path Edges", 0, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("FF Queries", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("EF Queries", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Value Propagation", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Value Computation", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("SpecialSummary-FF Application", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("SpecialSummary-EF Queries", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("JumpFn Construction", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Process Call", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Process Normal", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("Process Exit", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("[Calls] getAliasSet", 0, PAMM_SEVERITY_LEVEL::Full); - REG_HISTOGRAM("Data-flow facts", PAMM_SEVERITY_LEVEL::Full); - REG_HISTOGRAM("Points-to", PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("Gen facts", 0, Core); + REG_COUNTER("Kill facts", 0, Core); + REG_COUNTER("Summary-reuse", 0, Core); + REG_COUNTER("Intra Path Edges", 0, Core); + REG_COUNTER("Inter Path Edges", 0, Core); + REG_COUNTER("FF Queries", 0, Full); + REG_COUNTER("EF Queries", 0, Full); + REG_COUNTER("Value Propagation", 0, Full); + REG_COUNTER("Value Computation", 0, Full); + REG_COUNTER("SpecialSummary-FF Application", 0, Full); + REG_COUNTER("SpecialSummary-EF Queries", 0, Full); + REG_COUNTER("JumpFn Construction", 0, Full); + REG_COUNTER("Process Call", 0, Full); + REG_COUNTER("Process Normal", 0, Full); + REG_COUNTER("Process Exit", 0, Full); + REG_COUNTER("[Calls] getAliasSet", 0, Full); + REG_HISTOGRAM("Data-flow facts", Full); + REG_HISTOGRAM("Points-to", Full); PHASAR_LOG_LEVEL(INFO, "IDE solver is solving the specified problem"); PHASAR_LOG_LEVEL(INFO, "Submit initial seeds, construct exploded super graph"); // computations starting here - START_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); + START_TIMER("DFA Phase I", Full); // We start our analysis and construct exploded supergraph submitInitialSeeds(); @@ -1701,14 +1693,15 @@ class IDESolver } void finalizeInternal() { - STOP_TIMER("DFA Phase I", PAMM_SEVERITY_LEVEL::Full); + PAMM_GET_INSTANCE; + STOP_TIMER("DFA Phase I", Full); if (SolverConfig.computeValues()) { - START_TIMER("DFA Phase II", PAMM_SEVERITY_LEVEL::Full); + START_TIMER("DFA Phase II", Full); // Computing the final values for the edge functions PHASAR_LOG_LEVEL( INFO, "Compute the final values according to the edge functions"); computeValues(); - STOP_TIMER("DFA Phase II", PAMM_SEVERITY_LEVEL::Full); + STOP_TIMER("DFA Phase II", Full); } PHASAR_LOG_LEVEL(INFO, "Problem solved"); if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::Core) { diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index fb532a134..780f1ea6f 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -138,7 +138,7 @@ class SolverResultsBase { using f_t = typename ICFGTy::f_t; PAMM_GET_INSTANCE; - START_TIMER("DFA IDE Result Dumping", PAMM_SEVERITY_LEVEL::Full); + START_TIMER("DFA IDE Result Dumping", Full); OS << "\n***************************************************************\n" << "* Raw IDESolver results *\n" << "***************************************************************\n"; @@ -179,7 +179,7 @@ class SolverResultsBase { } } OS << '\n'; - STOP_TIMER("DFA IDE Result Dumping", PAMM_SEVERITY_LEVEL::Full); + STOP_TIMER("DFA IDE Result Dumping", Full); } template diff --git a/include/phasar/Utils/PAMM.h b/include/phasar/Utils/PAMM.h index 2f9265516..50f8f215c 100644 --- a/include/phasar/Utils/PAMM.h +++ b/include/phasar/Utils/PAMM.h @@ -17,12 +17,18 @@ #ifndef PHASAR_UTILS_PAMM_H_ #define PHASAR_UTILS_PAMM_H_ +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + #include // high_resolution_clock::time_point, milliseconds +#include #include -#include // set -#include // string -#include // unordered_map -#include // vector +#include // set +#include // string +#include // vector namespace llvm { class raw_ostream; @@ -50,24 +56,13 @@ namespace psr { /// @note This class implements the Singleton Pattern - use the /// PAMM_GET_INSTANCE macro to retrieve an instance of PAMM before you use any /// other macro from this class. -class PAMM { -private: - PAMM() = default; - ~PAMM() = default; +class PAMM final { +public: using TimePoint_t = std::chrono::high_resolution_clock::time_point; using Duration_t = std::chrono::milliseconds; - std::unordered_map RunningTimer; - std::unordered_map> - StoppedTimer; - std::unordered_map>> - RepeatingTimer; - std::unordered_map Counter; - std::unordered_map> - Histogram; -public: + PAMM() noexcept = default; + ~PAMM() = default; // PAMM is used as singleton. PAMM(const PAMM &PM) = delete; PAMM(PAMM &&PM) = delete; @@ -76,7 +71,7 @@ class PAMM { /// \brief Returns a reference to the PAMM object (singleton) - associated /// macro: PAMM_GET_INSTANCE. - static PAMM &getInstance(); + [[nodiscard]] static PAMM &getInstance(); /// \brief Resets PAMM, i.e. discards all gathered information (timer, counter /// etc.) - associated macro: RESET_PAMM. @@ -86,12 +81,12 @@ class PAMM { /// \brief Starts a timer under the given timer id - associated macro: /// START_TIMER(TIMER_ID, SEV_LVL). /// \param TimerId Unique timer id. - void startTimer(const std::string &TimerId); + void startTimer(llvm::StringRef TimerId); /// \brief Resets timer under the given timer id - associated macro: /// RESET_TIMER(TIMER_ID, SEV_LVL). /// \param TimerId Unique timer id. - void resetTimer(const std::string &TimerId); + void resetTimer(llvm::StringRef TimerId); /// If pauseTimer is true, a running timer gets paused, its start time point /// will paired with a current time point, and stored as an accumulated timer. @@ -107,18 +102,18 @@ class PAMM { /// \brief Stops or pauses a timer under the given timer id. /// \param TimerId Unique timer id. /// \param PauseTimer If true, timer will be paused instead of stopped. - void stopTimer(const std::string &TimerId, bool PauseTimer = false); + void stopTimer(llvm::StringRef TimerId, bool PauseTimer = false); /// \brief Computes the elapsed time of the given timer up until now or up to /// the moment the timer was stopped - associated macro: GET_TIMER(TIMERID) /// \param TimerId Unique timer id. /// \return Timer duration. - unsigned long elapsedTime(const std::string &TimerId); + uint64_t elapsedTime(llvm::StringRef TimerId); /// For each accumulated timer a vector holds all recorded durations. /// \brief Computes the elapsed time for all accumulated timer being used. /// \return Map containing measured durations of all accumulated timer. - std::unordered_map> + [[nodiscard]] llvm::StringMap> elapsedTimeOfRepeatingTimer(); /// A running timer will not be stopped. The precision for time computation @@ -129,42 +124,46 @@ class PAMM { /// explicitly. /// \brief Returns the elapsed time for a given timer id. /// \param timerId Unique timer id. - static std::string getPrintableDuration(unsigned long Duration); + [[nodiscard]] static std::string getPrintableDuration(uint64_t Duration); /// \brief Registers a new counter under the given counter id - associated /// macro: REG_COUNTER(COUNTER_ID, INIT_VALUE, SEV_LVL). /// \param CounterId Unique counter id. - void regCounter(const std::string &CounterId, unsigned IntialValue = 0); + void regCounter(llvm::StringRef CounterId, unsigned IntialValue = 0); /// \brief Increases the count for the given counter - associated macro: /// INC_COUNTER(COUNTER_ID, VALUE, SEV_LVL). /// \param CounterId Unique counter id. /// \param CValue to be added to the current counter. - void incCounter(const std::string &CounterId, unsigned CValue = 1); + void incCounter(llvm::StringRef CounterId, unsigned CValue = 1); /// \brief Decreases the count for the given counter - associated macro: /// DEC_COUNTER(COUNTER_ID, VALUE, SEV_LVL). /// \param CounterId Unique counter id. /// \param CValue to be subtracted from the current counter. - void decCounter(const std::string &CounterId, unsigned CValue = 1); + void decCounter(llvm::StringRef CounterId, unsigned CValue = 1); /// The associated macro does not check PAMM's severity level explicitly. /// \brief Returns the current count for the given counter - associated macro: /// GET_COUNTER(COUNTER_ID). /// \param CounterId Unique counter id. - int getCounter(const std::string &CounterId); + std::optional getCounter(llvm::StringRef CounterId); /// The associated macro does not check PAMM's severity level explicitly. /// \brief Sums the counts for the given counter ids - associated macro: /// GET_SUM_COUNT(...). /// \param CounterIds Unique counter ids. /// \note Macro uses variadic parameters, e.g. GET_SUM_COUNT({"foo", "bar"}). - int getSumCount(const std::set &CounterIds); + std::optional getSumCount(const std::set &CounterIds); + std::optional + getSumCount(llvm::ArrayRef CounterIds); + std::optional + getSumCount(std::initializer_list CounterIds); /// \brief Registers a new histogram - associated macro: /// REG_HISTOGRAM(HISTOGRAM_ID, SEV_LVL). /// \param HistogramId Unique hitogram id. - void regHistogram(const std::string &HistogramId); + void regHistogram(llvm::StringRef HistogramId); /// \brief Adds a new observed data point to the corresponding histogram - /// associated macro: ADD_TO_HISTOGRAM(HISTOGRAM_ID, DATAPOINT_ID, @@ -172,9 +171,10 @@ class PAMM { /// \param HistogramId ID of the histogram that tracks given data points. /// \param DataPointId ID of the given data point. /// \param DataPointValue Value of the given data point. - void addToHistogram(const std::string &HistogramId, - const std::string &DataPointId, - unsigned long DataPointValue = 1); + void addToHistogram(llvm::StringRef HistogramId, llvm::StringRef DataPointId, + uint64_t DataPointValue = 1); + + void stopAllTimers(); void printTimers(llvm::raw_ostream &OS); @@ -190,11 +190,20 @@ class PAMM { /// EXPORT_MEASURED_DATA(PATH). /// \param OutputPath to exported JSON file. void exportMeasuredData( - const std::string &OutputPath, - const std::string &ProjectId = "default-phasar-project", - const std::optional> &Modules = std::nullopt, - const std::optional> &DataFlowAnalyses = - std::nullopt); + const llvm::Twine &OutputPath, + llvm::StringRef ProjectId = "default-phasar-project", + const std::vector *Modules = nullptr, + const std::vector *DataFlowAnalyses = nullptr); + + [[nodiscard]] const auto &getHistogram() const noexcept { return Histogram; } + +private: + llvm::StringMap RunningTimer; + llvm::StringMap> StoppedTimer; + llvm::StringMap>> + RepeatingTimer; + llvm::StringMap Counter; + llvm::StringMap> Histogram; }; } // namespace psr diff --git a/include/phasar/Utils/PAMMMacros.h b/include/phasar/Utils/PAMMMacros.h index adf4356c1..f41ef4a0e 100644 --- a/include/phasar/Utils/PAMMMacros.h +++ b/include/phasar/Utils/PAMMMacros.h @@ -19,14 +19,20 @@ namespace psr { /// Defines the different level of severity of PAMM's performance evaluation -enum PAMM_SEVERITY_LEVEL { Off = 0, Core, Full }; // NOLINT +enum class PAMM_SEVERITY_LEVEL { Off = 0, Core, Full }; // NOLINT #if defined(PAMM_FULL) -static constexpr unsigned PAMM_CURR_SEV_LEVEL = 2; // NOLINT +// NOLINTNEXTLINE +static constexpr PAMM_SEVERITY_LEVEL PAMM_CURR_SEV_LEVEL = + PAMM_SEVERITY_LEVEL::Full; #elif defined(PAMM_CORE) -static constexpr unsigned PAMM_CURR_SEV_LEVEL = 1; // NOLINT +// NOLINTNEXTLINE +static constexpr PAMM_SEVERITY_LEVEL PAMM_CURR_SEV_LEVEL = + PAMM_SEVERITY_LEVEL::Core; #else -static constexpr unsigned PAMM_CURR_SEV_LEVEL = 0; // NOLINT +// NOLINTNEXTLINE +static constexpr PAMM_SEVERITY_LEVEL PAMM_CURR_SEV_LEVEL = + PAMM_SEVERITY_LEVEL::Off; #endif } // namespace psr @@ -39,46 +45,46 @@ static constexpr unsigned PAMM_CURR_SEV_LEVEL = 0; // NOLINT #define PAMM_RESET pamm.reset() #define START_TIMER(TIMER_ID, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.startTimer(TIMER_ID); \ } #define RESET_TIMER(TIMER_ID, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.resetTimer(TIMER_ID); \ } #define PAUSE_TIMER(TIMER_ID, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.stopTimer(TIMER_ID, true); \ } #define STOP_TIMER(TIMER_ID, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.stopTimer(TIMER_ID); \ } #define PRINT_TIMER(TIMER_ID) \ pamm.getPrintableDuration(pamm.elapsedTime(TIMER_ID)) #define REG_COUNTER(COUNTER_ID, INIT_VALUE, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.regCounter(COUNTER_ID, INIT_VALUE); \ } #define INC_COUNTER(COUNTER_ID, VALUE, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.incCounter(COUNTER_ID, VALUE); \ } #define DEC_COUNTER(COUNTER_ID, VALUE, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.decCounter(COUNTER_ID, VALUE); \ } #define GET_COUNTER(COUNTER_ID) pamm.getCounter(COUNTER_ID) #define GET_SUM_COUNT(...) pamm.getSumCount(__VA_ARGS__) #define REG_HISTOGRAM(HISTOGRAM_ID, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ pamm.regHistogram(HISTOGRAM_ID); \ } #define ADD_TO_HISTOGRAM(HISTOGRAM_ID, DATAPOINT_ID, DATAPOINT_VALUE, SEV_LVL) \ - if constexpr (PAMM_CURR_SEV_LEVEL >= SEV_LVL) { \ - pamm.addToHistogram(HISTOGRAM_ID, std::to_string(DATAPOINT_ID), \ + if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::SEV_LVL) { \ + pamm.addToHistogram(HISTOGRAM_ID, adl_to_string(DATAPOINT_ID), \ DATAPOINT_VALUE); \ } @@ -101,9 +107,10 @@ static constexpr unsigned PAMM_CURR_SEV_LEVEL = 0; // NOLINT #define EXPORT_MEASURED_DATA(PATH) // The following macros could be used in log messages, thus they have to // provide some default value to avoid compiler errors -#define PRINT_TIMER(TIMER_ID) "-1" -#define GET_COUNTER(COUNTER_ID) "-1" -#define GET_SUM_COUNT(...) "-1" +#define PRINT_TIMER(TIMER_ID) "" +#define GET_COUNTER(COUNTER_ID) "" +#define GET_SUM_COUNT(...) "" + #endif #endif diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 0957292bb..3f1d8d302 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -66,6 +66,19 @@ template struct has_str().str())> : std::true_type { }; // NOLINT +template struct has_adl_to_string { + template ())))> + static std::true_type test(int); + template ()))> + static std::true_type test(long); + template static std::false_type test(...); + + static constexpr bool value = + std::is_same_v; +}; + template struct has_erase_iterator : std::false_type {}; // NOLINT template @@ -155,6 +168,9 @@ constexpr bool is_printable_v = detail::is_printable::value; // NOLINT template constexpr bool has_str_v = detail::has_str::value; // NOLINT +template +constexpr bool has_adl_to_string_v = detail::has_adl_to_string::value; + template constexpr bool has_erase_iterator_v = // NOLINT detail::has_erase_iterator::value; @@ -233,6 +249,12 @@ template struct DefaultConstruct { } }; +template >> +[[nodiscard]] decltype(auto) adl_to_string(const T &Val) { + using std::to_string; + return to_string(Val); +} + // NOLINTEND(readability-identifier-naming) } // namespace psr diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 512345a2e..12154af21 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -15,6 +15,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -253,6 +254,18 @@ auto remove_by_index(Container &Cont, const Indices &Idx) { return remove_by_index(begin(Cont), end(Cont), begin(Idx), end(Idx)); } +template >> +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const std::optional &Opt) { + if (Opt) { + OS << *Opt; + } else { + OS << ""; + } + + return OS; +} + } // namespace psr #endif diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index 591e4e746..42d715c27 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -144,9 +144,12 @@ auto LLVMBasedICFG::Builder::buildCallGraph(Soundness /*S*/) << llvmIRToString(IndirectCall)); } } - REG_COUNTER("CG Vertices", boost::num_vertices(ret), - PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("CG Edges", boost::num_edges(ret), PAMM_SEVERITY_LEVEL::Full); + + PAMM_GET_INSTANCE; + REG_COUNTER("CG Functions", CGBuilder.viewCallGraph().getNumVertexFunctions(), + Full); + REG_COUNTER("CG CallSites", CGBuilder.viewCallGraph().getNumVertexCallSites(), + Full); PHASAR_LOG_LEVEL_CAT(INFO, "LLVMBasedICFG", "Call graph has been constructed"); return CGBuilder.consumeCallGraph(); diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp index 0213a77ad..7a9d83212 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp @@ -40,9 +40,8 @@ IFDSConstAnalysis::IFDSConstAnalysis(const LLVMProjectIRDB *IRDB, PT(PT) { assert(PT); PAMM_GET_INSTANCE; - REG_HISTOGRAM("Context-relevant Pointer", PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("[Calls] getContextRelevantAliasSet", 0, - PAMM_SEVERITY_LEVEL::Full); + REG_HISTOGRAM("Context-relevant Pointer", Full); + REG_COUNTER("[Calls] getContextRelevantAliasSet", 0, Full); } IFDSConstAnalysis::FlowFunctionPtrType @@ -207,10 +206,8 @@ std::set IFDSConstAnalysis::getContextRelevantAliasSet( std::set &AliasSet, IFDSConstAnalysis::f_t CurrentContext) { PAMM_GET_INSTANCE; - INC_COUNTER("[Calls] getContextRelevantAliasSet", 1, - PAMM_SEVERITY_LEVEL::Full); - START_TIMER("Context-Relevant-Alias-Set Computation", - PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("[Calls] getContextRelevantAliasSet", 1, Full); + START_TIMER("Context-Relevant-Alias-Set Computation", Full); std::set ToGenerate; for (const auto *Alias : AliasSet) { PHASAR_LOG_LEVEL(DEBUG, "Alias: " << llvmIRToString(Alias)); @@ -238,10 +235,8 @@ std::set IFDSConstAnalysis::getContextRelevantAliasSet( } } // ignore everything else } - PAUSE_TIMER("Context-Relevant-Alias-Set Computation", - PAMM_SEVERITY_LEVEL::Full); - ADD_TO_HISTOGRAM("Context-relevant Pointer", ToGenerate.size(), 1, - PAMM_SEVERITY_LEVEL::Full); + PAUSE_TIMER("Context-Relevant-Alias-Set Computation", Full); + ADD_TO_HISTOGRAM("Context-relevant Pointer", ToGenerate.size(), 1, Full); return ToGenerate; } diff --git a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp index 974ab2ba4..0b46a0c6f 100644 --- a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp +++ b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp @@ -139,23 +139,15 @@ GeneralStatistics GeneralStatisticsAnalysis::runOnModule(llvm::Module &M) { // the counter with the values of the counter varibles, i.e. PAMM simply // holds the results. PAMM_GET_INSTANCE; - REG_COUNTER("GS Instructions", Stats.instructions, PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("GS Allocated Types", Stats.allocatedTypes.size(), - PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Allocation-Sites", Stats.allocationsites, - PAMM_SEVERITY_LEVEL::Core); - REG_COUNTER("GS Basic Blocks", Stats.basicblocks, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Call-Sites", Stats.callsites, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Functions", Stats.functions, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Globals", Stats.globals, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Global Pointer", Stats.globalPointers, - PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Memory Intrinsics", Stats.memIntrinsic, - PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Store Instructions", Stats.storeInstructions, - PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("GS Load Instructions", Stats.loadInstructions, - PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("GS Instructions", Stats.Instructions, Core); + REG_COUNTER("GS Allocated Types", Stats.AllocatedTypes.size(), Full); + REG_COUNTER("GS Basic Blocks", Stats.BasicBlocks, Full); + REG_COUNTER("GS Call-Sites", Stats.CallSites, Full); + REG_COUNTER("GS Functions", Stats.Functions, Full); + REG_COUNTER("GS Globals", Stats.Globals, Full); + REG_COUNTER("GS Memory Intrinsics", Stats.MemIntrinsics, Full); + REG_COUNTER("GS Store Instructions", Stats.StoreInstructions, Full); + REG_COUNTER("GS Load Instructions", Stats.LoadInstructions, Full); // Using the logging guard explicitly since we are printing allocated types // manually IF_LOG_ENABLED( diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp index 7eb255bce..5d217fb44 100644 --- a/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp @@ -205,7 +205,7 @@ void LLVMAliasGraph::computeAliasGraph(llvm::Function *F) { } } - INC_COUNTER("GS Pointer", Pointers.size(), PAMM_SEVERITY_LEVEL::Core); + INC_COUNTER("GS Pointer", Pointers.size(), Core); // make vertices for all pointers for (auto *P : Pointers) { @@ -363,8 +363,8 @@ auto LLVMAliasGraph::getAliasSet(const llvm::Value *V, const llvm::Instruction * /*I*/) -> AliasSetPtrTy { PAMM_GET_INSTANCE; - INC_COUNTER("[Calls] getAliasSet", 1, PAMM_SEVERITY_LEVEL::Full); - START_TIMER("Alias-Set Computation", PAMM_SEVERITY_LEVEL::Full); + INC_COUNTER("[Calls] getAliasSet", 1, Full); + START_TIMER("Alias-Set Computation", Full); const auto *VF = retrieveFunction(V); computeAliasGraph(VF); // check if the graph contains a corresponding vertex @@ -388,9 +388,8 @@ auto LLVMAliasGraph::getAliasSet(const llvm::Value *V, for (auto Vertex : ReachableVertices) { ResultSet->insert(PAG[Vertex].V); } - PAUSE_TIMER("Alias-Set Computation", PAMM_SEVERITY_LEVEL::Full); - ADD_TO_HISTOGRAM("Points-to", ResultSet->size(), 1, - PAMM_SEVERITY_LEVEL::Full); + PAUSE_TIMER("Alias-Set Computation", Full); + ADD_TO_HISTOGRAM("Points-to", ResultSet->size(), 1, Full); return ResultSet; } diff --git a/lib/Utils/PAMM.cpp b/lib/Utils/PAMM.cpp index 7da9b7f5f..b1ea931ac 100644 --- a/lib/Utils/PAMM.cpp +++ b/lib/Utils/PAMM.cpp @@ -16,15 +16,26 @@ #include "phasar/Utils/PAMM.h" +#include "phasar/Utils/ChronoUtils.h" +#include "phasar/Utils/NlohmannLogging.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "nlohmann/json.hpp" #include +#include #include #include #include +#include #include +#include using namespace psr; using json = nlohmann::json; @@ -36,38 +47,43 @@ PAMM &PAMM::getInstance() { return Instance; } -void PAMM::startTimer(const std::string &TimerId) { - bool ValidTimerId = - !RunningTimer.count(TimerId) && !StoppedTimer.count(TimerId); - assert(ValidTimerId && "startTimer failed due to an invalid timer id"); - if (ValidTimerId) { - PAMM::TimePoint_t Start = std::chrono::high_resolution_clock::now(); - RunningTimer[TimerId] = Start; +void PAMM::startTimer(llvm::StringRef TimerId) { + if (LLVM_UNLIKELY(StoppedTimer.count(TimerId))) { + llvm::report_fatal_error("Do not start an already stopped timer"); } + + auto [It, Inserted] = RunningTimer.try_emplace(TimerId); + if (LLVM_UNLIKELY(!Inserted)) { + llvm::report_fatal_error("Do not start an already running timer"); + } + + PAMM::TimePoint_t Start = std::chrono::high_resolution_clock::now(); + It->second = Start; } -void PAMM::resetTimer(const std::string &TimerId) { - assert((RunningTimer.count(TimerId) && !StoppedTimer.count(TimerId)) || - (!RunningTimer.count(TimerId) && StoppedTimer.count(TimerId)) && +void PAMM::resetTimer(llvm::StringRef TimerId) { + bool InRunningTimers = RunningTimer.erase(TimerId); + bool InStoppedTimers = StoppedTimer.erase(TimerId); + + assert((InRunningTimers && !InStoppedTimers) || + (!InRunningTimers && InStoppedTimers) && "resetTimer failed due to an invalid timer id"); - if (RunningTimer.count(TimerId)) { - RunningTimer.erase(RunningTimer.find(TimerId)); - } else if (StoppedTimer.count(TimerId)) { - StoppedTimer.erase(StoppedTimer.find(TimerId)); - } } -void PAMM::stopTimer(const std::string &TimerId, bool PauseTimer) { - bool TimerRunning = RunningTimer.count(TimerId); - bool ValidTimerId = TimerRunning || StoppedTimer.count(TimerId); +void PAMM::stopTimer(llvm::StringRef TimerId, bool PauseTimer) { + auto RunningIt = RunningTimer.find(TimerId); + auto StoppedIt = StoppedTimer.find(TimerId); + bool TimerRunning = RunningIt != RunningTimer.end(); + bool TimerStopped = StoppedIt != StoppedTimer.end(); + bool ValidTimerId = TimerRunning || TimerStopped; assert(ValidTimerId && "stopTimer failed due to an invalid timer id or timer " "was already stopped"); assert(TimerRunning && "stopTimer failed because timer was already stopped"); - if (ValidTimerId) { - auto Timer = RunningTimer.find(TimerId); + + if (LLVM_LIKELY(ValidTimerId)) { PAMM::TimePoint_t End = std::chrono::high_resolution_clock::now(); - PAMM::TimePoint_t Start = Timer->second; - RunningTimer.erase(Timer); + PAMM::TimePoint_t Start = RunningIt->second; + RunningTimer.erase(RunningIt); auto P = make_pair(Start, End); if (PauseTimer) { RepeatingTimer[TimerId].push_back(P); @@ -77,191 +93,220 @@ void PAMM::stopTimer(const std::string &TimerId, bool PauseTimer) { } } -unsigned long PAMM::elapsedTime(const std::string &TimerId) { - assert((RunningTimer.count(TimerId) || StoppedTimer.count(TimerId)) && - "elapsedTime failed due to an invalid timer id"); - if (RunningTimer.count(TimerId)) { +uint64_t PAMM::elapsedTime(llvm::StringRef TimerId) { + auto RunningIt = RunningTimer.find(TimerId); + + if (RunningIt != RunningTimer.end()) { PAMM::TimePoint_t End = std::chrono::high_resolution_clock::now(); - PAMM::TimePoint_t Start = RunningTimer[TimerId]; + PAMM::TimePoint_t Start = RunningIt->second; auto Duration = std::chrono::duration_cast(End - Start); return Duration.count(); } - if (StoppedTimer.count(TimerId)) { - auto Duration = std::chrono::duration_cast( - StoppedTimer[TimerId].second - StoppedTimer[TimerId].first); + if (auto StoppedIt = StoppedTimer.find(TimerId); + StoppedIt != StoppedTimer.end()) { + auto [Start, End] = StoppedIt->second; + auto Duration = std::chrono::duration_cast(End - Start); return Duration.count(); } + + assert(false && "elapsedTime failed due to an invalid timer id"); return 0; } -std::unordered_map> -PAMM::elapsedTimeOfRepeatingTimer() { - std::unordered_map> AccTimes; +template +static void foreachElapsedTimeOfRepeatingTimer( + llvm::StringMap< + std::vector>> + &RepeatingTimer, + HandlerFn Handler) { for (const auto &Timer : RepeatingTimer) { - std::vector AccTimeVec; - for (auto Timepair : Timer.second) { - auto Duration = std::chrono::duration_cast( - Timepair.second - Timepair.first); - AccTimeVec.push_back(Duration.count()); - } - AccTimes[Timer.first] = AccTimeVec; + std::invoke( + Handler, Timer.first(), [&Timer](std::vector &AccTimeVec) { + AccTimeVec.reserve(Timer.second.size()); + + for (auto [Start, End] : Timer.second) { + auto Duration = + std::chrono::duration_cast(End - Start); + AccTimeVec.push_back(Duration.count()); + } + }); } +} + +llvm::StringMap> PAMM::elapsedTimeOfRepeatingTimer() { + llvm::StringMap> AccTimes; + + foreachElapsedTimeOfRepeatingTimer( + RepeatingTimer, [&AccTimes](llvm::StringRef Id, auto Handler) { + std::invoke(std::move(Handler), AccTimes[Id]); + }); + return AccTimes; } -std::string PAMM::getPrintableDuration(unsigned long Duration) { - unsigned long Milliseconds = Duration % 1000; - unsigned long Seconds = ((Duration - Milliseconds) / 1000) % 60; - unsigned long Minutes = - ((((Duration - Milliseconds) / 1000) - Seconds) / 60) % 60; - unsigned long Hours = - (((((Duration - Milliseconds) / 1000) - Seconds) / 60) - Minutes) / 60; - std::ostringstream Oss; - if (Hours) { - Oss << Hours << "h "; - } - if (Minutes) { - Oss << Minutes << "m "; - } - if (Seconds) { - Oss << Seconds << "sec "; - } - if (Milliseconds) { - Oss << Milliseconds << "ms"; - } else { - Oss << "0 ms"; - } - return Oss.str(); +std::string PAMM::getPrintableDuration(uint64_t Duration) { + return hms(std::chrono::milliseconds{Duration}).str(); } -void PAMM::regCounter(const std::string &CounterId, unsigned IntialValue) { - bool ValidCounterId = !Counter.count(CounterId); - assert(ValidCounterId && "regCounter failed due to an invalid counter id"); - if (ValidCounterId) { - Counter[CounterId] = IntialValue; - } +void PAMM::regCounter(llvm::StringRef CounterId, unsigned IntialValue) { + auto [It, Inserted] = Counter.try_emplace(CounterId, IntialValue); + assert(Inserted && "regCounter failed due to an invalid counter id"); } -void PAMM::incCounter(const std::string &CounterId, unsigned CValue) { - bool ValidCounterId = Counter.count(CounterId); +void PAMM::incCounter(llvm::StringRef CounterId, unsigned CValue) { + auto It = Counter.find(CounterId); + bool ValidCounterId = It != Counter.end(); assert(ValidCounterId && "incCounter failed due to an invalid counter id"); if (ValidCounterId) { - Counter[CounterId] += CValue; + It->second += CValue; } } -void PAMM::decCounter(const std::string &CounterId, unsigned CValue) { - bool ValidCounterId = Counter.count(CounterId); +void PAMM::decCounter(llvm::StringRef CounterId, unsigned CValue) { + auto It = Counter.find(CounterId); + bool ValidCounterId = It != Counter.end(); assert(ValidCounterId && "decCounter failed due to an invalid counter id"); if (ValidCounterId) { - Counter[CounterId] -= CValue; + It->second -= CValue; } } -int PAMM::getCounter(const std::string &CounterId) { - bool ValidCounterId = Counter.count(CounterId); +std::optional PAMM::getCounter(llvm::StringRef CounterId) { + auto It = Counter.find(CounterId); + bool ValidCounterId = It != Counter.end(); assert(ValidCounterId && "getCounter failed due to an invalid counter id"); if (ValidCounterId) { - return Counter[CounterId]; + return It->second; } - return -1; + return std::nullopt; } -int PAMM::getSumCount(const std::set &CounterIds) { - int Sum = 0; - for (const std::string &Id : CounterIds) { - int Count = getCounter(Id); - assert(Count != -1 && "getSumCount failed due to an invalid counter id"); - if (Count != -1) { - Sum += Count; - } else { - return -1; +template +static std::optional +getSumCountInternal(PAMM &P, ForwardIterator It, + ForwardIteratorSentinel End) noexcept { + uint64_t Ctr = 0; + for (; It != End; ++It) { + auto Count = P.getCounter(*It); + if (!Count) { + return std::nullopt; } + + Ctr += *Count; } - return Sum; + + return Ctr; } -void PAMM::regHistogram(const std::string &HistogramId) { - bool ValidHid = !Histogram.count(HistogramId); - assert(ValidHid && "failed to register new histogram due to an invalid id"); - if (ValidHid) { - std::unordered_map H; - Histogram[HistogramId] = H; - } +std::optional +PAMM::getSumCount(const std::set &CounterIds) { + return getSumCountInternal(*this, CounterIds.begin(), CounterIds.end()); } -void PAMM::addToHistogram(const std::string &HistogramId, - const std::string &DataPointId, - unsigned long DataPointValue) { - assert(Histogram.count(HistogramId) && - "adding data point to histogram failed due to invalid id"); - if (Histogram[HistogramId].count(DataPointId)) { - Histogram[HistogramId][DataPointId] += DataPointValue; - } else { - Histogram[HistogramId][DataPointId] = DataPointValue; +std::optional +PAMM::getSumCount(llvm::ArrayRef CounterIds) { + return getSumCountInternal(*this, CounterIds.begin(), CounterIds.end()); +} + +std::optional +PAMM::getSumCount(std::initializer_list CounterIds) { + return getSumCountInternal(*this, CounterIds.begin(), CounterIds.end()); +} + +void PAMM::regHistogram(llvm::StringRef HistogramId) { + auto [It, Inserted] = Histogram.try_emplace(HistogramId); + assert(Inserted && "failed to register new histogram due to an invalid id"); +} + +void PAMM::addToHistogram(llvm::StringRef HistogramId, + llvm::StringRef DataPointId, + uint64_t DataPointValue) { + auto HistIt = Histogram.find(HistogramId); + if (HistIt == Histogram.end()) { + assert(false && "adding data point to histogram failed due to invalid id"); + return; + } + + auto [DataIt, Inserted] = + HistIt->second.try_emplace(DataPointId, DataPointValue); + if (!Inserted) { + DataIt->second += DataPointValue; } } -void PAMM::printTimers(llvm::raw_ostream &Os) { - // stop all running timer +void PAMM::stopAllTimers() { while (!RunningTimer.empty()) { - stopTimer(RunningTimer.begin()->first); + // safe copy + auto Id = RunningTimer.begin()->first().str(); + stopTimer(Id); } - Os << "Single Timer\n"; - Os << "------------\n"; +} + +void PAMM::printTimers(llvm::raw_ostream &OS) { + // stop all running timer + stopAllTimers(); + + OS << "Single Timer\n"; + OS << "------------\n"; for (const auto &Timer : StoppedTimer) { - unsigned long Time = elapsedTime(Timer.first); - Os << Timer.first << " : " << getPrintableDuration(Time) << '\n'; + uint64_t Time = elapsedTime(Timer.first()); + OS << Timer.first() << " : " << getPrintableDuration(Time) << '\n'; } if (StoppedTimer.empty()) { - Os << "No single Timer started!\n\n"; + OS << "No single Timer started!\n\n"; } else { - Os << "\n"; - } - Os << "Repeating Timer\n"; - Os << "---------------\n"; - for (const auto &Timer : elapsedTimeOfRepeatingTimer()) { - unsigned long Sum = 0; - Os << Timer.first << " Timer:\n"; - for (auto Duration : Timer.second) { - Sum += Duration; - Os << Duration << '\n'; - } - Os << "===\n" << Sum << "\n\n"; + OS << "\n"; } + OS << "Repeating Timer\n"; + OS << "---------------\n"; + + foreachElapsedTimeOfRepeatingTimer(RepeatingTimer, + [&OS](llvm::StringRef Id, auto Handler) { + OS << Id << " Timer:\n"; + std::vector Times; + std::invoke(std::move(Handler), Times); + + uint64_t Sum = 0; + for (auto Duration : Times) { + Sum += Duration; + OS << Duration << '\n'; + } + OS << "===\n" << Sum << "\n\n"; + }); + if (RepeatingTimer.empty()) { - Os << "No repeating Timer found!\n"; + OS << "No repeating Timer found!\n"; } else { - Os << '\n'; + OS << '\n'; } } -void PAMM::printCounters(llvm::raw_ostream &Os) { - Os << "\nCounter\n"; - Os << "-------\n"; +void PAMM::printCounters(llvm::raw_ostream &OS) { + OS << "\nCounter\n"; + OS << "-------\n"; for (const auto &Counter : Counter) { - Os << Counter.first << " : " << Counter.second << '\n'; + OS << Counter.first() << " : " << Counter.second << '\n'; } if (Counter.empty()) { - Os << "No Counter registered!\n"; + OS << "No Counter registered!\n"; } else { - Os << "\n"; + OS << "\n"; } } -void PAMM::printHistograms(llvm::raw_ostream &Os) { - Os << "\nHistograms\n"; - Os << "--------------\n"; +void PAMM::printHistograms(llvm::raw_ostream &OS) { + OS << "\nHistograms\n"; + OS << "--------------\n"; for (const auto &H : Histogram) { - Os << H.first << " Histogram\n"; - Os << "Value : #Occurrences\n"; + OS << H.first() << " Histogram\n"; + OS << "Value : #Occurrences\n"; for (const auto &Entry : H.second) { - Os << Entry.first << " : " << Entry.second << '\n'; + OS << Entry.first() << " : " << Entry.second << '\n'; } - Os << '\n'; + OS << '\n'; } if (Histogram.empty()) { - Os << "No histograms tracked!\n"; + OS << "No histograms tracked!\n"; } } @@ -274,72 +319,83 @@ void PAMM::printMeasuredData(llvm::raw_ostream &Os) { } void PAMM::exportMeasuredData( - const std::string &OutputPath, const std::string &ProjectId, - const std::optional> &Modules, - const std::optional> &DataFlowAnalyses) { + const llvm::Twine &OutputPath, llvm::StringRef ProjectId, + const std::vector *Modules, + const std::vector *DataFlowAnalyses) { // json file for holding all data json JsonData; - // add timer data - while (!RunningTimer.empty()) { - stopTimer(std::string(RunningTimer.begin()->first)); - } - json JTimer; - for (const auto &Timer : StoppedTimer) { - unsigned long Time = elapsedTime(Timer.first); - JTimer[Timer.first] = Time; - } - for (const auto &Timer : elapsedTimeOfRepeatingTimer()) { - JTimer[Timer.first] = Timer.second; - } - JsonData["Timer"] = JTimer; + stopAllTimers(); + { + // add timer data + json JTimer; + for (const auto &Timer : StoppedTimer) { + uint64_t Time = elapsedTime(Timer.first()); + JTimer[Timer.first().str()] = Time; + } - // add histogram data if available - json JHistogram; - for (const auto &H : Histogram) { - json JSetH; - for (const auto &Entry : H.second) { - JSetH[Entry.first] = Entry.second; + foreachElapsedTimeOfRepeatingTimer( + RepeatingTimer, [&JTimer](llvm::StringRef Id, auto Handler) { + std::vector Times; + std::invoke(std::move(Handler), Times); + JTimer[Id.str()] = std::move(Times); + }); + + JsonData["Timer"] = std::move(JTimer); + } + + { + // add histogram data if available + json JHistogram; + for (const auto &H : Histogram) { + json JSetH; + for (const auto &Entry : H.second) { + JSetH[Entry.first()] = Entry.second; + } + JHistogram[H.first()] = std::move(JSetH); + } + if (!JHistogram.is_null()) { + JsonData["Histogram"] = std::move(JHistogram); } - JHistogram[H.first] = JSetH; } - if (!JHistogram.is_null()) { - JsonData["Histogram"] = JHistogram; + { + // add counter data + json JCounter; + for (const auto &Counter : Counter) { + JCounter[Counter.first()] = Counter.second; + } + JsonData["Counter"] = std::move(JCounter); } - // add counter data - json JCounter; - for (const auto &Counter : Counter) { - JCounter[Counter.first] = Counter.second; + { + // add analysis/project/source file information if available + json JInfo; + JInfo["Project-ID"] = ProjectId; + + if (Modules) { + JInfo["Module(s)"] = *Modules; + } + if (DataFlowAnalyses) { + JInfo["Data-flow analysis"] = *DataFlowAnalyses; + } + if (!JInfo.is_null()) { + JsonData["Info"] = std::move(JInfo); + } } - JsonData["Counter"] = JCounter; - // add analysis/project/source file information if available - json JInfo; + llvm::SmallString<128> Buf; + OutputPath.toStringRef(Buf); + if (!Buf.endswith(".json")) { + Buf.append(".json"); + } - JInfo["Project-ID"] = ProjectId; + std::error_code EC; + llvm::raw_fd_ostream OS(Buf, EC); - if (Modules) { - JInfo["Module(s)"] = *Modules; - } - if (DataFlowAnalyses) { - JInfo["Data-flow analysis"] = *DataFlowAnalyses; - } - if (!JInfo.is_null()) { - JsonData["Info"] = JInfo; + if (EC) { + throw std::system_error(EC); } - std::string Cfp(OutputPath); - if (Cfp.find(".json") == std::string::npos) { - Cfp += ".json"; - } - std::ofstream File(Cfp); - if (File.is_open()) { - File << std::setw(2) // sets the indentation - << JsonData << std::endl; - File.close(); - } else { - throw std::ios_base::failure("could not write file: " + Cfp); - } + OS << JsonData << '\n'; } void PAMM::reset() { diff --git a/unittests/Utils/PAMMTest.cpp b/unittests/Utils/PAMMTest.cpp index bec561d75..71aa2982e 100644 --- a/unittests/Utils/PAMMTest.cpp +++ b/unittests/Utils/PAMMTest.cpp @@ -2,6 +2,7 @@ #include "phasar/Config/Configuration.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" @@ -29,9 +30,11 @@ class PAMMTest : public ::testing::Test { TEST_F(PAMMTest, HandleTimer) { // PAMM &pamm = PAMM::getInstance(); PAMM::getInstance().startTimer("timer1"); - std::this_thread::sleep_for(std::chrono::milliseconds(1200)); + std::this_thread::sleep_for(std::chrono::milliseconds(120)); PAMM::getInstance().stopTimer("timer1"); - EXPECT_GE(PAMM::getInstance().elapsedTime("timer1"), 1200U); + auto Elapsed = PAMM::getInstance().elapsedTime("timer1"); + EXPECT_GE(Elapsed, 120U) << "Bad time measurement"; + EXPECT_LT(Elapsed, 240U) << "Too much tolerance"; } TEST_F(PAMMTest, HandleCounter) { @@ -72,7 +75,7 @@ TEST_F(PAMMTest, HandleJSONOutput) { Pamm.addToHistogram("Test-Set", "42"); Pamm.incCounter("setOpCount", 11); - std::this_thread::sleep_for(std::chrono::milliseconds(1800)); + std::this_thread::sleep_for(std::chrono::milliseconds(180)); Pamm.stopTimer("timer2"); Pamm.addToHistogram("Test-Set", "42"); @@ -90,7 +93,7 @@ TEST_F(PAMMTest, HandleJSONOutput) { Pamm.startTimer("timer3"); Pamm.incCounter("timerCount"); - std::this_thread::sleep_for(std::chrono::milliseconds(2300)); + std::this_thread::sleep_for(std::chrono::milliseconds(230)); Pamm.addToHistogram("Test-Set", "1"); Pamm.addToHistogram("Test-Set", "1"); @@ -105,99 +108,31 @@ TEST_F(PAMMTest, HandleJSONOutput) { Pamm.incCounter("setOpCount", 9); Pamm.stopTimer("timer3"); Pamm.exportMeasuredData("HandleJSONOutputTest"); -} -TEST_F(PAMMTest, DISABLED_PerformanceTimerBasic) { - time_point Start1 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - time_point End1 = std::chrono::high_resolution_clock::now(); - time_point Start2 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - time_point End2 = std::chrono::high_resolution_clock::now(); - time_point Start3 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(30)); - time_point End3 = std::chrono::high_resolution_clock::now(); - time_point Start4 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(40)); - time_point End4 = std::chrono::high_resolution_clock::now(); - time_point Start5 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - time_point End5 = std::chrono::high_resolution_clock::now(); - time_point Start6 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - time_point End6 = std::chrono::high_resolution_clock::now(); - time_point Start7 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(150)); - time_point End7 = std::chrono::high_resolution_clock::now(); - time_point Start8 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - time_point End8 = std::chrono::high_resolution_clock::now(); - time_point Start9 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(300)); - time_point End9 = std::chrono::high_resolution_clock::now(); - time_point Start10 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - time_point End10 = std::chrono::high_resolution_clock::now(); - time_point Start11 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - time_point End11 = std::chrono::high_resolution_clock::now(); - time_point Start12 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - time_point End12 = std::chrono::high_resolution_clock::now(); - time_point Start13 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(5000)); - time_point End13 = std::chrono::high_resolution_clock::now(); - time_point Start14 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(10000)); - time_point End14 = std::chrono::high_resolution_clock::now(); - time_point Start15 = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(20000)); - time_point End15 = std::chrono::high_resolution_clock::now(); - auto Duration = - std::chrono::duration_cast(End1 - Start1); - llvm::outs() << "timer_1 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End2 - Start2); - llvm::outs() << "timer_2 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End3 - Start3); - llvm::outs() << "timer_3 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End4 - Start4); - llvm::outs() << "timer_4 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End5 - Start5); - llvm::outs() << "timer_5 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End6 - Start6); - llvm::outs() << "timer_6 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End7 - Start7); - llvm::outs() << "timer_7 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End8 - Start8); - llvm::outs() << "timer_8 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End9 - Start9); - llvm::outs() << "timer_9 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End10 - Start10); - llvm::outs() << "timer_10 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End11 - Start11); - llvm::outs() << "timer_11 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End12 - Start12); - llvm::outs() << "timer_12 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End13 - Start13); - llvm::outs() << "timer_13 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End14 - Start14); - llvm::outs() << "timer_14 : " << Duration.count() << '\n'; - Duration = - std::chrono::duration_cast(End15 - Start15); - llvm::outs() << "timer_15 : " << Duration.count() << '\n'; + EXPECT_EQ(30, Pamm.getCounter("setOpCount")); + EXPECT_EQ(3, Pamm.getCounter("timerCount")); + + auto Timer1Elapsed = Pamm.elapsedTime("timer1"); + auto Timer2Elapsed = Pamm.elapsedTime("timer2"); + auto Timer3Elapsed = Pamm.elapsedTime("timer3"); + + EXPECT_GE(Timer1Elapsed, 410); // 180+230 + EXPECT_LT(Timer1Elapsed, 820); // 180+230 + + EXPECT_GE(Timer2Elapsed, 180); + EXPECT_LT(Timer2Elapsed, 360); + + EXPECT_GE(Timer3Elapsed, 230); + EXPECT_LT(Timer3Elapsed, 460); + + EXPECT_EQ(1, Pamm.getHistogram().size()); + EXPECT_EQ("Test-Set", Pamm.getHistogram().begin()->first()); + + llvm::StringMap Gt = { + {"1", 10}, {"2", 4}, {"13", 3}, {"42", 13}, {"54", 3}, + }; + const auto &Hist = Pamm.getHistogram().begin()->second; + EXPECT_EQ(Hist, Gt); } // main function for the test case From 1b28878d95817facf8ee700c13d959008802f1a3 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 17 Aug 2023 13:53:29 +0200 Subject: [PATCH 25/59] disable the RVO test as it requires a very specific system setup to work (#659) --- .../IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp index a121fe138..d0ca110ab 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysisTest.cpp @@ -855,8 +855,8 @@ TEST_F(IDEInstInteractionAnalysisTest, HandleHeapTest_01) { } PHASAR_SKIP_TEST(TEST_F(IDEInstInteractionAnalysisTest, HandleRVOTest_01) { - // If we use libcxx this won't work since internal implementation is different - LIBCPP_GTEST_SKIP; + GTEST_SKIP() << "This test heavily depends on the used stdlib version. TODO: " + "add a better one"; std::set GroundTruth; GroundTruth.emplace( From 4ac7e69ca28a77db31e1d81a77d69e9d9f3c56b7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 24 Aug 2023 19:56:27 +0200 Subject: [PATCH 26/59] Make NToString and friends free functions (#652) * Make NToString and friends free functions * Remove double parentheses * Template Typestate Analysis (#654) * Make IDETypeStateDescription a template to allow for type-safe type states * Implement JoinLatticeTraits for CSTDFILEIOState * Move TSA flow functions to source file again --------- Co-authored-by: Martin Mory --- .clang-tidy | 2 +- .../DataFlow/IfdsIde/IDETabulationProblem.h | 6 +- .../DataFlow/IfdsIde/IFDSTabulationProblem.h | 4 - .../phasar/DataFlow/IfdsIde/InitialSeeds.h | 2 +- .../IfdsIde/Solver/FlowEdgeFunctionCache.h | 103 +-- .../DataFlow/IfdsIde/Solver/IDESolver.h | 216 +++-- .../DataFlow/IfdsIde/Solver/JumpFunctions.h | 47 +- .../phasar/DataFlow/IfdsIde/SolverResults.h | 16 +- .../DataFlow/Mono/Contexts/CallStringCTX.h | 5 +- .../phasar/DataFlow/Mono/IntraMonoProblem.h | 7 +- .../DataFlow/Mono/Solver/InterMonoSolver.h | 31 +- .../DataFlow/Mono/Solver/IntraMonoSolver.h | 6 +- .../Problems/IDEExtendedTaintAnalysis.h | 8 - .../IDEGeneralizedLCA/IDEGeneralizedLCA.h | 9 - .../Problems/IDEInstInteractionAnalysis.h | 23 +- .../Problems/IDELinearConstantAnalysis.h | 8 - .../IfdsIde/Problems/IDEProtoAnalysis.h | 8 - .../Problems/IDESecureHeapPropagation.h | 12 +- .../DataFlow/IfdsIde/Problems/IDESolverTest.h | 8 - .../IfdsIde/Problems/IDETypeStateAnalysis.h | 606 +++++++++++--- .../IfdsIde/Problems/IFDSConstAnalysis.h | 6 - .../Problems/IFDSFieldSensTaintAnalysis.h | 31 +- .../IfdsIde/Problems/IFDSProtoAnalysis.h | 6 - .../IfdsIde/Problems/IFDSSignAnalysis.h | 6 - .../IfdsIde/Problems/IFDSSolverTest.h | 6 - .../IfdsIde/Problems/IFDSTaintAnalysis.h | 6 - .../IfdsIde/Problems/IFDSTypeAnalysis.h | 6 - .../Problems/IFDSUninitializedVariables.h | 6 - .../CSTDFILEIOTypeStateDescription.h | 80 +- .../OpenSSLEVPKDFCTXDescription.h | 88 +-- .../OpenSSLEVPKDFDescription.h | 60 +- .../OpenSSLSecureHeapDescription.h | 46 +- .../OpenSSLSecureMemoryDescription.h | 43 +- .../TypeStateDescription.h | 36 +- .../InterMonoFullConstantPropagation.h | 6 - .../Mono/Problems/InterMonoSolverTest.h | 6 - .../Mono/Problems/InterMonoTaintAnalysis.h | 6 - .../IntraMonoFullConstantPropagation.h | 28 +- .../Mono/Problems/IntraMonoSolverTest.h | 7 - .../Mono/Problems/IntraMonoUninitVariables.h | 6 - include/phasar/Utils/Printer.h | 173 ++-- include/phasar/Utils/TypeTraits.h | 2 + .../AnalysisControllerXIDECSTDIOTS.cpp | 3 +- .../AnalysisControllerXIDEOpenSSLTS.cpp | 3 +- .../Problems/IDEExtendedTaintAnalysis.cpp | 27 +- .../IDEGeneralizedLCA/IDEGeneralizedLCA.cpp | 54 +- .../Problems/IDELinearConstantAnalysis.cpp | 34 +- .../IfdsIde/Problems/IDEProtoAnalysis.cpp | 20 - .../Problems/IDESecureHeapPropagation.cpp | 72 +- .../IfdsIde/Problems/IDESolverTest.cpp | 20 - .../IfdsIde/Problems/IDETypeStateAnalysis.cpp | 741 ++++-------------- .../IfdsIde/Problems/IFDSConstAnalysis.cpp | 15 - .../Problems/IFDSFieldSensTaintAnalysis.cpp | 24 + .../IfdsIde/Problems/IFDSProtoAnalysis.cpp | 15 - .../IfdsIde/Problems/IFDSSignAnalysis.cpp | 15 - .../IfdsIde/Problems/IFDSSolverTest.cpp | 15 - .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 13 - .../IfdsIde/Problems/IFDSTypeAnalysis.cpp | 15 - .../Problems/IFDSUninitializedVariables.cpp | 22 +- .../CSTDFILEIOTypeStateDescription.cpp | 157 ++-- .../OpenSSLEVPKDFCTXDescription.cpp | 137 ++-- .../OpenSSLEVPKDFDescription.cpp | 67 +- .../OpenSSLSecureHeapDescription.cpp | 100 ++- .../OpenSSLSecureMemoryDescription.cpp | 163 ++-- .../InterMonoFullConstantPropagation.cpp | 15 - .../Mono/Problems/InterMonoSolverTest.cpp | 15 - .../Mono/Problems/InterMonoTaintAnalysis.cpp | 14 - .../IntraMonoFullConstantPropagation.cpp | 32 +- .../Mono/Problems/IntraMonoSolverTest.cpp | 15 - .../Problems/IntraMonoUninitVariables.cpp | 15 - lib/PhasarLLVM/Utils/LLVMPrinter.cpp | 14 + tools/example-tool/myphasartool.cpp | 4 +- .../Problems/IDETSAnalysisFileIOTest.cpp | 10 +- .../IDETSAnalysisOpenSSLEVPKDFTest.cpp | 403 +++++----- .../IDETSAnalysisOpenSSLSecureHeapTest.cpp | 24 +- .../IDETSAnalysisOpenSSLSecureMemoryTest.cpp | 23 +- 76 files changed, 1788 insertions(+), 2315 deletions(-) create mode 100644 lib/PhasarLLVM/Utils/LLVMPrinter.cpp diff --git a/.clang-tidy b/.clang-tidy index 93ad42fe9..847f4660f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,7 +55,7 @@ CheckOptions: - key: readability-identifier-naming.ParameterIgnoredRegexp value: (d|d1|d2|d3|d4|d5|eP|f|n) - key: readability-identifier-naming.FunctionIgnoredRegexp - value: (try_emplace|from_json|to_json|equal_to|to_string) + value: (try_emplace|from_json|to_json|equal_to|to_string,DToString|NToString|FToString|LToString) - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: 1 - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index 8f79ed8b4..cf4970f1d 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -39,12 +39,8 @@ struct HasNoConfigurationType; template > class IDETabulationProblem : public FlowFunctions, - public NodePrinter, - public DataFlowFactPrinter, - public FunctionPrinter, public EdgeFunctions, - public JoinLattice, - public EdgeFactPrinter { + public JoinLattice { public: using ProblemAnalysisDomain = AnalysisDomainTy; using d_t = typename AnalysisDomainTy::d_t; diff --git a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h index 5c6cb2059..5deddf1f9 100644 --- a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h @@ -78,10 +78,6 @@ class IFDSTabulationProblem } EdgeFunction allTopFunction() final { return AllTop{}; } - - void printEdgeFact(llvm::raw_ostream &OS, BinaryDomain Val) const final { - OS << Val; - } }; } // namespace psr diff --git a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h index b5a001031..60e5ae23e 100644 --- a/include/phasar/DataFlow/IfdsIde/InitialSeeds.h +++ b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h @@ -46,7 +46,7 @@ template class InitialSeeds { } void addSeed(N Node, D Fact, L Value) { - Seeds[Node][Fact] = std::move(Value); + Seeds[std::move(Node)].insert_or_assign(std::move(Fact), std::move(Value)); } [[nodiscard]] size_t countInitialSeeds() const { diff --git a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h index a670a403f..484606935 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h @@ -188,8 +188,8 @@ class FlowEdgeFunctionCache { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Normal flow function factory call"); - PHASAR_LOG_LEVEL(DEBUG, "(N) Curr Inst : " << Problem.NtoString(Curr)); - PHASAR_LOG_LEVEL(DEBUG, "(N) Succ Inst : " << Problem.NtoString(Succ))); + PHASAR_LOG_LEVEL(DEBUG, "(N) Curr Inst : " << NToString(Curr)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Succ Inst : " << NToString(Succ))); auto Key = createEdgeFunctionInstKey(Curr, Succ); auto SearchNormalFlowFunction = NormalFunctionCache.find(Key); if (SearchNormalFlowFunction != NormalFunctionCache.end()) { @@ -218,11 +218,10 @@ class FlowEdgeFunctionCache { FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) { PAMM_GET_INSTANCE; - IF_LOG_ENABLED(PHASAR_LOG_LEVEL(DEBUG, "Call flow function factory call"); - PHASAR_LOG_LEVEL(DEBUG, "(N) Call Stmt : " - << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL( - DEBUG, "(F) Dest Fun : " << Problem.FtoString(DestFun))); + IF_LOG_ENABLED( + PHASAR_LOG_LEVEL(DEBUG, "Call flow function factory call"); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Stmt : " << NToString(CallSite)); + PHASAR_LOG_LEVEL(DEBUG, "(F) Dest Fun : " << FToString(DestFun))); auto Key = std::tie(CallSite, DestFun); auto SearchCallFlowFunction = CallFlowFunctionCache.find(Key); if (SearchCallFlowFunction != CallFlowFunctionCache.end()) { @@ -245,14 +244,10 @@ class FlowEdgeFunctionCache { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Return flow function factory call"); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Call Site : " << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(F) Callee : " << Problem.FtoString(CalleeFun)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Exit Stmt : " << Problem.NtoString(ExitInst)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Ret Site : " << Problem.NtoString(RetSite))); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Site : " << NToString(CallSite)); + PHASAR_LOG_LEVEL(DEBUG, "(F) Callee : " << FToString(CalleeFun)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Exit Stmt : " << NToString(ExitInst)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Ret Site : " << NToString(RetSite))); auto Key = std::tie(CallSite, CalleeFun, ExitInst, RetSite); auto SearchReturnFlowFunction = ReturnFlowFunctionCache.find(Key); if (SearchReturnFlowFunction != ReturnFlowFunctionCache.end()) { @@ -279,13 +274,11 @@ class FlowEdgeFunctionCache { IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return flow function factory call"); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Call Site : " << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Ret Site : " << Problem.NtoString(RetSite)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Site : " << NToString(CallSite)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Ret Site : " << NToString(RetSite)); PHASAR_LOG_LEVEL(DEBUG, "(F) Callee's : "); for (auto callee : Callees) { - PHASAR_LOG_LEVEL(DEBUG, " " << Problem.FtoString(callee)); + PHASAR_LOG_LEVEL(DEBUG, " " << FToString(callee)); };); auto Key = std::tie(CallSite, RetSite); auto SearchCallToRetFlowFunction = CallToRetFlowFunctionCache.find(Key); @@ -311,10 +304,8 @@ class FlowEdgeFunctionCache { // INC_COUNTER("Summary-FF Construction", 1, Full); IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Summary flow function factory call"); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Call Stmt : " << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(F) Dest Mthd : " << Problem.FtoString(DestFun)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Stmt : " << NToString(CallSite)); + PHASAR_LOG_LEVEL(DEBUG, "(F) Dest Mthd : " << FToString(DestFun)); PHASAR_LOG_LEVEL(DEBUG, ' ')); auto FF = Problem.getSummaryFlowFunction(CallSite, DestFun); return FF; @@ -325,12 +316,10 @@ class FlowEdgeFunctionCache { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Normal edge function factory call"); - PHASAR_LOG_LEVEL(DEBUG, "(N) Curr Inst : " << Problem.NtoString(Curr)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Curr Node : " << Problem.DtoString(CurrNode)); - PHASAR_LOG_LEVEL(DEBUG, "(N) Succ Inst : " << Problem.NtoString(Succ)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Succ Node : " << Problem.DtoString(SuccNode))); + PHASAR_LOG_LEVEL(DEBUG, "(N) Curr Inst : " << NToString(Curr)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Curr Node : " << DToString(CurrNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Succ Inst : " << NToString(Succ)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Succ Node : " << DToString(SuccNode))); EdgeFuncInstKey OuterMapKey = createEdgeFunctionInstKey(Curr, Succ); auto SearchInnerMap = NormalFunctionCache.find(OuterMapKey); @@ -371,15 +360,12 @@ class FlowEdgeFunctionCache { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call edge function factory call"); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Call Stmt : " << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Src Node : " << Problem.DtoString(SrcNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Stmt : " << NToString(CallSite)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Src Node : " << DToString(SrcNode)); - PHASAR_LOG_LEVEL( - DEBUG, "(F) Dest Fun : " << Problem.FtoString(DestinationFunction)); PHASAR_LOG_LEVEL(DEBUG, - "(D) Dest Node : " << Problem.DtoString(DestNode))); + "(F) Dest Fun : " << FToString(DestinationFunction)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Dest Node : " << DToString(DestNode))); auto Key = std::tie(CallSite, SrcNode, DestinationFunction, DestNode); auto SearchCallEdgeFunction = CallEdgeFunctionCache.find(Key); if (SearchCallEdgeFunction != CallEdgeFunctionCache.end()) { @@ -404,18 +390,13 @@ class FlowEdgeFunctionCache { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Return edge function factory call"); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Site : " << NToString(CallSite)); PHASAR_LOG_LEVEL(DEBUG, - "(N) Call Site : " << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL( - DEBUG, "(F) Callee : " << Problem.FtoString(CalleeFunction)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Exit Stmt : " << Problem.NtoString(ExitInst)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Exit Node : " << Problem.DtoString(ExitNode)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Ret Site : " << Problem.NtoString(RetSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Ret Node : " << Problem.DtoString(RetNode))); + "(F) Callee : " << FToString(CalleeFunction)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Exit Stmt : " << NToString(ExitInst)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Exit Node : " << DToString(ExitNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Ret Site : " << NToString(RetSite)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Ret Node : " << DToString(RetNode))); auto Key = std::tie(CallSite, CalleeFunction, ExitInst, ExitNode, RetSite, RetNode); auto SearchReturnEdgeFunction = ReturnEdgeFunctionCache.find(Key); @@ -442,18 +423,14 @@ class FlowEdgeFunctionCache { IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return edge function factory call"); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Call Site : " << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Call Node : " << Problem.DtoString(CallNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Site : " << NToString(CallSite)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Call Node : " << DToString(CallNode)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Ret Site : " << Problem.NtoString(RetSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Ret Node : " << Problem.DtoString(RetSiteNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Ret Site : " << NToString(RetSite)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Ret Node : " << DToString(RetSiteNode)); PHASAR_LOG_LEVEL(DEBUG, "(F) Callee's : "); for (auto callee : Callees) { - PHASAR_LOG_LEVEL(DEBUG, " " << Problem.FtoString(callee)); + PHASAR_LOG_LEVEL(DEBUG, " " << FToString(callee)); }); EdgeFuncInstKey OuterMapKey = createEdgeFunctionInstKey(CallSite, RetSite); @@ -498,14 +475,10 @@ class FlowEdgeFunctionCache { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Summary edge function factory call"); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Call Site : " << Problem.NtoString(CallSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Call Node : " << Problem.DtoString(CallNode)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Ret Site : " << Problem.NtoString(RetSite)); - PHASAR_LOG_LEVEL(DEBUG, - "(D) Ret Node : " << Problem.DtoString(RetSiteNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Call Site : " << NToString(CallSite)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Call Node : " << DToString(CallNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Ret Site : " << NToString(RetSite)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Ret Node : " << DToString(RetSiteNode)); PHASAR_LOG_LEVEL(DEBUG, ' ')); auto Key = std::tie(CallSite, CallNode, RetSite, RetSiteNode); auto SearchSummaryEdgeFunction = SummaryEdgeFunctionCache.find(Key); diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 41207a44d..669bd108d 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -82,8 +82,7 @@ class IDESolver : IDEProblem(Problem), ZeroValue(Problem.getZeroValue()), ICF(ICF), SolverConfig(Problem.getIFDSIDESolverConfig()), CachedFlowEdgeFunctions(Problem), AllTop(Problem.allTopFunction()), - JumpFn(std::make_shared>( - IDEProblem)), + JumpFn(std::make_shared>()), Seeds(Problem.initialSeeds()) { assert(ICF != nullptr); } @@ -110,21 +109,16 @@ class IDESolver n_t Curr; for (unsigned I = 0; I < Cells.size(); ++I) { Curr = Cells[I].getRowKey(); - auto NStr = llvm::StringRef(IDEProblem.NtoString(Cells[I].getRowKey())) - .trim() - .str(); + auto NStr = + llvm::StringRef(NToString(Cells[I].getRowKey())).trim().str(); std::string NodeStr = ICF->getFunctionName(ICF->getFunctionOf(Curr)) + "::" + NStr; J[DataFlowID][NodeStr]; std::string FactStr = - llvm::StringRef(IDEProblem.DtoString(Cells[I].getColumnKey())) - .trim() - .str(); + llvm::StringRef(DToString(Cells[I].getColumnKey())).trim().str(); std::string ValueStr = - llvm::StringRef(IDEProblem.LtoString(Cells[I].getValue())) - .trim() - .str(); + llvm::StringRef(LToString(Cells[I].getValue())).trim().str(); J[DataFlowID][NodeStr]["Facts"] += {FactStr, ValueStr}; } } @@ -198,7 +192,7 @@ class IDESolver } void dumpResults(llvm::raw_ostream &OS = llvm::outs()) { - getSolverResults().dumpResults(*ICF, IDEProblem, OS); + getSolverResults().dumpResults(*ICF, OS); } void dumpAllInterPathEdges() { @@ -282,8 +276,8 @@ class IDESolver virtual void processCall(const PathEdge Edge) { PAMM_GET_INSTANCE; INC_COUNTER("Process Call", 1, Full); - PHASAR_LOG_LEVEL(DEBUG, "Process call at target: " - << IDEProblem.NtoString(Edge.getTarget())); + PHASAR_LOG_LEVEL(DEBUG, + "Process call at target: " << NToString(Edge.getTarget())); d_t d1 = Edge.factAtSource(); n_t n = Edge.getTarget(); // a call node; line 14... @@ -299,7 +293,7 @@ class IDESolver } PHASAR_LOG_LEVEL(DEBUG, "Possible return sites:"); for (auto ret : ReturnSiteNs) { - PHASAR_LOG_LEVEL(DEBUG, " " << IDEProblem.NtoString(ret)); + PHASAR_LOG_LEVEL(DEBUG, " " << NToString(ret)); }); // for each possible callee @@ -351,8 +345,8 @@ class IDESolver for (d_t d3 : Res) { using TableCell = typename Table>::Cell; // create initial self-loop - PHASAR_LOG_LEVEL(DEBUG, "Create initial self-loop with D: " - << IDEProblem.DtoString(d3)); + PHASAR_LOG_LEVEL( + DEBUG, "Create initial self-loop with D: " << DToString(d3)); WorkList.emplace_back(PathEdge(d3, SP, d3), EdgeIdentity{}); // line 15 // register the fact that has an incoming edge from @@ -363,8 +357,8 @@ class IDESolver // const std::set endSumm(endSummary(sP, d3)); // llvm::outs() << "ENDSUMM" << '\n'; // llvm::outs() << "Size: " << endSumm.size() << '\n'; - // llvm::outs() << "sP: " << IDEProblem.NtoString(sP) - // << "\nd3: " << IDEProblem.DtoString(d3) + // llvm::outs() << "sP: " << NToString(sP) + // << "\nd3: " << DToString(d3) // << '\n'; // printEndSummaryTab(); // still line 15.2 of Naeem/Lhotak/Rodriguez @@ -472,8 +466,8 @@ class IDESolver virtual void processNormalFlow(PathEdge Edge) { PAMM_GET_INSTANCE; INC_COUNTER("Process Normal", 1, Full); - PHASAR_LOG_LEVEL(DEBUG, "Process normal at target: " - << IDEProblem.NtoString(Edge.getTarget())); + PHASAR_LOG_LEVEL( + DEBUG, "Process normal at target: " << NToString(Edge.getTarget())); EdgeFunction f = jumpFunction(Edge); auto [d1, n, d2] = Edge.consume(); @@ -571,9 +565,9 @@ class IDESolver IF_LOG_ENABLED({ PHASAR_LOG_LEVEL(DEBUG, "Function : " << ICF->getFunctionOf(NHashN)->getName()); - PHASAR_LOG_LEVEL(DEBUG, "Inst. : " << IDEProblem.NtoString(NHashN)); - PHASAR_LOG_LEVEL(DEBUG, "Fact : " << IDEProblem.DtoString(NHashD)); - PHASAR_LOG_LEVEL(DEBUG, "Value : " << IDEProblem.LtoString(L)); + PHASAR_LOG_LEVEL(DEBUG, "Inst. : " << NToString(NHashN)); + PHASAR_LOG_LEVEL(DEBUG, "Fact : " << DToString(NHashD)); + PHASAR_LOG_LEVEL(DEBUG, "Value : " << LToString(L)); PHASAR_LOG_LEVEL(DEBUG, ' '); }); // TOP is the implicit default value which we do not need to store. @@ -588,12 +582,11 @@ class IDESolver EdgeFunction jumpFunction(const PathEdge Edge) { IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "JumpFunctions Forward-Lookup:"); - PHASAR_LOG_LEVEL(DEBUG, " Source D: " << IDEProblem.DtoString( - Edge.factAtSource())); - PHASAR_LOG_LEVEL( - DEBUG, " Target N: " << IDEProblem.NtoString(Edge.getTarget())); - PHASAR_LOG_LEVEL(DEBUG, " Target D: " << IDEProblem.DtoString( - Edge.factAtTarget()))); + PHASAR_LOG_LEVEL(DEBUG, + " Source D: " << DToString(Edge.factAtSource())); + PHASAR_LOG_LEVEL(DEBUG, " Target N: " << NToString(Edge.getTarget())); + PHASAR_LOG_LEVEL(DEBUG, + " Target D: " << DToString(Edge.factAtTarget()))); auto FwdLookupRes = JumpFn->forwardLookup(Edge.factAtSource(), Edge.getTarget()); @@ -632,15 +625,12 @@ class IDESolver << ". Path Edge --------------------------------------------"); PHASAR_LOG_LEVEL(DEBUG, ' '); PHASAR_LOG_LEVEL(DEBUG, "Process " << PathEdgeCount << ". path edge:"); - PHASAR_LOG_LEVEL(DEBUG, "< D source: " - << IDEProblem.DtoString(Edge.factAtSource()) - << " ;"); - PHASAR_LOG_LEVEL(DEBUG, " N target: " - << IDEProblem.NtoString(Edge.getTarget()) - << " ;"); - PHASAR_LOG_LEVEL(DEBUG, " D target: " - << IDEProblem.DtoString(Edge.factAtTarget()) - << " >"); + PHASAR_LOG_LEVEL(DEBUG, "< D source: " << DToString(Edge.factAtSource()) + << " ;"); + PHASAR_LOG_LEVEL(DEBUG, + " N target: " << NToString(Edge.getTarget()) << " ;"); + PHASAR_LOG_LEVEL(DEBUG, " D target: " << DToString(Edge.factAtTarget()) + << " >"); PHASAR_LOG_LEVEL(DEBUG, ' ')); if (!ICF->isCallSite(Edge.getTarget())) { @@ -717,11 +707,10 @@ class IDESolver // do processing for (const auto &[StartPoint, Facts] : AllSeeds) { for (auto &[Fact, Value] : Facts) { - PHASAR_LOG_LEVEL(DEBUG, - "set initial seed at: " - << IDEProblem.NtoString(StartPoint) - << ", fact: " << IDEProblem.DtoString(Fact) - << ", value: " << IDEProblem.LtoString(Value)); + PHASAR_LOG_LEVEL(DEBUG, "set initial seed at: " + << NToString(StartPoint) + << ", fact: " << DToString(Fact) + << ", value: " << LToString(Value)); // initialize the initial seeds with the top element as we have no // information at the beginning of the value computation problem setVal(StartPoint, Fact, Value); @@ -762,7 +751,7 @@ class IDESolver // Add zero value if it's not in the set of facts. PHASAR_LOG_LEVEL( DEBUG, "Zero-Value has been added automatically to start point: " - << IDEProblem.NtoString(StartPoint)); + << NToString(StartPoint)); Seeds.addSeed(StartPoint, ZeroValue, IDEProblem.bottomElement()); } } @@ -770,22 +759,20 @@ class IDESolver "Number of initial seeds: " << Seeds.countInitialSeeds()); PHASAR_LOG_LEVEL(DEBUG, "List of initial seeds: "); for (const auto &[StartPoint, Facts] : Seeds.getSeeds()) { - PHASAR_LOG_LEVEL(DEBUG, - "Start point: " << IDEProblem.NtoString(StartPoint)); + PHASAR_LOG_LEVEL(DEBUG, "Start point: " << NToString(StartPoint)); /// If statically disabling the logger, Fact and Value are unused. To /// prevent the copilation to fail with -Werror, add the [[maybe_unused]] /// attribute for ([[maybe_unused]] const auto &[Fact, Value] : Facts) { - PHASAR_LOG_LEVEL(DEBUG, "\tFact: " << IDEProblem.DtoString(Fact)); - PHASAR_LOG_LEVEL(DEBUG, "\tValue: " << IDEProblem.LtoString(Value)); + PHASAR_LOG_LEVEL(DEBUG, "\tFact: " << DToString(Fact)); + PHASAR_LOG_LEVEL(DEBUG, "\tValue: " << LToString(Value)); } } for (const auto &[StartPoint, Facts] : Seeds.getSeeds()) { for (const auto &[Fact, Value] : Facts) { - PHASAR_LOG_LEVEL( - DEBUG, "Submit seed at: " << IDEProblem.NtoString(StartPoint)); - PHASAR_LOG_LEVEL(DEBUG, "\tFact: " << IDEProblem.DtoString(Fact)); - PHASAR_LOG_LEVEL(DEBUG, "\tValue: " << IDEProblem.LtoString(Value)); + PHASAR_LOG_LEVEL(DEBUG, "Submit seed at: " << NToString(StartPoint)); + PHASAR_LOG_LEVEL(DEBUG, "\tFact: " << DToString(Fact)); + PHASAR_LOG_LEVEL(DEBUG, "\tValue: " << LToString(Value)); if (!IDEProblem.isZeroValue(Fact)) { INC_COUNTER("Gen facts", 1, Core); } @@ -806,8 +793,8 @@ class IDESolver virtual void processExit(const PathEdge Edge) { PAMM_GET_INSTANCE; INC_COUNTER("Process Exit", 1, Full); - PHASAR_LOG_LEVEL(DEBUG, "Process exit at target: " - << IDEProblem.NtoString(Edge.getTarget())); + PHASAR_LOG_LEVEL(DEBUG, + "Process exit at target: " << NToString(Edge.getTarget())); n_t n = Edge.getTarget(); // an exit node; line 21... EdgeFunction f = jumpFunction(Edge); f_t FunctionThatNeedsSummary = ICF->getFunctionOf(n); @@ -1054,11 +1041,9 @@ class IDESolver void propagate(d_t SourceVal, n_t Target, d_t TargetVal, EdgeFunction f) { PHASAR_LOG_LEVEL(DEBUG, "Propagate flow"); - PHASAR_LOG_LEVEL(DEBUG, - "Source value : " << IDEProblem.DtoString(SourceVal)); - PHASAR_LOG_LEVEL(DEBUG, "Target : " << IDEProblem.NtoString(Target)); - PHASAR_LOG_LEVEL(DEBUG, - "Target value : " << IDEProblem.DtoString(TargetVal)); + PHASAR_LOG_LEVEL(DEBUG, "Source value : " << DToString(SourceVal)); + PHASAR_LOG_LEVEL(DEBUG, "Target : " << NToString(Target)); + PHASAR_LOG_LEVEL(DEBUG, "Target value : " << DToString(TargetVal)); PHASAR_LOG_LEVEL( DEBUG, "Edge function : " << f << " (result of previous compose)"); @@ -1095,13 +1080,11 @@ class IDESolver pathEdgeProcessingTask(std::move(Edge)); IF_LOG_ENABLED(if (!IDEProblem.isZeroValue(TargetVal)) { - PHASAR_LOG_LEVEL( - DEBUG, "EDGE: getFunction()->getName() << ", D: " - << IDEProblem.DtoString(SourceVal) << '>'); - PHASAR_LOG_LEVEL(DEBUG, - " ---> getFunction()->getName() + << ", D: " << DToString(SourceVal) + << '>'); + PHASAR_LOG_LEVEL(DEBUG, " ---> '); PHASAR_LOG_LEVEL(DEBUG, ' '); }); @@ -1141,15 +1124,12 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "Start of incomingtab entry"); for (const auto &Cell : IncomingTab.cellSet()) { - PHASAR_LOG_LEVEL(DEBUG, - "sP: " << IDEProblem.NtoString(Cell.getRowKey())); - PHASAR_LOG_LEVEL(DEBUG, - "d3: " << IDEProblem.DtoString(Cell.getColumnKey())); + PHASAR_LOG_LEVEL(DEBUG, "sP: " << NToString(Cell.getRowKey())); + PHASAR_LOG_LEVEL(DEBUG, "d3: " << DToString(Cell.getColumnKey())); for (const auto &Entry : Cell.getValue()) { - PHASAR_LOG_LEVEL(DEBUG, - " n: " << IDEProblem.NtoString(Entry.first)); + PHASAR_LOG_LEVEL(DEBUG, " n: " << NToString(Entry.first)); for (const auto &Fact : Entry.second) { - PHASAR_LOG_LEVEL(DEBUG, " d2: " << IDEProblem.DtoString(Fact)); + PHASAR_LOG_LEVEL(DEBUG, " d2: " << DToString(Fact)); } } PHASAR_LOG_LEVEL(DEBUG, "---------------"); @@ -1160,19 +1140,19 @@ class IDESolver IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Start of endsummarytab entry"); - EndsummaryTab.foreachCell([this](const auto &Row, const auto &Col, - const auto &Val) { - PHASAR_LOG_LEVEL(DEBUG, "sP: " << IDEProblem.NtoString(Row)); - PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(Col)); + EndsummaryTab.foreachCell( + [](const auto &Row, const auto &Col, const auto &Val) { + PHASAR_LOG_LEVEL(DEBUG, "sP: " << NToString(Row)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(Col)); - Val.foreachCell([this](const auto &InnerRow, const auto &InnerCol, + Val.foreachCell([](const auto &InnerRow, const auto &InnerCol, const auto &InnerVal) { - PHASAR_LOG_LEVEL(DEBUG, " eP: " << IDEProblem.NtoString(InnerRow)); - PHASAR_LOG_LEVEL(DEBUG, " d2: " << IDEProblem.DtoString(InnerCol)); - PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerVal); - }); - PHASAR_LOG_LEVEL(DEBUG, "---------------"); - }); + PHASAR_LOG_LEVEL(DEBUG, " eP: " << NToString(InnerRow)); + PHASAR_LOG_LEVEL(DEBUG, " d2: " << DToString(InnerCol)); + PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerVal); + }); + PHASAR_LOG_LEVEL(DEBUG, "---------------"); + }); PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry");) } @@ -1193,15 +1173,15 @@ class IDESolver }); for (const auto &Cell : Cells) { auto Edge = std::make_pair(Cell.getRowKey(), Cell.getColumnKey()); - std::string N2Label = IDEProblem.NtoString(Edge.second); - llvm::outs() << "\nN1: " << IDEProblem.NtoString(Edge.first) << '\n' + std::string N2Label = NToString(Edge.second); + llvm::outs() << "\nN1: " << NToString(Edge.first) << '\n' << "N2: " << N2Label << "\n----" << std::string(N2Label.size(), '-') << '\n'; for (auto D1ToD2Set : Cell.getValue()) { auto D1Fact = D1ToD2Set.first; - llvm::outs() << "D1: " << IDEProblem.DtoString(D1Fact) << '\n'; + llvm::outs() << "D1: " << DToString(D1Fact) << '\n'; for (auto D2Fact : D1ToD2Set.second) { - llvm::outs() << "\tD2: " << IDEProblem.DtoString(D2Fact) << '\n'; + llvm::outs() << "\tD2: " << DToString(D2Fact) << '\n'; } llvm::outs() << '\n'; } @@ -1221,15 +1201,15 @@ class IDESolver }); for (const auto &Cell : Cells) { auto Edge = std::make_pair(Cell.getRowKey(), Cell.getColumnKey()); - std::string N2Label = IDEProblem.NtoString(Edge.second); - llvm::outs() << "\nN1: " << IDEProblem.NtoString(Edge.first) << '\n' + std::string N2Label = NToString(Edge.second); + llvm::outs() << "\nN1: " << NToString(Edge.first) << '\n' << "N2: " << N2Label << "\n----" << std::string(N2Label.size(), '-') << '\n'; for (auto D1ToD2Set : Cell.getValue()) { auto D1Fact = D1ToD2Set.first; - llvm::outs() << "D1: " << IDEProblem.DtoString(D1Fact) << '\n'; + llvm::outs() << "D1: " << DToString(D1Fact) << '\n'; for (auto D2Fact : D1ToD2Set.second) { - llvm::outs() << "\tD2: " << IDEProblem.DtoString(D2Fact) << '\n'; + llvm::outs() << "\tD2: " << DToString(D2Fact) << '\n'; } llvm::outs() << '\n'; } @@ -1264,10 +1244,10 @@ class IDESolver // Case 2: d1 not in d2-Set, i.e., d1 was killed. d2-Set could be empty. for (const auto &Cell : ComputedIntraPathEdges.cellSet()) { auto Edge = std::make_pair(Cell.getRowKey(), Cell.getColumnKey()); - PHASAR_LOG_LEVEL(DEBUG, "N1: " << IDEProblem.NtoString(Edge.first)); - PHASAR_LOG_LEVEL(DEBUG, "N2: " << IDEProblem.NtoString(Edge.second)); + PHASAR_LOG_LEVEL(DEBUG, "N1: " << NToString(Edge.first)); + PHASAR_LOG_LEVEL(DEBUG, "N2: " << NToString(Edge.second)); for (auto &[D1, D2s] : Cell.getValue()) { - PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(D1)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(D1)); NumIntraPathEdges += D2s.size(); // Case 1 if (D2s.find(D1) != D2s.end()) { @@ -1283,7 +1263,7 @@ class IDESolver } IF_LOG_ENABLED([this](const auto &D2s) { for (auto D2 : D2s) { - PHASAR_LOG_LEVEL(DEBUG, "d2: " << IDEProblem.DtoString(D2)); + PHASAR_LOG_LEVEL(DEBUG, "d2: " << DToString(D2)); } PHASAR_LOG_LEVEL(DEBUG, "----"); }(D2s)); @@ -1296,8 +1276,8 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "INTER PATH EDGES"); for (const auto &Cell : ComputedInterPathEdges.cellSet()) { auto Edge = std::make_pair(Cell.getRowKey(), Cell.getColumnKey()); - PHASAR_LOG_LEVEL(DEBUG, "N1: " << IDEProblem.NtoString(Edge.first)); - PHASAR_LOG_LEVEL(DEBUG, "N2: " << IDEProblem.NtoString(Edge.second)); + PHASAR_LOG_LEVEL(DEBUG, "N1: " << NToString(Edge.first)); + PHASAR_LOG_LEVEL(DEBUG, "N2: " << NToString(Edge.second)); // --- Call-flow Path Edges --- // Case 1: d1 --> empty set // Can be ignored, since killing a fact in the caller context will @@ -1314,7 +1294,7 @@ class IDESolver // Process the summary's #gen and #kill. if (ICF->isCallSite(Edge.first)) { for (auto &[D1, D2s] : Cell.getValue()) { - PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(D1)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(D1)); NumInterPathEdges += D2s.size(); for (auto D2 : D2s) { if (!IDEProblem.isZeroValue(D2)) { @@ -1340,7 +1320,7 @@ class IDESolver } else { ProcessSummaryFacts.emplace(Edge.second, D2); } - PHASAR_LOG_LEVEL(DEBUG, "d2: " << IDEProblem.DtoString(D2)); + PHASAR_LOG_LEVEL(DEBUG, "d2: " << DToString(D2)); } PHASAR_LOG_LEVEL(DEBUG, "----"); } @@ -1354,7 +1334,7 @@ class IDESolver // Zero value does not count towards generated/killed facts. if (ICF->isExitInst(Cell.getRowKey())) { for (auto &[D1, D2s] : Cell.getValue()) { - PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(D1)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(D1)); NumInterPathEdges += D2s.size(); auto CallerFacts = ValidInCallerContext[Edge.second]; for (auto D2 : D2s) { @@ -1362,7 +1342,7 @@ class IDESolver if (CallerFacts.find(D2) == CallerFacts.end()) { NumGenFacts++; } - PHASAR_LOG_LEVEL(DEBUG, "d2: " << IDEProblem.DtoString(D2)); + PHASAR_LOG_LEVEL(DEBUG, "d2: " << DToString(D2)); } PHASAR_LOG_LEVEL(DEBUG, "----"); } @@ -1372,10 +1352,8 @@ class IDESolver PHASAR_LOG_LEVEL(DEBUG, "SUMMARY REUSE"); std::size_t TotalSummaryReuse = 0; for (const auto &Entry : FSummaryReuse) { - PHASAR_LOG_LEVEL(DEBUG, - "N1: " << IDEProblem.NtoString(Entry.first.first)); - PHASAR_LOG_LEVEL(DEBUG, - "D1: " << IDEProblem.DtoString(Entry.first.second)); + PHASAR_LOG_LEVEL(DEBUG, "N1: " << NToString(Entry.first.first)); + PHASAR_LOG_LEVEL(DEBUG, "D1: " << DToString(Entry.first.second)); PHASAR_LOG_LEVEL(DEBUG, "#Reuse: " << Entry.second); TotalSummaryReuse += Entry.second; } @@ -1438,8 +1416,8 @@ class IDESolver }); for (const auto &Cell : Cells) { auto Edge = std::make_pair(Cell.getRowKey(), Cell.getColumnKey()); - std::string N1Label = IDEProblem.NtoString(Edge.first); - std::string N2Label = IDEProblem.NtoString(Edge.second); + std::string N1Label = NToString(Edge.first); + std::string N2Label = NToString(Edge.second); PHASAR_LOG_LEVEL(DEBUG, "N1: " << N1Label); PHASAR_LOG_LEVEL(DEBUG, "N2: " << N2Label); std::string N1StmtId = ICF->getStatementId(Edge.first); @@ -1468,7 +1446,7 @@ class IDESolver unsigned D2FactId = 0; for (const auto &D1ToD2Set : Cell.getValue()) { auto D1Fact = D1ToD2Set.first; - PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(D1Fact)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(D1Fact)); DOTNode D1; if (IDEProblem.isZeroValue(D1Fact)) { @@ -1477,7 +1455,7 @@ class IDESolver } else { // Get the fact-ID D1FactId = G.getFactID(D1Fact); - std::string D1Label = IDEProblem.DtoString(D1Fact); + std::string D1Label = DToString(D1Fact); // Get or create the fact subgraph D1FSG = FG->getOrCreateFactSG(D1FactId, D1Label); @@ -1489,13 +1467,13 @@ class IDESolver DOTFactSubGraph *D2FSG = nullptr; for (const auto &D2Fact : D1ToD2Set.second) { - PHASAR_LOG_LEVEL(DEBUG, "d2: " << IDEProblem.DtoString(D2Fact)); + PHASAR_LOG_LEVEL(DEBUG, "d2: " << DToString(D2Fact)); // We do not need to generate any intra-procedural nodes and edges // for the zero value since they will be auto-generated if (!IDEProblem.isZeroValue(D2Fact)) { // Get the fact-ID D2FactId = G.getFactID(D2Fact); - std::string D2Label = IDEProblem.DtoString(D2Fact); + std::string D2Label = DToString(D2Fact); DOTNode D2 = {FuncName, D2Label, N2StmtId, D2FactId, false, true}; std::string EFLabel; auto EFVec = IntermediateEdgeFunctions[std::make_tuple( @@ -1531,8 +1509,8 @@ class IDESolver }); for (const auto &Cell : Cells) { auto Edge = std::make_pair(Cell.getRowKey(), Cell.getColumnKey()); - std::string N1Label = IDEProblem.NtoString(Edge.first); - std::string N2Label = IDEProblem.NtoString(Edge.second); + std::string N1Label = NToString(Edge.first); + std::string N2Label = NToString(Edge.second); std::string FNameOfN1 = ICF->getFunctionOf(Edge.first)->getName().str(); std::string FNameOfN2 = ICF->getFunctionOf(Edge.second)->getName().str(); std::string N1StmtId = ICF->getStatementId(Edge.first); @@ -1573,14 +1551,14 @@ class IDESolver unsigned D2FactId = 0; for (const auto &D1ToD2Set : Cell.getValue()) { auto D1Fact = D1ToD2Set.first; - PHASAR_LOG_LEVEL(DEBUG, "d1: " << IDEProblem.DtoString(D1Fact)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(D1Fact)); DOTNode D1; if (IDEProblem.isZeroValue(D1Fact)) { D1 = {FNameOfN1, "Λ", N1StmtId, 0, false, true}; } else { // Get the fact-ID D1FactId = G.getFactID(D1Fact); - std::string D1Label = IDEProblem.DtoString(D1Fact); + std::string D1Label = DToString(D1Fact); D1 = {FNameOfN1, D1Label, N1StmtId, D1FactId, false, true}; // FG should already exist even for single statement functions if (!G.containsFactSG(FNameOfN1, D1FactId)) { @@ -1592,14 +1570,14 @@ class IDESolver auto D2Set = D1ToD2Set.second; for (const auto &D2Fact : D2Set) { - PHASAR_LOG_LEVEL(DEBUG, "d2: " << IDEProblem.DtoString(D2Fact)); + PHASAR_LOG_LEVEL(DEBUG, "d2: " << DToString(D2Fact)); DOTNode D2; if (IDEProblem.isZeroValue(D2Fact)) { D2 = {FNameOfN2, "Λ", N2StmtId, 0, false, true}; } else { // Get the fact-ID D2FactId = G.getFactID(D2Fact); - std::string D2Label = IDEProblem.DtoString(D2Fact); + std::string D2Label = DToString(D2Fact); D2 = {FNameOfN2, D2Label, N2StmtId, D2FactId, false, true}; // FG should already exist even for single statement functions if (!G.containsFactSG(FNameOfN2, D2FactId)) { diff --git a/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h index 6bb2c6ffa..0a9bcb327 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h @@ -17,7 +17,7 @@ #ifndef PHASAR_DATAFLOW_IFDSIDE_SOLVER_JUMPFUNCTIONS_H #define PHASAR_DATAFLOW_IFDSIDE_SOLVER_JUMPFUNCTIONS_H -#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/Table.h" @@ -43,9 +43,6 @@ template class JumpFunctions { using d_t = typename AnalysisDomainTy::d_t; using n_t = typename AnalysisDomainTy::n_t; -private: - const IDETabulationProblem &Problem; - protected: // mapping from target node and value to a list of all source values and // associated functions where the list is implemented as a mapping from @@ -64,10 +61,7 @@ template class JumpFunctions { NonEmptyLookupByTargetNode; public: - JumpFunctions( - const IDETabulationProblem &Problem) - : Problem(Problem) {} - + JumpFunctions() noexcept = default; ~JumpFunctions() = default; JumpFunctions(const JumpFunctions &JFs) = default; @@ -82,11 +76,9 @@ template class JumpFunctions { void addFunction(d_t SourceVal, n_t Target, d_t TargetVal, EdgeFunction EdgeFunc) { PHASAR_LOG_LEVEL(DEBUG, "Start adding new jump function"); - PHASAR_LOG_LEVEL(DEBUG, - "Fact at source : " << Problem.DtoString(SourceVal)); - PHASAR_LOG_LEVEL(DEBUG, - "Fact at target : " << Problem.DtoString(TargetVal)); - PHASAR_LOG_LEVEL(DEBUG, "Destination : " << Problem.NtoString(Target)); + PHASAR_LOG_LEVEL(DEBUG, "Fact at source : " << DToString(SourceVal)); + PHASAR_LOG_LEVEL(DEBUG, "Fact at target : " << DToString(TargetVal)); + PHASAR_LOG_LEVEL(DEBUG, "Destination : " << NToString(Target)); PHASAR_LOG_LEVEL(DEBUG, "Edge Function : " << EdgeFunc); // we do not store the default function (all-top) if (llvm::isa>(EdgeFunc)) { @@ -207,12 +199,12 @@ template class JumpFunctions { OS << "\n* Print all Jump Functions *"; OS << "\n******************************************************\n"; for (auto &Entry : NonEmptyLookupByTargetNode) { - std::string NLabel = Problem.NtoString(Entry.first); + std::string NLabel = NToString(Entry.first); OS << "\nN: " << NLabel << "\n---" << std::string(NLabel.size(), '-') << '\n'; for (auto Cell : Entry.second.cellSet()) { - OS << "D1: " << Problem.DtoString(Cell.r) << '\n' - << "\tD2: " << Problem.DtoString(Cell.c) << '\n' + OS << "D1: " << DToString(Cell.r) << '\n' + << "\tD2: " << DToString(Cell.c) << '\n' << "\tEF: " << Cell.v << "\n\n"; } } @@ -223,11 +215,11 @@ template class JumpFunctions { "EdgeFunctionPtrType>>\n"; auto CellVec = NonEmptyReverseLookup.cellVec(); for (auto Cell : CellVec) { - OS << "N : " << Problem.NtoString(Cell.r) - << "\nD1: " << Problem.DtoString(Cell.c) << '\n'; + OS << "N : " << NToString(Cell.r) << "\nD1: " << DToString(Cell.c) + << '\n'; for (auto D2ToEF : Cell.v) { - OS << "D2: " << Problem.DtoString(D2ToEF.first) - << "\nEF: " << D2ToEF.second << '\n'; + OS << "D2: " << DToString(D2ToEF.first) << "\nEF: " << D2ToEF.second + << '\n'; } OS << '\n'; } @@ -238,11 +230,11 @@ template class JumpFunctions { "EdgeFunctionPtrType>>\n"; auto CellVec = NonEmptyForwardLookup.cellVec(); for (auto Cell : CellVec) { - OS << "D1: " << Problem.DtoString(Cell.r) - << "\nN : " << Problem.NtoString(Cell.c) << '\n'; + OS << "D1: " << DToString(Cell.r) << "\nN : " << NToString(Cell.c) + << '\n'; for (auto D2ToEF : Cell.v) { - OS << "D2: " << Problem.DtoString(D2ToEF.first) - << "\nEF: " << D2ToEF.second << '\n'; + OS << "D2: " << DToString(D2ToEF.first) << "\nEF: " << D2ToEF.second + << '\n'; } OS << '\n'; } @@ -252,13 +244,12 @@ template class JumpFunctions { OS << "DUMP nonEmptyLookupByTargetNode\nstd::unordered_map>\n"; for (auto Node : NonEmptyLookupByTargetNode) { - OS << "\nN : " << Problem.NtoString(Node.first) << '\n'; + OS << "\nN : " << NToString(Node.first) << '\n'; auto Table = NonEmptyLookupByTargetNode[Node.first]; auto CellVec = Table.cellVec(); for (auto Cell : CellVec) { - OS << "D1: " << Problem.DtoString(Cell.r) - << "\nD2: " << Problem.DtoString(Cell.c) << "\nEF: " << Cell.v - << '\n'; + OS << "D1: " << DToString(Cell.r) << "\nD2: " << DToString(Cell.c) + << "\nEF: " << Cell.v << '\n'; } OS << '\n'; } diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 780f1ea6f..512d80063 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -131,9 +131,7 @@ class SolverResultsBase { } template - void dumpResults(const ICFGTy &ICF, const NodePrinterBase &NP, - const DataFlowFactPrinterBase &DP, - const EdgeFactPrinterBase &LP, + void dumpResults(const ICFGTy &ICF, llvm::raw_ostream &OS = llvm::outs()) const { using f_t = typename ICFGTy::f_t; @@ -170,24 +168,18 @@ class SolverResultsBase { } if (Prev != Curr) { Prev = Curr; - std::string NString = NP.NtoString(Curr); + std::string NString = NToString(Curr); std::string Line(NString.size(), '-'); OS << "\n\nN: " << NString << "\n---" << Line << '\n'; } - OS << "\tD: " << DP.DtoString(Cells[I].getColumnKey()) - << " | V: " << LP.LtoString(Cells[I].getValue()) << '\n'; + OS << "\tD: " << DToString(Cells[I].getColumnKey()) + << " | V: " << LToString(Cells[I].getValue()) << '\n'; } } OS << '\n'; STOP_TIMER("DFA IDE Result Dumping", Full); } - template - void dumpResults(const ICFGTy &ICF, const ProblemTy &IDEProblem, - llvm::raw_ostream &OS = llvm::outs()) const { - dumpResults(ICF, IDEProblem, IDEProblem, IDEProblem, OS); - } - private: [[nodiscard]] const Derived &self() const noexcept { static_assert(std::is_base_of_v); diff --git a/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h b/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h index ae813f39f..2e835c6f5 100644 --- a/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h +++ b/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h @@ -68,11 +68,10 @@ template class CallStringCTX { return Lhs.cs < Rhs.cs; } - llvm::raw_ostream &print(llvm::raw_ostream &OS, - const NodePrinterBase &NP) const { + llvm::raw_ostream &print(llvm::raw_ostream &OS) const { OS << "Call string: [ "; for (auto C : CallString) { - NP.printNode(OS, C); + OS << NToString(C); if (C != CallString.back()) { OS << " * "; } diff --git a/include/phasar/DataFlow/Mono/IntraMonoProblem.h b/include/phasar/DataFlow/Mono/IntraMonoProblem.h index 8405d2030..4915cfe4f 100644 --- a/include/phasar/DataFlow/Mono/IntraMonoProblem.h +++ b/include/phasar/DataFlow/Mono/IntraMonoProblem.h @@ -35,10 +35,7 @@ struct HasNoConfigurationType; template class TypeHierarchy; template class CFG; -template -class IntraMonoProblem : public NodePrinter, - public DataFlowFactPrinter, - public FunctionPrinter { +template class IntraMonoProblem { public: using n_t = typename AnalysisDomainTy::n_t; using d_t = typename AnalysisDomainTy::d_t; @@ -72,7 +69,7 @@ class IntraMonoProblem : public NodePrinter, : IRDB(IRDB), TH(TH), CF(CF), PT(PT), EntryPoints(std::move(EntryPoints)) {} - ~IntraMonoProblem() override = default; + virtual ~IntraMonoProblem() = default; virtual mono_container_t normalFlow(n_t Inst, const mono_container_t &In) = 0; diff --git a/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h index b8785ebe0..518d80c7d 100644 --- a/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h +++ b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h @@ -85,8 +85,7 @@ template class InterMonoSolver { void printWorkList() { llvm::outs() << "CURRENT WORKLIST:\n"; for (auto &[Src, Dst] : Worklist) { - llvm::outs() << IMProblem.NtoString(Src) << " --> " - << IMProblem.NtoString(Dst) << '\n'; + llvm::outs() << NToString(Src) << " --> " << NToString(Dst) << '\n'; } llvm::outs() << "-----------------\n"; } @@ -178,8 +177,8 @@ template class InterMonoSolver { llvm::outs() << "Handle normal flow\n"; auto Src = Edge.first; auto Dst = Edge.second; - llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; - llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; + llvm::outs() << "Src: " << NToString(Src) << '\n'; + llvm::outs() << "Dst: " << NToString(Dst) << '\n'; std::unordered_map, mono_container_t> Out; for (auto &[Ctx, Facts] : Analysis[Src]) { Out[Ctx] = IMProblem.normalFlow(Src, Analysis[Src][Ctx]); @@ -224,8 +223,8 @@ template class InterMonoSolver { std::unordered_map, mono_container_t> Out; if (!isIntraEdge(Edge)) { llvm::outs() << "Handle call flow\n"; - llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; - llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; + llvm::outs() << "Src: " << NToString(Src) << '\n'; + llvm::outs() << "Dst: " << NToString(Dst) << '\n'; for (auto &[Ctx, Facts] : Analysis[Src]) { auto CTXAdd(Ctx); CTXAdd.push_back(Src); @@ -253,8 +252,8 @@ template class InterMonoSolver { } else { // Handle call-to-ret flow llvm::outs() << "Handle call to ret flow\n"; - llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; - llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; + llvm::outs() << "Src: " << NToString(Src) << '\n'; + llvm::outs() << "Dst: " << NToString(Dst) << '\n'; for (auto &[Ctx, Facts] : Analysis[Src]) { // call-to-ret flow does not modify contexts Out[Ctx] = IMProblem.callToRetFlow( @@ -288,11 +287,11 @@ template class InterMonoSolver { std::unordered_map, mono_container_t> Out; llvm::outs() << "\nHandle ret flow in: " << ICF->getFunctionName(ICF->getFunctionOf(Src)) << '\n'; - llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; - llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; + llvm::outs() << "Src: " << NToString(Src) << '\n'; + llvm::outs() << "Dst: " << NToString(Dst) << '\n'; for (auto &[Ctx, Facts] : Analysis[Src]) { auto CTXRm(Ctx); - CTXRm.print(llvm::outs() << "CTXRm: ", IMProblem) << '\n'; + CTXRm.print(llvm::outs() << "CTXRm: ") << '\n'; // we need to use several call- and retsites if the context is empty llvm::SmallVector CallSites; @@ -319,7 +318,7 @@ template class InterMonoSolver { // TODO! llvm::outs() << "ResSites.size(): " << RetSites.size() << '\n'; for (auto RetSite : RetSites) { - llvm::outs() << "RetSite: " << IMProblem.NtoString(RetSite) << '\n'; + llvm::outs() << "RetSite: " << NToString(RetSite) << '\n'; llvm::outs() << "Return facts: "; IMProblem.printContainer(llvm::outs(), Out[CTXRm]); llvm::outs() << '\n'; @@ -402,19 +401,17 @@ template class InterMonoSolver { virtual void dumpResults(llvm::raw_ostream &OS = llvm::outs()) { OS << "======= DUMP LLVM-INTER-MONOTONE-SOLVER RESULTS =======\n"; for (auto &[Node, ContextMap] : this->Analysis) { - OS << "Instruction:\n" << IMProblem.NtoString(Node); + OS << "Instruction:\n" << NToString(Node); OS << "\nFacts:\n"; if (ContextMap.empty()) { OS << "\tEMPTY\n"; } else { for (auto &[Context, FlowFacts] : ContextMap) { - Context.print(OS, IMProblem) << '\n'; + Context.print(OS) << '\n'; if (FlowFacts.empty()) { OS << "\tEMPTY\n"; } else { - for (auto FlowFact : FlowFacts) { - OS << IMProblem.DtoString(FlowFact); - } + IMProblem.printContainer(OS, FlowFacts); } } } diff --git a/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h b/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h index 53c26627c..ac46b9068 100644 --- a/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h +++ b/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h @@ -115,14 +115,12 @@ template class IntraMonoSolver { OS << "Intra-Monotone solver results:\n" "------------------------------\n"; for (auto &[Node, FlowFacts] : this->Analysis) { - OS << "Instruction:\n" << this->IMProblem.NtoString(Node); + OS << "Instruction:\n" << NToString(Node); OS << "\nFacts:\n"; if (FlowFacts.empty()) { OS << "\tEMPTY\n"; } else { - for (auto FlowFact : FlowFacts) { - OS << this->IMProblem.DtoString(FlowFact) << '\n'; - } + IMProblem.printContainer(OS, FlowFacts); } OS << "\n\n"; } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index 8a9979b52..e2ba69e2d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -260,14 +260,6 @@ class IDEExtendedTaintAnalysis // Printing functions - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printEdgeFact(llvm::raw_ostream &OS, l_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override; - void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h index 26ea81ca7..9461ff4f2 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h @@ -106,14 +106,6 @@ class IDEGeneralizedLCA : public IDETabulationProblem { EdgeFunction allTopFunction() override; - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - - void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; - // void printIDEReport(llvm::raw_ostream &OS, // SolverResults &SR) override; void emitTextReport(const SolverResults &SR, @@ -127,7 +119,6 @@ class IDEGeneralizedLCA : public IDETabulationProblem { void stripBottomResults(std::unordered_map &Res); [[nodiscard]] bool isEntryPoint(const std::string &Name) const; - template std::string VtoString(V Val); // NOLINT bool isStringConstructor(const llvm::Function *Func); }; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index ca75d1c12..207c9bdbe 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -1135,23 +1135,6 @@ class IDEInstInteractionAnalysisT // Provide functionalities for printing things and emitting text reports. - void printNode(llvm::raw_ostream &OS, n_t n) const override { - OS << llvmIRToString(n); - } - - void printDataFlowFact(llvm::raw_ostream &OS, d_t FlowFact) const override { - OS << llvmIRToString(FlowFact); - } - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override { - OS << Fun->getName(); - } - - inline void printEdgeFact(llvm::raw_ostream &OS, - l_t EdgeFact) const override { - printEdgeFactImpl(OS, EdgeFact); - } - static void stripBottomResults(std::unordered_map &Res) { for (auto It = Res.begin(); It != Res.end();) { if (It->second.isBottom()) { @@ -1178,11 +1161,11 @@ class IDEInstInteractionAnalysisT auto Results = SR.resultsAt(Inst, true); stripBottomResults(Results); if (!Results.empty()) { - OS << "At IR statement: " << this->NtoString(Inst) << '\n'; + OS << "At IR statement: " << NToString(Inst) << '\n'; for (auto Result : Results) { if (!Result.second.isBottom()) { - OS << " Fact: " << this->DtoString(Result.first) - << "\n Value: " << this->LtoString(Result.second) << '\n'; + OS << " Fact: " << DToString(Result.first) + << "\n Value: " << LToString(Result.second) << '\n'; } } OS << '\n'; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h index 14e84327c..d84f491cc 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -121,14 +121,6 @@ class IDELinearConstantAnalysis // Helper functions - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - - void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; - [[nodiscard]] lca_results_t getLCAResults(SolverResults SR); void emitTextReport(const SolverResults &SR, diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h index 9c25256ff..d4927219e 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h @@ -97,14 +97,6 @@ class IDEProtoAnalysis : public IDETabulationProblem { l_t join(l_t Lhs, l_t Rhs) override; EdgeFunction allTopFunction() override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - - void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h index 51663d05c..a41352335 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h @@ -11,6 +11,7 @@ #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "llvm/ADT/StringRef.h" @@ -82,12 +83,6 @@ class IDESecureHeapPropagation [[nodiscard]] bool isZeroValue(d_t Fact) const override; - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - // in addition provide specifications for the IDE parts EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, @@ -118,11 +113,12 @@ class IDESecureHeapPropagation EdgeFunction allTopFunction() override; - void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; - void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS) override; }; + +llvm::StringRef DToString(SecureHeapFact Fact) noexcept; +llvm::StringRef LToString(SecureHeapValue Val) noexcept; } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h index cceb38a9d..2bc92e9db 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h @@ -98,14 +98,6 @@ class IDESolverTest : public IDETabulationProblem { l_t join(l_t Lhs, l_t Rhs) override; EdgeFunction allTopFunction() override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - - void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 9339ef91f..475e18ead 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -10,38 +10,137 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" - -#include "llvm/IR/InstrTypes.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/Logger.h" +#include "phasar/Utils/Printer.h" +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Demangle/Demangle.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Value.h" #include #include #include +#include #include -namespace llvm { -class CallBase; -class Instruction; -class Function; -class Value; -} // namespace llvm - namespace psr { class LLVMBasedICFG; class LLVMTypeHierarchy; -struct TypeStateDescription; +namespace detail { +class IDETypeStateAnalysisBase { +public: + virtual ~IDETypeStateAnalysisBase() = default; + +protected: + IDETypeStateAnalysisBase(LLVMAliasInfoRef PT) noexcept : PT(PT) {} + + using d_t = const llvm::Value *; + using n_t = const llvm::Instruction *; + using f_t = const llvm::Function *; + using container_type = std::set; + using FlowFunctionPtrType = FlowFunctionPtrType; + + // --- Flow Functions + + FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ); + FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun); + FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, + n_t ExitStmt, n_t RetSite); + FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees); + FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun); + + // --- Utilities + + [[nodiscard]] virtual bool + isAPIFunction(llvm::StringRef Name) const noexcept = 0; + [[nodiscard]] virtual bool + isFactoryFunction(llvm::StringRef Name) const noexcept = 0; + [[nodiscard]] virtual bool + isTypeNameOfInterest(llvm::StringRef Name) const noexcept = 0; + + /** + * @brief Returns all alloca's that are (indirect) aliases of V. + * + * Currently PhASAR's points-to information does not include alloca + * instructions, since alloca instructions, i.e. memory locations, are of + * type T* for a target type T. Thus they do not alias directly. Therefore, + * for each alias of V we collect related alloca instructions by checking + * load and store instructions for used alloca's. + */ + container_type getRelevantAllocas(d_t V); + + /** + * @brief Returns whole-module aliases of V. + * + * This function retrieves whole-module points-to information. We store + * already computed points-to information in a cache to prevent expensive + * recomputation since the whole module points-to graph can be huge. This + * might become unnecessary once PhASAR's AliasGraph starts using a cache + * itself. + */ + container_type getWMAliasSet(d_t V); + + /** + * @brief Provides whole module aliases and relevant alloca's of V. + */ + container_type getWMAliasesAndAllocas(d_t V); + + /** + * @brief Provides local aliases and relevant alloca's of V. + */ + container_type getLocalAliasesAndAllocas(d_t V, llvm::StringRef Fname); + + /** + * @brief Checks if the type machtes the type of interest. + */ + bool hasMatchingType(d_t V); + +private: + FlowFunctionPtrType generateFromZero(d_t FactToGenerate) { + return generateFlow(FactToGenerate, LLVMZeroValue::getInstance()); + } + + bool hasMatchingTypeName(const llvm::Type *Ty); + + std::map AliasCache; + LLVMAliasInfoRef PT{}; + std::map> + RelevantAllocaCache; +}; +} // namespace detail + +template struct IDETypeStateAnalysisDomain : public LLVMAnalysisDomainDefault { - using l_t = int; + using l_t = typename TypeStateDescriptionTy::State; }; +template class IDETypeStateAnalysis - : public IDETabulationProblem { + : public IDETabulationProblem< + IDETypeStateAnalysisDomain>, + private detail::IDETypeStateAnalysisBase { public: - using IDETabProblemType = IDETabulationProblem; + using IDETabProblemType = + IDETabulationProblem>; + using typename IDETabProblemType::container_type; using typename IDETabProblemType::d_t; using typename IDETabProblemType::f_t; using typename IDETabProblemType::i_t; @@ -50,61 +149,317 @@ class IDETypeStateAnalysis using typename IDETabProblemType::t_t; using typename IDETabProblemType::v_t; - using ConfigurationTy = TypeStateDescription; + using typename IDETabProblemType::FlowFunctionPtrType; + using ConfigurationTy = TypeStateDescriptionTy; + +private: + static AllBottom + makeAllBottom(const TypeStateDescriptionTy *TSD) noexcept { + if constexpr (HasJoinLatticeTraits) { + return AllBottom{}; + } else { + return AllBottom{TSD->bottom()}; + } + } + template >> + static AllBottom makeAllBottom(EmptyType /*unused*/) noexcept { + return AllBottom{}; + } + static bool isBottom(l_t State, const TypeStateDescriptionTy *TSD) noexcept { + if constexpr (HasJoinLatticeTraits) { + return State == JoinLatticeTraits::bottom(); + } else { + return State == TSD->bottom(); + } + } + template >> + static bool isBottom(l_t State, EmptyType /*unused*/) noexcept { + return State == JoinLatticeTraits::bottom(); + } + + struct TSEdgeFunctionComposer : EdgeFunctionComposer { + TSEdgeFunctionComposer(EdgeFunction First, EdgeFunction Second, + const TypeStateDescriptionTy *TSD) noexcept + : EdgeFunctionComposer{std::move(First), std::move(Second)} { + if constexpr (!HasJoinLatticeTraits) { + BotElement = TSD->bottom(); + } + } + + [[no_unique_address]] std::conditional_t, + EmptyType, l_t> + BotElement{}; + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + if constexpr (HasJoinLatticeTraits) { + return AllBottom{}; + } else { + return AllBottom{This->BotElement}; + } + } + }; + + struct TSEdgeFunction { + using l_t = l_t; + const TypeStateDescriptionTy *TSD{}; + // XXX: Do we really need a string here? Can't we just use an integer or sth + // else that is cheap? + std::string Token; + const llvm::CallBase *CallSite{}; + + [[nodiscard]] l_t computeTarget(l_t Source) const { + + // assert((Source != TSD->top()) && "Error: call computeTarget with + // TOP\n"); + + auto CurrentState = TSD->getNextState( + Token, Source == TSD->top() ? TSD->uninit() : Source, CallSite); + PHASAR_LOG_LEVEL(DEBUG, "State machine transition: (" + << Token << " , " << LToString(Source) + << ") -> " << LToString(CurrentState)); + return CurrentState; + } + + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + return TSEdgeFunctionComposer{This, SecondFunction, This->TSD}; + } + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + + return makeAllBottom(This->TSD); + } + + bool operator==(const TSEdgeFunction &Other) const { + return CallSite == Other.CallSite && Token == Other.Token; + } + + friend llvm::raw_ostream &print(llvm::raw_ostream &OS, + const TSEdgeFunction &TSE) { + return OS << "TSEF(" << TSE.Token << " at " + << llvmIRToShortString(TSE.CallSite) << ")"; + } + }; + + struct TSConstant : ConstantEdgeFunction { + std::conditional_t, EmptyType, + const TypeStateDescriptionTy *> + TSD{}; + + TSConstant(l_t Value, const TypeStateDescriptionTy *TSD) noexcept + : ConstantEdgeFunction{Value} { + if constexpr (!HasJoinLatticeTraits) { + this->TSD = TSD; + } + } + + template >> + TSConstant(l_t Value, EmptyType /*unused*/ = {}) noexcept + : ConstantEdgeFunction{Value} { + if constexpr (!HasJoinLatticeTraits) { + this->TSD = TSD; + } + } + + /// XXX: Cannot default compose() and join(), because l_t does not implement + /// JoinLatticeTraits (because bottom value is not constant) + template + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + l_t Ret = SecondFunction.computeTarget(This->Value); + if (Ret == This->Value) { + return This; + } + if (isBottom(Ret, This->TSD)) { + return makeAllBottom(This->TSD); + } + + return TSConstant{Ret, This->TSD}; + } + + template + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + + auto Top = [TSD = This->TSD] { + if constexpr (HasJoinLatticeTraits) { + return JoinLatticeTraits::top(); + } else { + return TSD->top(); + } + }(); + if (const auto *C = llvm::dyn_cast(OtherFunction)) { + if (C->Value == This->Value || C->Value == Top) { + return This; + } + if (This->Value == Top) { + return OtherFunction; + } + } + return makeAllBottom(This->TSD); + } + + bool operator==(const TSConstant &Other) const noexcept { + return this->Value == Other.Value; + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const TSConstant &EF) { + return OS << "TSConstant[" << LToString(EF.Value) << "]"; + } + }; +public: IDETypeStateAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT, - const TypeStateDescription *TSD, - std::vector EntryPoints = {"main"}); + const TypeStateDescriptionTy *TSD, + std::vector EntryPoints = {"main"}) + : IDETabProblemType(IRDB, std::move(EntryPoints), createZeroValue()), + IDETypeStateAnalysisBase(PT), TSD(TSD) { + assert(TSD != nullptr); + assert(PT); + } ~IDETypeStateAnalysis() override = default; // start formulating our analysis by specifying the parts required for IFDS - FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override; + FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override { + return detail::IDETypeStateAnalysisBase::getNormalFlowFunction(Curr, Succ); + } - FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override; + FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override { + return detail::IDETypeStateAnalysisBase::getCallFlowFunction(CallSite, + DestFun); + } FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, - n_t ExitStmt, n_t RetSite) override; + n_t ExitStmt, n_t RetSite) override { + + return detail::IDETypeStateAnalysisBase::getRetFlowFunction( + CallSite, CalleeFun, ExitStmt, RetSite); + } FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - llvm::ArrayRef Callees) override; + llvm::ArrayRef Callees) override { + return detail::IDETypeStateAnalysisBase::getCallToRetFlowFunction( + CallSite, RetSite, Callees); + } FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, - f_t DestFun) override; + f_t DestFun) override { + return detail::IDETypeStateAnalysisBase::getSummaryFlowFunction(CallSite, + DestFun); + } - InitialSeeds initialSeeds() override; + InitialSeeds initialSeeds() override { + return this->createDefaultSeeds(); + } - [[nodiscard]] d_t createZeroValue() const; + [[nodiscard]] d_t createZeroValue() const { + return LLVMZeroValue::getInstance(); + } - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const override { + return LLVMZeroValue::isLLVMZeroValue(Fact); + } // in addition provide specifications for the IDE parts - EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode) override; - - EdgeFunction getCallEdgeFunction(n_t CallSite, d_t SrcNode, - f_t DestinationFunction, - d_t DestNode) override; - - EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, - n_t ExitInst, d_t ExitNode, - n_t RetSite, d_t RetNode) override; + EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t /*Succ*/, + d_t SuccNode) override { + // Set alloca instructions of target type to uninitialized. + if (const auto *Alloca = llvm::dyn_cast(Curr)) { + if (hasMatchingType(Alloca)) { + if (LLVMZeroValue::isLLVMZeroValue(CurrNode) && SuccNode == Alloca) { + return TSConstant(TSD->uninit(), TSD); + } + } + } + return EdgeIdentity{}; + } + + EdgeFunction getCallEdgeFunction(n_t /*CallSite*/, d_t /*SrcNode*/, + f_t /*DestinationFunction*/, + d_t /*DestNode*/) override { + return EdgeIdentity{}; + } + + EdgeFunction getReturnEdgeFunction(n_t /*CallSite*/, + f_t /*CalleeFunction*/, + n_t /*ExitInst*/, d_t /*ExitNode*/, + n_t /*RetSite*/, + d_t /*RetNode*/) override { + return EdgeIdentity{}; + } EdgeFunction - getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, + getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t /*RetSite*/, d_t RetSiteNode, - llvm::ArrayRef Callees) override; - - EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, - n_t RetSite, - d_t RetSiteNode) override; - - l_t topElement() override; - - l_t bottomElement() override; + llvm::ArrayRef Callees) override { + const auto *CS = llvm::cast(CallSite); + for (const auto *Callee : Callees) { + std::string DemangledFname = llvm::demangle(Callee->getName().str()); + + // For now we assume that we can only generate from the return value. + // We apply the same edge function for the return value, i.e. callsite. + if (TSD->isFactoryFunction(DemangledFname)) { + PHASAR_LOG_LEVEL(DEBUG, "Processing factory function"); + if (isZeroValue(CallNode) && RetSiteNode == CS) { + return TSConstant{ + TSD->getNextState(DemangledFname, TSD->uninit(), CS), TSD}; + } + } + + // For every consuming parameter and all its aliases and relevant alloca's + // we apply the same edge function. + if (TSD->isConsumingFunction(DemangledFname)) { + PHASAR_LOG_LEVEL(DEBUG, "Processing consuming function"); + for (auto Idx : TSD->getConsumerParamIdx(DemangledFname)) { + const auto &AliasAndAllocas = + getWMAliasesAndAllocas(CS->getArgOperand(Idx)); + + if (CallNode == RetSiteNode && AliasAndAllocas.count(CallNode)) { + return TSEdgeFunction{TSD, DemangledFname, CS}; + } + } + } + } + return EdgeIdentity{}; + } + + EdgeFunction getSummaryEdgeFunction(n_t /*CallSite*/, d_t /*CallNode*/, + n_t /*RetSite*/, + d_t /*RetSiteNode*/) override { + return nullptr; + } + + l_t topElement() override { return TSD->top(); } + + l_t bottomElement() override { return TSD->bottom(); } /** * We have a lattice with BOTTOM representing all information @@ -114,65 +469,124 @@ class IDETypeStateAnalysis * * @note Only one-level lattice's are handled currently */ - l_t join(l_t Lhs, l_t Rhs) override; - - EdgeFunction allTopFunction() override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - - void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; + l_t join(l_t Lhs, l_t Rhs) override { + if (Lhs == Rhs) { + return Lhs; + } + if (Lhs == TSD->top()) { + return Rhs; + } + if (Rhs == TSD->top()) { + return Lhs; + } + return TSD->bottom(); + } + + EdgeFunction allTopFunction() override { + if constexpr (HasJoinLatticeTraits) { + return AllTop{}; + } else { + return AllTop{topElement()}; + } + } + + [[nodiscard]] bool + isAPIFunction(llvm::StringRef Name) const noexcept override { + return TSD->isAPIFunction(Name); + } + + [[nodiscard]] bool + isFactoryFunction(llvm::StringRef Name) const noexcept override { + return TSD->isFactoryFunction(Name); + } + + [[nodiscard]] bool + isTypeNameOfInterest(llvm::StringRef Name) const noexcept override { + return Name.contains(TSD->getTypeNameOfInterest()); + } void emitTextReport(const SolverResults &SR, - llvm::raw_ostream &OS = llvm::outs()) override; + llvm::raw_ostream &OS = llvm::outs()) override { + LLVMBasedCFG CFG; + OS << "\n======= TYPE STATE RESULTS =======\n"; + for (const auto &F : this->IRDB->getAllFunctions()) { + OS << '\n' << F->getName() << '\n'; + for (const auto &BB : *F) { + for (const auto &I : BB) { + auto Results = SR.resultsAt(&I, true); + if (CFG.isExitInst(&I)) { + OS << "\nAt exit stmt: " << NToString(&I) << '\n'; + for (auto Res : Results) { + if (const auto *Alloca = + llvm::dyn_cast(Res.first)) { + if (Res.second == TSD->error()) { + OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " + << DToString(Res.first) << '\n'; + for (const auto *Pred : CFG.getPredsOf(&I)) { + OS << "\nPredecessor: " << NToString(Pred) << '\n'; + auto PredResults = SR.resultsAt(Pred, true); + for (auto Res : PredResults) { + if (Res.first == Alloca) { + OS << "Pred State: " << LToString(Res.second) << '\n'; + } + } + } + OS << "============================\n"; + } else { + OS << "\nAlloca : " << DToString(Res.first) + << "\nState : " << LToString(Res.second) << '\n'; + } + } else { + OS << "\nInst: " << NToString(&I) << '\n' + << "Fact: " << DToString(Res.first) << '\n' + << "State: " << LToString(Res.second) << '\n'; + } + } + } else { + for (auto Res : Results) { + if (const auto *Alloca = + llvm::dyn_cast(Res.first)) { + if (Res.second == TSD->error()) { + OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " + << DToString(Res.first) << '\n' + << "\nAt IR Inst: " << NToString(&I) << '\n'; + for (const auto *Pred : CFG.getPredsOf(&I)) { + OS << "\nPredecessor: " << NToString(Pred) << '\n'; + auto PredResults = SR.resultsAt(Pred, true); + for (auto Res : PredResults) { + if (Res.first == Alloca) { + OS << "Pred State: " << LToString(Res.second) << '\n'; + } + } + } + OS << "============================\n"; + } + } else { + OS << "\nInst: " << NToString(&I) << '\n' + << "Fact: " << DToString(Res.first) << '\n' + << "State: " << LToString(Res.second) << '\n'; + } + } + } + } + } + OS << "\n--------------------------------------------\n"; + } + } private: - const TypeStateDescription *TSD{}; - std::map AliasCache; - LLVMAliasInfoRef PT{}; - std::map> - RelevantAllocaCache; - - /** - * @brief Returns all alloca's that are (indirect) aliases of V. - * - * Currently PhASAR's points-to information does not include alloca - * instructions, since alloca instructions, i.e. memory locations, are of - * type T* for a target type T. Thus they do not alias directly. Therefore, - * for each alias of V we collect related alloca instructions by checking - * load and store instructions for used alloca's. - */ - std::set getRelevantAllocas(d_t V); - - /** - * @brief Returns whole-module aliases of V. - * - * This function retrieves whole-module points-to information. We store - * already computed points-to information in a cache to prevent expensive - * recomputation since the whole module points-to graph can be huge. This - * might become unnecessary once PhASAR's AliasGraph starts using a cache - * itself. - */ - std::set getWMAliasSet(d_t V); + const TypeStateDescriptionTy *TSD{}; +}; - /** - * @brief Provides whole module aliases and relevant alloca's of V. - */ - std::set getWMAliasesAndAllocas(d_t V); +template +IDETypeStateAnalysis(const LLVMProjectIRDB *, LLVMAliasInfoRef, + const TypeStateDescriptionTy *, + std::vector EntryPoints) + -> IDETypeStateAnalysis; - /** - * @brief Provides local aliases and relevant alloca's of V. - */ - std::set getLocalAliasesAndAllocas(d_t V, const std::string &Fname); +// class CSTDFILEIOTypeStateDescription; - /** - * @brief Checks if the type machtes the type of interest. - */ - bool hasMatchingType(d_t V); -}; +// extern template class IDETypeStateAnalysis; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h index 4f11609a4..0d4585614 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h @@ -144,12 +144,6 @@ class IFDSConstAnalysis [[nodiscard]] bool isZeroValue(d_t Fact) const override; - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h index 62dcd7eb5..fc0f52a9a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h @@ -85,41 +85,14 @@ class IFDSFieldSensTaintAnalysis return LLVMZeroValue::isLLVMZeroValue(EV.getValue()); } - void printNode(llvm::raw_ostream &OS, - const llvm::Instruction *Stmt) const override { - OS << llvmIRToString(Stmt); - } - - void printDataFlowFact(llvm::raw_ostream &OS, - ExtendedValue EV) const override { - OS << llvmIRToString(EV.getValue()) << "\n"; - for (const auto *MemLocationPart : EV.getMemLocationSeq()) { - OS << "A:\t" << llvmIRToString(MemLocationPart) << "\n"; - } - if (!EV.getEndOfTaintedBlockLabel().empty()) { - OS << "L:\t" << EV.getEndOfTaintedBlockLabel() << "\n"; - } - if (EV.isVarArg()) { - OS << "VT:\t" << EV.isVarArgTemplate() << "\n"; - for (const auto *VAListMemLocationPart : EV.getVaListMemLocationSeq()) { - OS << "VLA:\t" << llvmIRToString(VAListMemLocationPart) << "\n"; - } - OS << "VI:\t" << EV.getVarArgIndex() << "\n"; - OS << "CI:\t" << EV.getCurrentVarArgIndex() << "\n"; - } - } - - void printFunction(llvm::raw_ostream &OS, - const llvm::Function *Func) const override { - OS << Func->getName(); - } - private: const LLVMTaintConfig *Config{}; TraceStats Stats{}; }; +std::string DToString(const ExtendedValue &EV); + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h index 16d7b1c59..9e3e43769 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h @@ -53,12 +53,6 @@ class IFDSProtoAnalysis [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h index 67dae0c90..5575275c4 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h @@ -54,12 +54,6 @@ class IFDSSignAnalysis [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h index 25b7c28a5..8099e5184 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h @@ -52,12 +52,6 @@ class IFDSSolverTest [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h index 9df7cf69b..49479bc1e 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -79,12 +79,6 @@ class IFDSTaintAnalysis bool isZeroValue(d_t FlowFact) const override; - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t FlowFact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override; - void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h index 9c4b55c9d..3f9edcfe8 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h @@ -45,12 +45,6 @@ class IFDSTypeAnalysis [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h index 24e07c8ff..ee81523e0 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h @@ -62,12 +62,6 @@ class IFDSUninitializedVariables [[nodiscard]] bool isZeroValue(d_t Fact) const override; - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - void emitTextReport(const SolverResults &Results, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h index ef36022a7..1f28206d1 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h @@ -10,6 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" #include @@ -18,55 +19,54 @@ namespace psr { +enum class CSTDFILEIOState { + TOP = 42, + UNINIT = 0, + OPENED = 1, + CLOSED = 2, + ERROR = 3, + BOT = 4 +}; +llvm::StringRef to_string(CSTDFILEIOState State) noexcept; +template <> struct JoinLatticeTraits { + static constexpr CSTDFILEIOState top() noexcept { + return CSTDFILEIOState::TOP; + } + static constexpr CSTDFILEIOState bottom() noexcept { + return CSTDFILEIOState::BOT; + } + static constexpr CSTDFILEIOState join(CSTDFILEIOState L, + CSTDFILEIOState R) noexcept { + if (L == top() || R == bottom()) { + return R; + } + if (L == bottom() || R == top()) { + return L; + } + return bottom(); + } +}; + /** * A type state description for C's file I/O API. The finite state machine * is encoded by a two-dimensional array with rows as function tokens and * columns as states. */ -class CSTDFILEIOTypeStateDescription : public TypeStateDescription { -private: - /** - * We use the following lattice - * BOT = all information - * - * UNINIT OPENED CLOSED ERROR - * - * TOP = no information - */ - enum CSTDFILEIOState { - TOP = 42, - UNINIT = 0, - OPENED = 1, - CLOSED = 2, - ERROR = 3, - BOT = 4 - }; - - /** - * The STAR token represents all API functions besides fopen(), fdopen() and - * fclose(). FOPEN covers fopen() and fdopen() since both functions are - * modeled the same in our case. - */ - enum class CSTDFILEIOToken { FOPEN = 0, FCLOSE = 1, STAR = 2 }; - - static const std::map> StdFileIOFuncs; - // delta matrix to implement the state machine's delta function - static const CSTDFILEIOState Delta[3][5]; - static CSTDFILEIOToken funcNameToToken(const std::string &F); - +class CSTDFILEIOTypeStateDescription + : public TypeStateDescription { public: - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + using TypeStateDescription::getNextState; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] std::string - stateToString(TypeStateDescription::State S) const override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; [[nodiscard]] TypeStateDescription::State top() const override; [[nodiscard]] TypeStateDescription::State uninit() const override; @@ -74,6 +74,8 @@ class CSTDFILEIOTypeStateDescription : public TypeStateDescription { [[nodiscard]] TypeStateDescription::State error() const override; }; +extern template class IDETypeStateAnalysis; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h index 0a31b6042..081b94a46 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h @@ -13,9 +13,8 @@ #include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" #include "phasar/Domain/AnalysisDomain.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" -#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h" -#include #include #include #include @@ -27,32 +26,35 @@ class Value; namespace psr { +/** + * We use the following lattice + * BOT = all information + * + * UNINIT CTX_ATTACHED PARAM_INIT DERIVED ERROR + * + * TOP = no information + */ +enum class OpenSSLEVPKDFCTXState { + TOP = 42, + UNINIT = 5, + CTX_ATTACHED = 1, + PARAM_INIT = 2, + DERIVED = 3, + ERROR = 4, + BOT = 0 // It is VERY IMPORTANT, athat BOT has value 0, since this is the + // default value +}; + +llvm::StringRef to_string(OpenSSLEVPKDFCTXState State) noexcept; + /** * A type state description for OpenSSL's EVP Key Derivation functions. The * finite state machine is encoded by a two-dimensional array with rows as * function tokens and columns as states. */ -class OpenSSLEVPKDFCTXDescription : public TypeStateDescription { +class OpenSSLEVPKDFCTXDescription + : public TypeStateDescription { private: - /** - * We use the following lattice - * BOT = all information - * - * UNINIT CTX_ATTACHED PARAM_INIT DERIVED ERROR - * - * TOP = no information - */ - enum OpenSSLEVPKDFState { - TOP = 42, - UNINIT = 5, - CTX_ATTACHED = 1, - PARAM_INIT = 2, - DERIVED = 3, - ERROR = 4, - BOT = 0 // It is VERY IMPORTANT, athat BOT has value 0, since this is the - // default value - }; - /** * The STAR token represents all functions besides EVP_KDF_fetch(), * EVP_KDF_CTX_new(), EVP_KDF_CTX_set_params() ,derive() and @@ -66,42 +68,40 @@ class OpenSSLEVPKDFCTXDescription : public TypeStateDescription { STAR = 4 }; - static const std::map> OpenSSLEVPKDFFuncs; // Delta matrix to implement the state machine's Delta function - static const OpenSSLEVPKDFState Delta[5][6]; + static const OpenSSLEVPKDFCTXState Delta[5][6]; // std::map, int> // requiredKDFState; - IDESolver &KDFAnalysisResults; - static OpenSSLEVTKDFToken funcNameToToken(const std::string &F); + IDESolver> + &KDFAnalysisResults; + static OpenSSLEVTKDFToken funcNameToToken(llvm::StringRef F); public: + using TypeStateDescription::getNextState; OpenSSLEVPKDFCTXDescription( - IDESolver &KDFAnalysisResults) + IDESolver> + &KDFAnalysisResults) : KDFAnalysisResults(KDFAnalysisResults) {} + [[nodiscard]] bool isFactoryFunction(llvm::StringRef FuncName) const override; [[nodiscard]] bool - isFactoryFunction(const std::string &FuncName) const override; - [[nodiscard]] bool - isConsumingFunction(const std::string &FuncName) const override; - [[nodiscard]] bool isAPIFunction(const std::string &FuncName) const override; - [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; - [[nodiscard]] TypeStateDescription::State - getNextState(const std::string &Tok, TypeStateDescription::State S, + isConsumingFunction(llvm::StringRef FuncName) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef FuncName) const override; + [[nodiscard]] State getNextState(llvm::StringRef Tok, State S) const override; + [[nodiscard]] State + getNextState(llvm::StringRef Tok, State S, const llvm::CallBase *CallSite) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] std::string - stateToString(TypeStateDescription::State S) const override; - [[nodiscard]] TypeStateDescription::State bottom() const override; - [[nodiscard]] TypeStateDescription::State top() const override; - [[nodiscard]] TypeStateDescription::State uninit() const override; - [[nodiscard]] TypeStateDescription::State start() const override; - [[nodiscard]] TypeStateDescription::State error() const override; + getFactoryParamIdx(llvm::StringRef F) const override; + [[nodiscard]] State bottom() const override; + [[nodiscard]] State top() const override; + [[nodiscard]] State uninit() const override; + [[nodiscard]] State start() const override; + [[nodiscard]] State error() const override; /* /// Checks all callSites, where a EVP_KDF object needs to be in a /// certain state, such that the state transition for EVP_KDF_CTX is valid. diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h index f038e04a6..34023c863 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h @@ -17,24 +17,28 @@ #include namespace psr { -class OpenSSLEVPKDFDescription : public TypeStateDescription { -public: - /** - * We use the following lattice - * BOT = all information - * - * UNINIT KDF_FETCHED ERROR - * - * TOP = no information - */ - enum OpenSSLEVPKDFState { - TOP = 42, - UNINIT = 0, - KDF_FETCHED = 1, - ERROR = 2, - BOT = 3 - }; +/** + * We use the following lattice + * BOT = all information + * + * UNINIT KDF_FETCHED ERROR + * + * TOP = no information + */ +enum class OpenSSLEVPKDFState { + TOP = 42, + UNINIT = 0, + KDF_FETCHED = 1, + ERROR = 2, + BOT = 3 +}; + +llvm::StringRef to_string(OpenSSLEVPKDFState State) noexcept; + +class OpenSSLEVPKDFDescription + : public TypeStateDescription { +public: /** * The STAR token represents all functions besides EVP_KDF_fetch(), * EVP_KDF_fetch() and EVP_KDF_CTX_free(). @@ -45,32 +49,32 @@ class OpenSSLEVPKDFDescription : public TypeStateDescription { STAR = 2 }; + using State = OpenSSLEVPKDFState; + private: - static const std::map> OpenSSLEVPKDFFuncs; // delta matrix to implement the state machine's delta function static const OpenSSLEVPKDFState Delta[3][4]; - static OpenSSLEVTKDFToken funcNameToToken(const std::string &F); + static OpenSSLEVTKDFToken funcNameToToken(llvm::StringRef F); public: - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; + using TypeStateDescription::getNextState; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - - [[nodiscard]] std::string - stateToString(TypeStateDescription::State S) const override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h index f0b0c6ab9..cb69f4fe7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h @@ -15,24 +15,23 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" -#include -#include #include namespace psr { +enum class OpenSSLSecureHeapState { + TOP = 42, + BOT = 0, + UNINIT = 1, + ALLOCATED = 2, + ZEROED = 3, + FREED = 4, + ERROR = 5 +}; +llvm::StringRef to_string(OpenSSLSecureHeapState State) noexcept; -class OpenSSLSecureHeapDescription : public TypeStateDescription { +class OpenSSLSecureHeapDescription + : public TypeStateDescription { private: - enum OpenSSLSecureHeapState { - TOP = 42, - BOT = 0, - UNINIT = 1, - ALLOCATED = 2, - ZEROED = 3, - FREED = 4, - ERROR = 5 - }; - enum class OpenSSLSecureHeapToken { SECURE_MALLOC = 0, SECURE_ZALLOC = 1, @@ -41,34 +40,33 @@ class OpenSSLSecureHeapDescription : public TypeStateDescription { STAR = 4 }; - static const std::map> OpenSSLSecureHeapFuncs; // Delta matrix to implement the state machine's Delta function static const OpenSSLSecureHeapState Delta[5][6]; IDESolver &SecureHeapPropagationResults; - static OpenSSLSecureHeapToken funcNameToToken(const std::string &F); + static OpenSSLSecureHeapToken funcNameToToken(llvm::StringRef F); public: + using TypeStateDescription::getNextState; OpenSSLSecureHeapDescription(IDESolver &SecureHeapPropagationResults); - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] TypeStateDescription::State - getNextState(const std::string &Tok, TypeStateDescription::State S, + getNextState(llvm::StringRef Tok, TypeStateDescription::State S, const llvm::CallBase *CallSite) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] std::string - stateToString(TypeStateDescription::State S) const override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; [[nodiscard]] TypeStateDescription::State top() const override; [[nodiscard]] TypeStateDescription::State uninit() const override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h index 5f06867f2..a1c41d1c2 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h @@ -18,43 +18,24 @@ namespace psr { -class OpenSSLSecureMemoryDescription : public TypeStateDescription { -private: - enum OpenSSLSecureMemoryState { - TOP = 42, - BOT = 0, - ZEROED = 1, - FREED = 2, - ERROR = 3, - ALLOCATED = 4 - }; - - enum class OpenSSLSecureMemoryToken { - CRYPTO_MALLOC = 0, - CRYPTO_ZALLOC = 1, - CRYPTO_FREE = 2, - OPENSSL_CLEANSE = 3, - STAR = 4 - }; - - static const std::map> OpenSSLSecureMemoryFuncs; - // Delta matrix to implement the state machine's Delta function - static const OpenSSLSecureMemoryState Delta[6][7]; - static OpenSSLSecureMemoryToken funcNameToToken(const std::string &F); +enum class OpenSSLSecureMemoryState; +llvm::StringRef to_string(OpenSSLSecureMemoryState State) noexcept; +class OpenSSLSecureMemoryDescription + : public TypeStateDescription { public: - [[nodiscard]] bool isFactoryFunction(const std::string &F) const override; - [[nodiscard]] bool isConsumingFunction(const std::string &F) const override; - [[nodiscard]] bool isAPIFunction(const std::string &F) const override; + using TypeStateDescription::getNextState; + [[nodiscard]] bool isFactoryFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isConsumingFunction(llvm::StringRef F) const override; + [[nodiscard]] bool isAPIFunction(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State - getNextState(std::string Tok, TypeStateDescription::State S) const override; + getNextState(llvm::StringRef Tok, + TypeStateDescription::State S) const override; [[nodiscard]] std::string getTypeNameOfInterest() const override; [[nodiscard]] std::set - getConsumerParamIdx(const std::string &F) const override; + getConsumerParamIdx(llvm::StringRef F) const override; [[nodiscard]] std::set - getFactoryParamIdx(const std::string &F) const override; - [[nodiscard]] std::string - stateToString(TypeStateDescription::State S) const override; + getFactoryParamIdx(llvm::StringRef F) const override; [[nodiscard]] TypeStateDescription::State bottom() const override; [[nodiscard]] TypeStateDescription::State top() const override; [[nodiscard]] TypeStateDescription::State uninit() const override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h index a67b119ba..883b1d89d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h @@ -17,6 +17,19 @@ namespace psr { +struct TypeStateDescriptionBase { + virtual ~TypeStateDescriptionBase() = default; + + [[nodiscard]] virtual bool isFactoryFunction(llvm::StringRef F) const = 0; + [[nodiscard]] virtual bool isConsumingFunction(llvm::StringRef F) const = 0; + [[nodiscard]] virtual bool isAPIFunction(llvm::StringRef F) const = 0; + [[nodiscard]] virtual std::string getTypeNameOfInterest() const = 0; + [[nodiscard]] virtual std::set + getConsumerParamIdx(llvm::StringRef F) const = 0; + [[nodiscard]] virtual std::set + getFactoryParamIdx(llvm::StringRef F) const = 0; +}; + /** * Interface for a type state problem to be used with the IDETypeStateAnalysis. * It needs to provide a finite state machine to handle state changes and a list @@ -31,31 +44,24 @@ namespace psr { * * @see CSTDFILEIOTypeStateDescription as an example of type state description. */ -struct TypeStateDescription { +template +struct TypeStateDescription : public TypeStateDescriptionBase { /// Type for states of the finite state machine - using State = int; - virtual ~TypeStateDescription() = default; - [[nodiscard]] virtual bool isFactoryFunction(const std::string &F) const = 0; - [[nodiscard]] virtual bool - isConsumingFunction(const std::string &F) const = 0; - [[nodiscard]] virtual bool isAPIFunction(const std::string &F) const = 0; + using State = StateTy; + ~TypeStateDescription() override = default; /** * @brief For a given function name (as a string token) and a state, this * function returns the next state. */ - [[nodiscard]] virtual State getNextState(std::string Tok, State S) const = 0; + [[nodiscard]] virtual State getNextState(llvm::StringRef Tok, + State S) const = 0; [[nodiscard]] virtual State - getNextState(const std::string &Tok, State S, + getNextState(llvm::StringRef Tok, State S, const llvm::CallBase * /*CallSite*/) const { return getNextState(Tok, S); } - [[nodiscard]] virtual std::string getTypeNameOfInterest() const = 0; - [[nodiscard]] virtual std::set - getConsumerParamIdx(const std::string &F) const = 0; - [[nodiscard]] virtual std::set - getFactoryParamIdx(const std::string &F) const = 0; - [[nodiscard]] virtual std::string stateToString(State S) const = 0; + [[nodiscard]] virtual State bottom() const = 0; [[nodiscard]] virtual State top() const = 0; diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h index 4c6e0e798..df91bce7d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h @@ -75,12 +75,6 @@ class InterMonoFullConstantPropagation std::unordered_map initialSeeds() override; - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override; - void printContainer(llvm::raw_ostream &OS, mono_container_t Con) const override; }; diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h index 235d9a31e..8674ff564 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h @@ -77,12 +77,6 @@ class InterMonoSolverTest : public InterMonoProblem { const mono_container_t &In) override; std::unordered_map initialSeeds() override; - - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h index c155f1b71..211de3a91 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h @@ -82,12 +82,6 @@ class InterMonoTaintAnalysis std::unordered_map initialSeeds() override; - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override; - [[nodiscard]] const std::map> &getAllLeaks() const; private: diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h index e62d24369..010e2f517 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h @@ -22,6 +22,7 @@ #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/Utils/BitVectorSet.h" +#include "phasar/Utils/Printer.h" #include #include @@ -44,10 +45,15 @@ class LLVMBasedICFG; class LLVMTypeHierarchy; class InterMonoFullConstantPropagation; +struct IntraMonoFCAFact { + const llvm::Value *Fact{}; + LatticeDomain Value{}; +}; + struct IntraMonoFullConstantPropagationAnalysisDomain : public LLVMAnalysisDomainDefault { using plain_d_t = int64_t; - using d_t = std::pair>; + using d_t = IntraMonoFCAFact; using mono_container_t = std::map>; }; @@ -90,31 +96,23 @@ class IntraMonoFullConstantPropagation const mono_container_t &Rhs) override; std::unordered_map initialSeeds() override; - - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override; }; +std::string DToString(const IntraMonoFCAFact &Fact); + } // namespace psr namespace std { -template <> -struct hash>> { - size_t operator()(const std::pair> &P) const { +template <> struct hash { + size_t operator()(const psr::IntraMonoFCAFact &P) const { std::hash HashPtr; - size_t HP = HashPtr(P.first); + size_t HP = HashPtr(P.Fact); size_t HU = 0; // returns nullptr if P.second is Top or Bottom, a valid pointer otherwise if (const auto *Ptr = std::get_if( - &P.second)) { + &P.Value)) { HU = *Ptr; } return HP ^ (HU << 1); diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h index 05a95b293..13c5ac42f 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h @@ -69,13 +69,6 @@ class IntraMonoSolverTest mono_container_t normalFlow(n_t Inst, const mono_container_t &In) override; std::unordered_map initialSeeds() override; - - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, - const llvm::Function *Fun) const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h index 7b1f887b8..e813e38d3 100644 --- a/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h @@ -65,12 +65,6 @@ class IntraMonoUninitVariables mono_container_t normalFlow(n_t Inst, const mono_container_t &In) override; std::unordered_map initialSeeds() override; - - void printNode(llvm::raw_ostream &OS, n_t Inst) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override; }; } // namespace psr diff --git a/include/phasar/Utils/Printer.h b/include/phasar/Utils/Printer.h index c8f70578d..31a08cdb4 100644 --- a/include/phasar/Utils/Printer.h +++ b/include/phasar/Utils/Printer.h @@ -10,106 +10,109 @@ #ifndef PHASAR_UTILS_PRINTER_H #define PHASAR_UTILS_PRINTER_H +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include #include +#include -namespace psr { - -template -std::string toStringBuilder(void (P::*Printer)(llvm::raw_ostream &, T) const, - const P *This, const T &Arg) { - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - std::invoke(Printer, This, std::ref(StrS), Arg); - return Buffer; -} - -template struct NodePrinterBase { - virtual ~NodePrinterBase() = default; - - virtual void printNode(llvm::raw_ostream &OS, N Stmt) const = 0; - - [[nodiscard]] std::string NtoString(N Stmt) const { // NOLINT - return toStringBuilder(&NodePrinterBase::printNode, this, Stmt); - } -}; -template -using NodePrinter = NodePrinterBase; - -template struct DataFlowFactPrinterBase { - virtual ~DataFlowFactPrinterBase() = default; - - virtual void printDataFlowFact(llvm::raw_ostream &OS, D Fact) const = 0; - - [[nodiscard]] std::string DtoString(D Fact) const { // NOLINT - return toStringBuilder(&DataFlowFactPrinterBase::printDataFlowFact, this, - Fact); - } -}; -template -using DataFlowFactPrinter = - DataFlowFactPrinterBase; - -template struct ValuePrinter { - virtual ~ValuePrinter() = default; - - virtual void printValue(llvm::raw_ostream &OS, V Val) const = 0; - - [[nodiscard]] std::string VtoString(V Val) const { // NOLINT - return toStringBuilder(&ValuePrinter::printValue, this, Val); - } -}; - -template struct TypePrinter { - virtual ~TypePrinter() = default; +namespace llvm { +class Value; +class Instruction; +class Function; +} // namespace llvm - virtual void printType(llvm::raw_ostream &OS, T Ty) const = 0; - - [[nodiscard]] std::string TtoString(T Ty) const { // NOLINT - return toStringBuilder(&TypePrinter::printType, this, Ty); +namespace psr { +namespace detail { +template +static constexpr bool IsSomehowPrintable = + has_str_v || is_llvm_printable_v || has_adl_to_string_v; + +template decltype(auto) printSomehow(const T &Val) { + if constexpr (has_str_v) { + return Val.str(); + } else if constexpr (has_adl_to_string_v) { + return adl_to_string(Val); + } else if constexpr (is_llvm_printable_v) { + std::string Str; + llvm::raw_string_ostream ROS(Str); + ROS << Val; + return Str; + } else { + llvm_unreachable( + "All compilable cases should be handled in the if-chain above"); } -}; - -template struct EdgeFactPrinterBase { - using l_t = L; - - virtual ~EdgeFactPrinterBase() = default; - - virtual void printEdgeFact(llvm::raw_ostream &OS, l_t Val) const = 0; +} +} // namespace detail + +/// Stringify the given ICFG node (instruction/statement). +/// +/// Default implementation. Provide your own overload to customize this API for +/// your types +template >> +[[nodiscard]] decltype(auto) NToString(const N &Node) { + return detail::printSomehow(Node); +} - [[nodiscard]] std::string LtoString(l_t Val) const { // NOLINT - return toStringBuilder(&EdgeFactPrinterBase::printEdgeFact, this, Val); - } -}; +/// Stringify the given data-flow fact. +/// +/// Default implementation. Provide your own overload to customize this API for +/// your types +template >> +[[nodiscard]] decltype(auto) DToString(const D &Fact) { + return detail::printSomehow(Fact); +} -template -using EdgeFactPrinter = EdgeFactPrinterBase; +/// Stringify the given edge value. +/// +/// Default implementation. Provide your own overload to customize this API for +/// your types +template >> +[[nodiscard]] decltype(auto) LToString(const L &Value) { + return detail::printSomehow(Value); +} -template struct FunctionPrinter { - using F = typename AnalysisDomainTy::f_t; +/// Stringify the given function. +/// +/// Default implementation. Provide your own overload to customize this API for +/// your types +template >> +[[nodiscard]] std::string FToString(const F &Fun) { + return detail::printSomehow(Fun); +} - virtual ~FunctionPrinter() = default; +// -- specializations - virtual void printFunction(llvm::raw_ostream &OS, F Func) const = 0; +// --- LLVM +// Note: Provide forward declarations here, such that improper usage will +// definitely lead to an error instead of triggering one of the default +// implementations - [[nodiscard]] std::string FtoString(F Func) const { // NOLINT - return toStringBuilder(&FunctionPrinter::printFunction, this, Func); - } -}; +/// Stringify the given LLVM Value. +/// +/// \remark Link phasar_llvm_utils to use this +[[nodiscard]] std::string NToString(const llvm::Value *V); -template struct ContainerPrinter { - virtual ~ContainerPrinter() = default; +/// Stringify the given LLVM Instruction. +/// +/// \remark Link phasar_llvm_utils to use this +[[nodiscard]] std::string NToString(const llvm::Instruction *V); - virtual void printContainer(llvm::raw_ostream &OS, - ContainerTy Container) const = 0; +/// Stringify the given LLVM Value. +/// +/// \remark Link phasar_llvm_utils to use this +[[nodiscard]] std::string DToString(const llvm::Value *V); - [[nodiscard]] std::string - ContainertoString(ContainerTy Container) const { // NOLINT - return toStringBuilder(&ContainerPrinter::printContainer, this, Container); - } -}; +/// Stringify the given LLVM Function. +/// +/// \remark Link phasar_llvm_utils to use this +[[nodiscard]] llvm::StringRef FToString(const llvm::Function *V); } // namespace psr diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 3f1d8d302..7aebbdb72 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -12,6 +12,7 @@ #include "llvm/Support/raw_ostream.h" +#include #include #include #include @@ -19,6 +20,7 @@ #include namespace psr { + // NOLINTBEGIN(readability-identifier-naming) namespace detail { diff --git a/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp b/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp index 68cb0c0f4..59bd16534 100644 --- a/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp +++ b/lib/Controller/AnalysisControllerXIDECSTDIOTS.cpp @@ -15,7 +15,8 @@ namespace psr { void AnalysisController::executeIDECSTDIOTS() { CSTDFILEIOTypeStateDescription TSDesc; - executeIDEAnalysis(&TSDesc, EntryPoints); + executeIDEAnalysis>( + &TSDesc, EntryPoints); } } // namespace psr diff --git a/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp b/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp index b686680f0..6c6dba3b4 100644 --- a/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp +++ b/lib/Controller/AnalysisControllerXIDEOpenSSLTS.cpp @@ -15,7 +15,8 @@ namespace psr { void AnalysisController::executeIDEOpenSSLTS() { OpenSSLEVPKDFDescription TSDesc; - executeIDEAnalysis(&TSDesc, EntryPoints); + executeIDEAnalysis>( + &TSDesc, EntryPoints); } } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp index 38c07cbf5..9c39547aa 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @@ -23,6 +23,7 @@ #include "phasar/Pointer/PointsToInfo.h" #include "phasar/Utils/DebugOutput.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/Printer.h" #include "phasar/Utils/Utilities.h" #include "llvm/ADT/SmallSet.h" @@ -324,7 +325,7 @@ IDEExtendedTaintAnalysis::getCallFlowFunction(n_t CallStmt, f_t DestFun) { ParamIterator FEnd = DestFun->arg_end(); PHASAR_LOG_LEVEL(DEBUG, "##Call-FF at: " << psr::llvmIRToString(Call) - << " to: " << FtoString(DestFun)); + << " to: " << FToString(DestFun)); for (; FIt != FEnd && It != End; ++FIt, ++It) { auto From = makeFlowFact(It->get()); /// Pointer-Arithetics in the last indirection are irrelevant for @@ -747,26 +748,6 @@ auto IDEExtendedTaintAnalysis::getSummaryEdgeFunction(n_t Curr, d_t CurrNode, // Printing functions: -void IDEExtendedTaintAnalysis::printNode(llvm::raw_ostream &OS, - n_t Inst) const { - OS << llvmIRToString(Inst); -} - -void IDEExtendedTaintAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - d_t Fact) const { - OS << Fact; -} - -void IDEExtendedTaintAnalysis::printEdgeFact(llvm::raw_ostream &OS, - l_t Fact) const { - OS << Fact; -} - -void IDEExtendedTaintAnalysis::printFunction(llvm::raw_ostream &OS, - f_t Fun) const { - OS << (Fun && Fun->hasName() ? Fun->getName() : ""); -} - void IDEExtendedTaintAnalysis::emitTextReport( const SolverResults &SR, llvm::raw_ostream &OS) { OS << "===== IDEExtendedTaintAnalysis-Results =====\n"; @@ -776,9 +757,7 @@ void IDEExtendedTaintAnalysis::emitTextReport( } for (auto &[Inst, LeakSet] : Leaks) { - OS << "At "; - printNode(OS, Inst); - OS << "\n"; + OS << "At " << NToString(Inst) << '\n'; for (const auto &Leak : LeakSet) { OS << "\t" << llvmIRToShortString(Leak) << "\n"; } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp index a7656d23b..cfb72c540 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp @@ -258,14 +258,10 @@ EdgeFunction IDEGeneralizedLCA::getNormalEdgeFunction( IDEGeneralizedLCA::n_t Curr, IDEGeneralizedLCA::d_t CurrNode, IDEGeneralizedLCA::n_t Succ, IDEGeneralizedLCA::d_t SuccNode) { PHASAR_LOG_LEVEL(DEBUG, "IDEGeneralizedLCA::getNormalEdgeFunction()"); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Curr Inst : " << IDEGeneralizedLCA::NtoString(Curr)); - PHASAR_LOG_LEVEL( - DEBUG, "(D) Curr Node : " << IDEGeneralizedLCA::DtoString(CurrNode)); - PHASAR_LOG_LEVEL(DEBUG, - "(N) Succ Inst : " << IDEGeneralizedLCA::NtoString(Succ)); - PHASAR_LOG_LEVEL( - DEBUG, "(D) Succ Node : " << IDEGeneralizedLCA::DtoString(SuccNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Curr Inst : " << NToString(Curr)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Curr Node : " << DToString(CurrNode)); + PHASAR_LOG_LEVEL(DEBUG, "(N) Succ Inst : " << NToString(Succ)); + PHASAR_LOG_LEVEL(DEBUG, "(D) Succ Node : " << DToString(SuccNode)); // Initialize global variables at entry point if (!isZeroValue(CurrNode) && ICF->isStartPoint(Curr) && isEntryPoint(ICF->getFunctionOf(Curr)->getName().str()) && @@ -479,27 +475,6 @@ EdgeFunction IDEGeneralizedLCA::allTopFunction() { return AlltopFn; } -void IDEGeneralizedLCA::printNode(llvm::raw_ostream &Os, - IDEGeneralizedLCA::n_t Stmt) const { - Os << llvmIRToString(Stmt); -} - -void IDEGeneralizedLCA::printDataFlowFact(llvm::raw_ostream &Os, - IDEGeneralizedLCA::d_t Fact) const { - assert(Fact && "Invalid dataflow fact"); - Os << llvmIRToString(Fact); -} - -void IDEGeneralizedLCA::printFunction(llvm::raw_ostream &Os, - IDEGeneralizedLCA::f_t Func) const { - Os << Func->getName(); -} - -void IDEGeneralizedLCA::printEdgeFact(llvm::raw_ostream &Os, - IDEGeneralizedLCA::l_t L) const { - Os << L; -} - /*void IDEGeneralizedLCA::printIDEReport( llvm::raw_ostream &os, SolverResults AllocatedVars; for (const auto *Stmt : ICF->getAllInstructionsOf(F)) { unsigned Lnr = getLineFromIR(Stmt); - llvm::outs() << "\nIR : " << NtoString(Stmt) << "\nLNR: " << Lnr << '\n'; + llvm::outs() << "\nIR : " << NToString(Stmt) << "\nLNR: " << Lnr << '\n'; // We skip statements with no source code mapping if (Lnr == 0) { llvm::outs() << "Skipping this stmt!\n"; @@ -627,15 +602,15 @@ IDEGeneralizedLCA::lca_results_t IDEGeneralizedLCA::getLCAResults( } else { // It's not a terminator inst, hence it has only a single successor const auto *Succ = ICF->getSuccsOf(Stmt)[0]; - llvm::outs() << "Succ stmt: " << NtoString(Succ) << '\n'; + llvm::outs() << "Succ stmt: " << NToString(Succ) << '\n'; Results = SR.resultsAt(Succ, true); } // stripBottomResults(results); std::set ValidVarsAtStmt; for (const auto &Res : Results) { auto VarName = getVarNameFromIR(Res.first); - llvm::outs() << " D: " << DtoString(Res.first) - << " | V: " << VtoString(Res.second) + llvm::outs() << " D: " << DToString(Res.first) + << " | V: " << LToString(Res.second) << " | Var: " << VarName << '\n'; if (!VarName.empty()) { // Only store/overwrite values of variables from allocas or @@ -698,13 +673,6 @@ bool IDEGeneralizedLCA::isEntryPoint(const std::string &Name) const { return Name == "main"; } -template std::string IDEGeneralizedLCA::VtoString(V Val) { - std::string Buffer; - llvm::raw_string_ostream Ss(Buffer); - Ss << Val; - return Ss.str(); -} - bool IDEGeneralizedLCA::isStringConstructor(const llvm::Function *F) { return (ICF->getSpecialMemberFunctionType(F) == SpecialMemberFunctionType::Constructor && diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp index fd4b8908e..fef29aaf6 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp @@ -568,26 +568,6 @@ EdgeFunction IDELinearConstantAnalysis::allTopFunction() { return AllTop{}; } -void IDELinearConstantAnalysis::printNode(llvm::raw_ostream &OS, - n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IDELinearConstantAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - d_t Fact) const { - OS << llvmIRToShortString(Fact); -} - -void IDELinearConstantAnalysis::printFunction(llvm::raw_ostream &OS, - f_t Func) const { - OS << Func->getName(); -} - -void IDELinearConstantAnalysis::printEdgeFact(llvm::raw_ostream &OS, - l_t L) const { - OS << L; -} - void IDELinearConstantAnalysis::emitTextReport( const SolverResults &SR, llvm::raw_ostream &OS) { OS << "\n====================== IDE-Linear-Constant-Analysis Report " @@ -604,11 +584,11 @@ void IDELinearConstantAnalysis::emitTextReport( auto Results = SR.resultsAt(Stmt, true); stripBottomResults(Results); if (!Results.empty()) { - OS << "At IR statement: " << NtoString(Stmt) << '\n'; + OS << "At IR statement: " << NToString(Stmt) << '\n'; for (auto Res : Results) { if (!Res.second.isBottom()) { - OS << " Fact: " << DtoString(Res.first) - << "\n Value: " << LtoString(Res.second) << '\n'; + OS << " Fact: " << DToString(Res.first) + << "\n Value: " << LToString(Res.second) << '\n'; } } OS << '\n'; @@ -652,7 +632,7 @@ IDELinearConstantAnalysis::getLCAResults(SolverResults SR) { std::set AllocatedVars; for (const auto *Stmt : ICF->getAllInstructionsOf(F)) { unsigned Lnr = getLineFromIR(Stmt); - llvm::outs() << "\nIR : " << NtoString(Stmt) << "\nLNR: " << Lnr << '\n'; + llvm::outs() << "\nIR : " << NToString(Stmt) << "\nLNR: " << Lnr << '\n'; // We skip statements with no source code mapping if (Lnr == 0) { llvm::outs() << "Skipping this stmt!\n"; @@ -683,15 +663,15 @@ IDELinearConstantAnalysis::getLCAResults(SolverResults SR) { } else { // It's not a terminator inst, hence it has only a single successor const auto *Succ = ICF->getSuccsOf(Stmt)[0]; - llvm::outs() << "Succ stmt: " << NtoString(Succ) << '\n'; + llvm::outs() << "Succ stmt: " << NToString(Succ) << '\n'; Results = SR.resultsAt(Succ, true); } stripBottomResults(Results); std::set ValidVarsAtStmt; for (auto Res : Results) { auto VarName = getVarNameFromIR(Res.first); - llvm::outs() << " D: " << DtoString(Res.first) - << " | V: " << LtoString(Res.second) + llvm::outs() << " D: " << DToString(Res.first) + << " | V: " << LToString(Res.second) << " | Var: " << VarName << '\n'; if (!VarName.empty()) { // Only store/overwrite values of variables from allocas or globals diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp index e40ec7a5f..a0a8619e4 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp @@ -141,24 +141,4 @@ EdgeFunction IDEProtoAnalysis::allTopFunction() { return AllTop{nullptr}; } -void IDEProtoAnalysis::printNode(llvm::raw_ostream &OS, - IDEProtoAnalysis::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IDEProtoAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - IDEProtoAnalysis::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IDEProtoAnalysis::printFunction(llvm::raw_ostream &OS, - IDEProtoAnalysis::f_t Func) const { - OS << Func->getName(); -} - -void IDEProtoAnalysis::printEdgeFact(llvm::raw_ostream &OS, - IDEProtoAnalysis::l_t L) const { - OS << llvmIRToString(L); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp index 14706b7df..116981c0a 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp @@ -19,6 +19,7 @@ #include "llvm/IR/AbstractCallSite.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Value.h" +#include "llvm/Support/ErrorHandling.h" #include #include @@ -113,31 +114,6 @@ bool IDESecureHeapPropagation::isZeroValue(d_t Fact) const { return Fact == SecureHeapFact::ZERO; } -void IDESecureHeapPropagation::printNode(llvm::raw_ostream &Os, - n_t Stmt) const { - Os << llvmIRToString(Stmt); -} - -void IDESecureHeapPropagation::printDataFlowFact(llvm::raw_ostream &Os, - d_t Fact) const { - switch (Fact) { - case SecureHeapFact::ZERO: - Os << "ZERO"; - break; - case SecureHeapFact::INITIALIZED: - Os << "INITIALIZED"; - break; - default: - assert(false && "Invalid dataflow-fact"); - break; - } -} - -void IDESecureHeapPropagation::printFunction(llvm::raw_ostream &Os, - f_t F) const { - Os << llvm::demangle(F->getName().str()); -} - // in addition provide specifications for the IDE parts EdgeFunction @@ -213,24 +189,6 @@ IDESecureHeapPropagation::allTopFunction() { return AllTop{}; } -void IDESecureHeapPropagation::printEdgeFact(llvm::raw_ostream &Os, - l_t L) const { - switch (L) { - case l_t::BOT: - Os << "BOT"; - break; - case l_t::INITIALIZED: - Os << "INITIALIZED"; - break; - case l_t::TOP: - Os << "TOP"; - break; - default: - assert(false && "Invalid edge fact"); - break; - } -} - void IDESecureHeapPropagation::emitTextReport( const SolverResults &SR, llvm::raw_ostream &Os) { LLVMBasedCFG CFG; @@ -243,11 +201,11 @@ void IDESecureHeapPropagation::emitTextReport( auto Results = SR.resultsAt(Stmt, true); if (!Results.empty()) { - Os << "At IR statement: " << NtoString(Stmt) << '\n'; + Os << "At IR statement: " << NToString(Stmt) << '\n'; for (auto Res : Results) { - Os << " Fact: " << DtoString(Res.first) - << "\n Value: " << LtoString(Res.second) << '\n'; + Os << " Fact: " << DToString(Res.first) + << "\n Value: " << LToString(Res.second) << '\n'; } Os << '\n'; } @@ -257,3 +215,25 @@ void IDESecureHeapPropagation::emitTextReport( } } // namespace psr + +llvm::StringRef psr::DToString(SecureHeapFact Fact) noexcept { + switch (Fact) { + case SecureHeapFact::ZERO: + return "ZERO"; + case SecureHeapFact::INITIALIZED: + return "INITIALIZED"; + } + llvm_unreachable("Invalid dataflow-fact"); +} + +llvm::StringRef psr::LToString(SecureHeapValue Val) noexcept { + switch (Val) { + case SecureHeapValue::BOT: + return "BOT"; + case SecureHeapValue::INITIALIZED: + return "INITIALIZED"; + case SecureHeapValue::TOP: + return "TOP"; + } + llvm_unreachable("Invalid edge fact"); +} diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp index ba1d9b848..a5b37ec6f 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp @@ -143,24 +143,4 @@ EdgeFunction IDESolverTest::allTopFunction() { return AllTop{nullptr}; } -void IDESolverTest::printNode(llvm::raw_ostream &OS, - IDESolverTest::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IDESolverTest::printDataFlowFact(llvm::raw_ostream &OS, - IDESolverTest::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IDESolverTest::printFunction(llvm::raw_ostream &OS, - IDESolverTest::f_t Func) const { - OS << Func->getName(); -} - -void IDESolverTest::printEdgeFact(llvm::raw_ostream &OS, - IDESolverTest::l_t /*L*/) const { - OS << "empty V test"; -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp index 5033fff0b..b646ea57f 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp @@ -34,238 +34,73 @@ #include #include -namespace psr { +namespace psr::detail { -/// -/// -/// TODO: Make Bottom common across all implementations of TypeStateDescription! -/// then we can factor it out of all edge functions making some of them -/// applicable for small-object optimization! -/// -/// - -// customize the edge function composer -struct TSEdgeFunctionComposer - : EdgeFunctionComposer { - IDETypeStateAnalysisDomain::l_t BotElement{}; - - static EdgeFunction - join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - return AllBottom{This->BotElement}; - } -}; - -struct TSEdgeFunction { - const TypeStateDescription *TSD; - // XXX: Do we really need a string here? Can't we just use an integer or sth - // else that is cheap? - std::string Token; - const llvm::CallBase *CallSite; - - using l_t = IDETypeStateAnalysisDomain ::l_t; - - [[nodiscard]] l_t computeTarget(l_t Source) const { - - // assert((Source != TSD->top()) && "Error: call computeTarget with TOP\n"); - - auto CurrentState = TSD->getNextState( - Token, Source == TSD->top() ? TSD->uninit() : Source, CallSite); - PHASAR_LOG_LEVEL(DEBUG, "State machine transition: (" - << Token << " , " << TSD->stateToString(Source) - << ") -> " << TSD->stateToString(CurrentState)); - return CurrentState; - } - - static EdgeFunction compose(EdgeFunctionRef This, - const EdgeFunction &SecondFunction) { - if (auto Default = defaultComposeOrNull(This, SecondFunction)) { - return Default; - } - - return TSEdgeFunctionComposer{{This, SecondFunction}, This->TSD->bottom()}; - } - - static EdgeFunction join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - return AllBottom{This->TSD->bottom()}; - } - - bool operator==(const TSEdgeFunction &Other) const { - return CallSite == Other.CallSite && Token == Other.Token; - } - - friend llvm::raw_ostream &print(llvm::raw_ostream &OS, - const TSEdgeFunction &TSE) { - return OS << "TSEF(" << TSE.Token << " at " - << llvmIRToShortString(TSE.CallSite) << ")"; - } -}; - -struct TSConstant : ConstantEdgeFunction { - const TypeStateDescription *TSD{}; - - /// XXX: Cannot default compose() and join(), because l_t does not implement - /// JoinLatticeTraits (because bottom value is not constant) - template - static EdgeFunction compose(EdgeFunctionRef This, - const EdgeFunction &SecondFunction) { - - if (auto Default = defaultComposeOrNull(This, SecondFunction)) { - return Default; - } - - auto Ret = SecondFunction.computeTarget(This->Value); - if (Ret == This->Value) { - return This; - } - if (Ret == This->TSD->bottom()) { - return AllBottom{Ret}; - } - - return TSConstant{{Ret}, This->TSD}; - } - - template - static EdgeFunction join(EdgeFunctionRef This, - const EdgeFunction &OtherFunction) { - if (auto Default = defaultJoinOrNull(This, OtherFunction)) { - return Default; - } - - const auto *TSD = This->TSD; - if (const auto *C = llvm::dyn_cast(OtherFunction)) { - if (C->Value == This->Value || C->Value == TSD->top()) { - return This; - } - if (This->Value == TSD->top()) { - return OtherFunction; - } - } - return AllBottom{TSD->bottom()}; - } -}; - -bool operator==(ByConstRef LHS, - ByConstRef RHS) noexcept { - return LHS.Value == RHS.Value; -} - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - ByConstRef EF) { - return OS << "TSConstant[" << EF.TSD->stateToString(EF.Value) << "]"; -} - -IDETypeStateAnalysis::IDETypeStateAnalysis(const LLVMProjectIRDB *IRDB, - LLVMAliasInfoRef PT, - const TypeStateDescription *TSD, - std::vector EntryPoints) - : IDETabulationProblem(IRDB, std::move(EntryPoints), createZeroValue()), - TSD(TSD), PT(PT) { - assert(TSD != nullptr); - assert(PT); -} - -// Start formulating our analysis by specifying the parts required for IFDS - -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getNormalFlowFunction( - IDETypeStateAnalysis::n_t Curr, IDETypeStateAnalysis::n_t /*Succ*/) { +auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) + -> FlowFunctionPtrType { // Check if Alloca's type matches the target type. If so, generate from zero // value. if (const auto *Alloca = llvm::dyn_cast(Curr)) { if (hasMatchingType(Alloca)) { - return generateFromZero(Alloca); + return this->generateFromZero(Alloca); } } - // Check load instructions for target type. Generate from the loaded value and - // kill the load instruction if it was generated previously (strong update!). + // Check load instructions for target type. Generate from the loaded value + // and kill the load instruction if it was generated previously (strong + // update!). if (const auto *Load = llvm::dyn_cast(Curr)) { if (hasMatchingType(Load)) { - struct TSFlowFunction : FlowFunction { - const llvm::LoadInst *Load; - - TSFlowFunction(const llvm::LoadInst *L) : Load(L) {} - ~TSFlowFunction() override = default; - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - if (Source == Load) { - return {}; - } - if (Source == Load->getPointerOperand()) { - return {Source, Load}; - } - return {Source}; - } - }; - return std::make_shared(Load); + return transferFlow(Load, Load->getPointerOperand()); } } if (const auto *Gep = llvm::dyn_cast(Curr)) { if (hasMatchingType(Gep->getPointerOperand())) { - return lambdaFlow([=](d_t Source) -> std::set { - // if (Source == Gep->getPointerOperand()) { - // return {Source, Gep}; - //} - return {Source}; - }); + return identityFlow(); + // return lambdaFlow([=](d_t Source) -> std::set { + // // if (Source == Gep->getPointerOperand()) { + // // return {Source, Gep}; + // //} + // return {Source}; + // }); } } // Check store instructions for target type. Perform a strong update, i.e. - // kill the alloca pointed to by the pointer-operand and all alloca's related - // to the value-operand and then generate them from the value-operand. + // kill the alloca pointed to by the pointer-operand and all alloca's + // related to the value-operand and then generate them from the + // value-operand. if (const auto *Store = llvm::dyn_cast(Curr)) { if (hasMatchingType(Store)) { auto RelevantAliasesAndAllocas = getLocalAliasesAndAllocas( Store->getPointerOperand(), // pointer- or value operand??? // Store->getValueOperand(), - Curr->getParent()->getParent()->getName().str()); - - struct TSFlowFunction : FlowFunction { - const llvm::StoreInst *Store; - std::set AliasesAndAllocas; - TSFlowFunction(const llvm::StoreInst *S, - std::set AA) - : Store(S), AliasesAndAllocas(std::move(AA)) {} - ~TSFlowFunction() override = default; - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - // We kill all relevant loacal aliases and alloca's - if (Source != Store->getValueOperand() && - // AliasesAndAllocas.find(Source) != AliasesAndAllocas.end() - // Is simple comparison sufficient? - Source == Store->getPointerOperand()) { - return {}; - } - // Generate all local aliases and relevant alloca's from the stored - // value - if (Source == Store->getValueOperand()) { - AliasesAndAllocas.insert(Source); - return AliasesAndAllocas; - } - return {Source}; - } - }; - return std::make_shared(Store, RelevantAliasesAndAllocas); + Curr->getFunction()->getName().str()); + + RelevantAliasesAndAllocas.insert(Store->getValueOperand()); + return lambdaFlow( + [Store, AliasesAndAllocas = std::move(RelevantAliasesAndAllocas)]( + d_t Source) -> container_type { + // We kill all relevant loacal aliases and alloca's + if (Source == Store->getPointerOperand()) { + // XXX: later kill must-aliases too + return {}; + } + // Generate all local aliases and relevant alloca's from the + // stored value + if (Source == Store->getValueOperand()) { + return AliasesAndAllocas; + } + return {Source}; + }); } } - return Identity::getInstance(); + return identityFlow(); } -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getCallFlowFunction(IDETypeStateAnalysis::n_t CallSite, - IDETypeStateAnalysis::f_t DestFun) { +auto IDETypeStateAnalysisBase::getCallFlowFunction(n_t CallSite, f_t DestFun) + -> FlowFunctionPtrType { // Kill all data-flow facts if we hit a function of the target API. // Those functions are modled within Call-To-Return. - if (TSD->isAPIFunction(llvm::demangle(DestFun->getName().str()))) { + if (isAPIFunction(llvm::demangle(DestFun->getName().str()))) { return killAllFlows(); } // Otherwise, if we have an ordinary function call, we can just use the @@ -276,128 +111,88 @@ IDETypeStateAnalysis::getCallFlowFunction(IDETypeStateAnalysis::n_t CallSite, llvm::report_fatal_error("callSite not a CallInst nor a InvokeInst"); } -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getRetFlowFunction( - IDETypeStateAnalysis::n_t CallSite, IDETypeStateAnalysis::f_t CalleeFun, - IDETypeStateAnalysis::n_t ExitStmt, IDETypeStateAnalysis::n_t /*RetSite*/) { - // Besides mapping the formal parameter back into the actual parameter and - // propagating the return value into the caller context, we also propagate - // all related alloca's of the formal parameter and the return value. - struct TSFlowFunction : FlowFunction { - const llvm::CallBase *CallSite; - const llvm::Function *CalleeFun; - const llvm::ReturnInst *ExitSite; - IDETypeStateAnalysis *Analysis; - std::vector Actuals; - std::vector Formals; - TSFlowFunction(const llvm::CallBase *CallSite, - const llvm::Function *CalleeFun, - const llvm::Instruction *ExitSite, - IDETypeStateAnalysis *Analysis) - : CallSite(CallSite), CalleeFun(CalleeFun), - ExitSite(llvm::dyn_cast(ExitSite)), - Analysis(Analysis) { - // Set up the actual parameters - for (unsigned Idx = 0; Idx < CallSite->arg_size(); ++Idx) { - Actuals.push_back(CallSite->getArgOperand(Idx)); - } - // Set up the formal parameters - for (unsigned Idx = 0; Idx < CalleeFun->arg_size(); ++Idx) { - Formals.push_back(getNthFunctionArgument(CalleeFun, Idx)); - } - } - - ~TSFlowFunction() override = default; +auto IDETypeStateAnalysisBase::getRetFlowFunction(n_t CallSite, f_t CalleeFun, + n_t ExitStmt, n_t /*RetSite*/) + -> FlowFunctionPtrType { - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - if (!LLVMZeroValue::isLLVMZeroValue(Source)) { - std::set Res; - // Handle C-style varargs functions - if (CalleeFun->isVarArg() && !CalleeFun->isDeclaration()) { - const llvm::Instruction *AllocVarArg; - // Find the allocation of %struct.__va_list_tag - for (const auto &BB : *CalleeFun) { - for (const auto &I : BB) { - if (const auto *Alloc = llvm::dyn_cast(&I)) { - if (Alloc->getAllocatedType()->isArrayTy() && - Alloc->getAllocatedType()->getArrayNumElements() > 0 && - Alloc->getAllocatedType() + /// TODO: Implement return-POI in LLVMFlowFunctions.h + return lambdaFlow([this, CalleeFun, + CS = llvm::cast(CallSite), + Ret = llvm::dyn_cast(ExitStmt)]( + d_t Source) -> container_type { + if (LLVMZeroValue::isLLVMZeroValue(Source)) { + return {Source}; + } + container_type Res; + // Handle C-style varargs functions + if (CalleeFun->isVarArg() && !CalleeFun->isDeclaration()) { + const llvm::Instruction *AllocVarArg; + // Find the allocation of %struct.__va_list_tag + for (const auto &BB : *CalleeFun) { + for (const auto &I : BB) { + if (const auto *Alloc = llvm::dyn_cast(&I)) { + if (Alloc->getAllocatedType()->isArrayTy() && + Alloc->getAllocatedType()->getArrayNumElements() > 0 && + Alloc->getAllocatedType() + ->getArrayElementType() + ->isStructTy() && + Alloc->getAllocatedType() ->getArrayElementType() - ->isStructTy() && - Alloc->getAllocatedType() - ->getArrayElementType() - ->getStructName() == "struct.__va_list_tag") { - AllocVarArg = Alloc; - // TODO break out this nested loop earlier (without goto ;-) - } - } + ->getStructName() == "struct.__va_list_tag") { + AllocVarArg = Alloc; + // TODO break out this nested loop earlier (without goto ;-) } } - // Generate the varargs things by using an over-approximation - if (Source == AllocVarArg) { - for (unsigned Idx = Formals.size(); Idx < Actuals.size(); ++Idx) { - Res.insert(Actuals[Idx]); - } - } - } - // Handle ordinary case - // Map formal parameter into corresponding actual parameter. - for (unsigned Idx = 0; Idx < Formals.size(); ++Idx) { - if (Source == Formals[Idx]) { - Res.insert(Actuals[Idx]); // corresponding actual - } - } - // Collect the return value - if (Source == ExitSite->getReturnValue()) { - Res.insert(CallSite); } - // Collect all relevant alloca's to map into caller context - std::set RelAllocas; - for (const auto *Fact : Res) { - auto Allocas = Analysis->getRelevantAllocas(Fact); - RelAllocas.insert(Allocas.begin(), Allocas.end()); + } + // Generate the varargs things by using an over-approximation + if (Source == AllocVarArg) { + for (unsigned Idx = CalleeFun->arg_size(); Idx < CS->arg_size(); + ++Idx) { + Res.insert(CS->getArgOperand(Idx)); } - Res.insert(RelAllocas.begin(), RelAllocas.end()); - return Res; } - return {Source}; } - }; - return std::make_shared(llvm::cast(CallSite), - CalleeFun, ExitStmt, this); + // Handle ordinary case + // Map formal parameter into corresponding actual parameter. + for (auto [Formal, Actual] : llvm::zip(CalleeFun->args(), CS->args())) { + if (Source == &Formal) { + Res.insert(Actual); // corresponding actual + } + } + + // Collect the return value + if (Ret && Source == Ret->getReturnValue()) { + Res.insert(CS); + } + + // Collect all relevant alloca's to map into caller context + { + container_type RelAllocas; + for (const auto *Fact : Res) { + const auto &Allocas = getRelevantAllocas(Fact); + RelAllocas.insert(Allocas.begin(), Allocas.end()); + } + Res.insert(RelAllocas.begin(), RelAllocas.end()); + } + + return Res; + }); } -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getCallToRetFlowFunction( - IDETypeStateAnalysis::n_t CallSite, IDETypeStateAnalysis::n_t /*RetSite*/, - llvm::ArrayRef Callees) { +auto IDETypeStateAnalysisBase::getCallToRetFlowFunction( + n_t CallSite, n_t /*RetSite*/, llvm::ArrayRef Callees) + -> FlowFunctionPtrType { const auto *CS = llvm::cast(CallSite); for (const auto *Callee : Callees) { std::string DemangledFname = llvm::demangle(Callee->getName().str()); // Generate the return value of factory functions from zero value - if (TSD->isFactoryFunction(DemangledFname)) { - struct TSFlowFunction : FlowFunction { - IDETypeStateAnalysis::d_t CS, ZeroValue; - - TSFlowFunction(IDETypeStateAnalysis::d_t CS, - IDETypeStateAnalysis::d_t Z) - : CS(CS), ZeroValue(Z) {} - ~TSFlowFunction() override = default; - std::set - computeTargets(IDETypeStateAnalysis::d_t Source) override { - if (Source == CS) { - return {}; - } - if (Source == ZeroValue) { - return {Source, CS}; - } - return {Source}; - } - }; - return std::make_shared(CS, getZeroValue()); + if (isFactoryFunction(DemangledFname)) { + return this->generateFromZero(CS); } + /// XXX: Revisit this: + // Handle all functions that are not modeld with special semantics. // Kill actual parameters of target type and all its aliases // and the corresponding alloca(s) as these data-flow facts are @@ -408,7 +203,7 @@ IDETypeStateAnalysis::getCallToRetFlowFunction( // not be killed during call-to-return, since it is not safe to assume // that the return value will be used afterwards, i.e. is stored to memory // pointed to by related alloca's. - if (!TSD->isAPIFunction(DemangledFname) && !Callee->isDeclaration()) { + if (!isAPIFunction(DemangledFname) && !Callee->isDeclaration()) { for (const auto &Arg : CS->args()) { if (hasMatchingType(Arg)) { return killManyFlows(getWMAliasesAndAllocas(Arg.get())); @@ -416,201 +211,40 @@ IDETypeStateAnalysis::getCallToRetFlowFunction( } } } - return Identity::getInstance(); -} - -IDETypeStateAnalysis::FlowFunctionPtrType -IDETypeStateAnalysis::getSummaryFlowFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::f_t /*DestFun*/) { - return nullptr; -} - -InitialSeeds -IDETypeStateAnalysis::initialSeeds() { - // just start in main() - return createDefaultSeeds(); -} - -IDETypeStateAnalysis::d_t IDETypeStateAnalysis::createZeroValue() const { - // create a special value to represent the zero value! - return LLVMZeroValue::getInstance(); -} - -bool IDETypeStateAnalysis::isZeroValue(IDETypeStateAnalysis::d_t Fact) const { - return LLVMZeroValue::isLLVMZeroValue(Fact); -} - -// in addition provide specifications for the IDE parts - -struct TSAllocaEF : TSConstant { - const llvm::AllocaInst *Alloca; - TSAllocaEF(const TypeStateDescription *Tsd, - const llvm::AllocaInst *Alloca) noexcept - : TSConstant{{Tsd->uninit()}, Tsd}, Alloca(Alloca) {} - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const TSAllocaEF &TSA) { - return OS << "Alloca(" << llvmIRToShortString(TSA.Alloca) << ")"; - } -}; - -auto IDETypeStateAnalysis::getNormalEdgeFunction( - IDETypeStateAnalysis::n_t Curr, IDETypeStateAnalysis::d_t CurrNode, - IDETypeStateAnalysis::n_t /*Succ*/, IDETypeStateAnalysis::d_t SuccNode) - -> EdgeFunction { - // Set alloca instructions of target type to uninitialized. - if (const auto *Alloca = llvm::dyn_cast(Curr)) { - if (hasMatchingType(Alloca)) { - if (CurrNode == getZeroValue() && SuccNode == Alloca) { - return TSAllocaEF(TSD, Alloca); - } - } - } - return EdgeIdentity{}; -} - -auto IDETypeStateAnalysis::getCallEdgeFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::d_t /*SrcNode*/, - IDETypeStateAnalysis::f_t /*DestinationFunction*/, - IDETypeStateAnalysis::d_t /*DestNode*/) -> EdgeFunction { - return EdgeIdentity{}; -} - -auto IDETypeStateAnalysis::getReturnEdgeFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::f_t /*CalleeFunction*/, - IDETypeStateAnalysis::n_t /*ExitSite*/, - IDETypeStateAnalysis::d_t /*ExitNode*/, - IDETypeStateAnalysis::n_t /*ReSite*/, IDETypeStateAnalysis::d_t /*RetNode*/) - -> EdgeFunction { - return EdgeIdentity{}; -} - -auto IDETypeStateAnalysis::getCallToRetEdgeFunction( - IDETypeStateAnalysis::n_t CallSite, IDETypeStateAnalysis::d_t CallNode, - IDETypeStateAnalysis::n_t /*RetSite*/, - IDETypeStateAnalysis::d_t RetSiteNode, llvm::ArrayRef Callees) - -> EdgeFunction { - const auto *CS = llvm::cast(CallSite); - for (const auto *Callee : Callees) { - std::string DemangledFname = llvm::demangle(Callee->getName().str()); - - // For now we assume that we can only generate from the return value. - // We apply the same edge function for the return value, i.e. callsite. - if (TSD->isFactoryFunction(DemangledFname)) { - PHASAR_LOG_LEVEL(DEBUG, "Processing factory function"); - if (isZeroValue(CallNode) && RetSiteNode == CS) { - return TSConstant{ - {TSD->getNextState(DemangledFname, TSD->uninit(), CS)}, TSD}; - } - } - - // For every consuming parameter and all its aliases and relevant alloca's - // we apply the same edge function. - if (TSD->isConsumingFunction(DemangledFname)) { - PHASAR_LOG_LEVEL(DEBUG, "Processing consuming function"); - for (auto Idx : TSD->getConsumerParamIdx(DemangledFname)) { - std::set AliasAndAllocas = - getWMAliasesAndAllocas(CS->getArgOperand(Idx)); - - if (CallNode == RetSiteNode && - AliasAndAllocas.find(CallNode) != AliasAndAllocas.end()) { - return TSEdgeFunction{TSD, DemangledFname, CS}; - } - } - } - } - return EdgeIdentity{}; + return identityFlow(); } -auto IDETypeStateAnalysis::getSummaryEdgeFunction( - IDETypeStateAnalysis::n_t /*CallSite*/, - IDETypeStateAnalysis::d_t /*CallNode*/, - IDETypeStateAnalysis::n_t /*RetSite*/, - IDETypeStateAnalysis::d_t /*RetSiteNode*/) -> EdgeFunction { +auto IDETypeStateAnalysisBase::getSummaryFlowFunction(n_t /*CallSite*/, + f_t /*DestFun*/) + -> FlowFunctionPtrType { return nullptr; } -IDETypeStateAnalysis::l_t IDETypeStateAnalysis::topElement() { - return TSD->top(); -} - -IDETypeStateAnalysis::l_t IDETypeStateAnalysis::bottomElement() { - return TSD->bottom(); -} - -IDETypeStateAnalysis::l_t -IDETypeStateAnalysis::join(IDETypeStateAnalysis::l_t Lhs, - IDETypeStateAnalysis::l_t Rhs) { - if (Lhs == Rhs) { - return Lhs; - } - if (Lhs == TSD->top()) { - return Rhs; - } - if (Rhs == TSD->top()) { - return Lhs; - } - return TSD->bottom(); -} - -auto IDETypeStateAnalysis::allTopFunction() -> EdgeFunction { - return AllTop{TSD->top()}; -} - -void IDETypeStateAnalysis::printNode(llvm::raw_ostream &OS, n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IDETypeStateAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IDETypeStateAnalysis::printFunction(llvm::raw_ostream &OS, - IDETypeStateAnalysis::f_t Func) const { - OS << Func->getName(); -} - -void IDETypeStateAnalysis::printEdgeFact(llvm::raw_ostream &OS, - IDETypeStateAnalysis::l_t L) const { - OS << TSD->stateToString(L); -} - -std::set -IDETypeStateAnalysis::getRelevantAllocas(IDETypeStateAnalysis::d_t V) { +auto IDETypeStateAnalysisBase::getRelevantAllocas(d_t V) -> container_type { if (RelevantAllocaCache.find(V) != RelevantAllocaCache.end()) { return RelevantAllocaCache[V]; } auto AliasSet = getWMAliasSet(V); - std::set RelevantAllocas; - PHASAR_LOG_LEVEL(DEBUG, "Compute relevant alloca's of " - << IDETypeStateAnalysis::DtoString(V)); + container_type RelevantAllocas; + PHASAR_LOG_LEVEL(DEBUG, "Compute relevant alloca's of " << DToString(V)); for (const auto *Alias : AliasSet) { - PHASAR_LOG_LEVEL(DEBUG, - "Alias: " << IDETypeStateAnalysis::DtoString(Alias)); + PHASAR_LOG_LEVEL(DEBUG, "Alias: " << DToString(Alias)); // Collect the pointer operand of a aliased load instruciton if (const auto *Load = llvm::dyn_cast(Alias)) { if (hasMatchingType(Alias)) { - PHASAR_LOG_LEVEL(DEBUG, - " -> Alloca: " << IDETypeStateAnalysis::DtoString( - Load->getPointerOperand())); + PHASAR_LOG_LEVEL( + DEBUG, " -> Alloca: " << DToString(Load->getPointerOperand())); RelevantAllocas.insert(Load->getPointerOperand()); } } else { // For all other types of aliases, e.g. callsites, function arguments, // we check store instructions where thoses aliases are value operands. for (const auto *User : Alias->users()) { - PHASAR_LOG_LEVEL(DEBUG, - " User: " << IDETypeStateAnalysis::DtoString(User)); + PHASAR_LOG_LEVEL(DEBUG, " User: " << DToString(User)); if (const auto *Store = llvm::dyn_cast(User)) { if (hasMatchingType(Store)) { - PHASAR_LOG_LEVEL( - DEBUG, " -> Alloca: " << IDETypeStateAnalysis::DtoString( - Store->getPointerOperand())); + PHASAR_LOG_LEVEL(DEBUG, " -> Alloca: " << DToString( + Store->getPointerOperand())); RelevantAllocas.insert(Store->getPointerOperand()); } } @@ -623,11 +257,9 @@ IDETypeStateAnalysis::getRelevantAllocas(IDETypeStateAnalysis::d_t V) { return RelevantAllocas; } -std::set -IDETypeStateAnalysis::getWMAliasSet(IDETypeStateAnalysis::d_t V) { +auto IDETypeStateAnalysisBase::getWMAliasSet(d_t V) -> container_type { if (AliasCache.find(V) != AliasCache.end()) { - std::set AliasSet(AliasCache[V].begin(), - AliasCache[V].end()); + container_type AliasSet(AliasCache[V].begin(), AliasCache[V].end()); return AliasSet; } auto PTS = PT.getAliasSet(V); @@ -636,28 +268,25 @@ IDETypeStateAnalysis::getWMAliasSet(IDETypeStateAnalysis::d_t V) { AliasCache[Alias] = *PTS; } } - std::set AliasSet(PTS->begin(), PTS->end()); + container_type AliasSet(PTS->begin(), PTS->end()); return AliasSet; } -std::set -IDETypeStateAnalysis::getWMAliasesAndAllocas(IDETypeStateAnalysis::d_t V) { - std::set AliasAndAllocas; - std::set RelevantAllocas = getRelevantAllocas(V); - std::set Aliases = getWMAliasSet(V); +auto IDETypeStateAnalysisBase::getWMAliasesAndAllocas(d_t V) -> container_type { + container_type AliasAndAllocas; + container_type RelevantAllocas = getRelevantAllocas(V); + container_type Aliases = getWMAliasSet(V); AliasAndAllocas.insert(Aliases.begin(), Aliases.end()); AliasAndAllocas.insert(RelevantAllocas.begin(), RelevantAllocas.end()); return AliasAndAllocas; } -std::set -IDETypeStateAnalysis::getLocalAliasesAndAllocas(IDETypeStateAnalysis::d_t V, - const std::string & /*Fname*/) { - std::set AliasAndAllocas; - std::set RelevantAllocas = getRelevantAllocas(V); - std::set - Aliases; // = - // IRDB->getAliasGraph(Fname)->getAliasSet(V); +auto IDETypeStateAnalysisBase::getLocalAliasesAndAllocas( + d_t V, llvm::StringRef /*Fname*/) -> container_type { + container_type AliasAndAllocas; + container_type RelevantAllocas = getRelevantAllocas(V); + container_type Aliases; // = + // IRDB->getAliasGraph(Fname)->getAliasSet(V); for (const auto *Alias : Aliases) { if (hasMatchingType(Alias)) { AliasAndAllocas.insert(Alias); @@ -667,45 +296,38 @@ IDETypeStateAnalysis::getLocalAliasesAndAllocas(IDETypeStateAnalysis::d_t V, AliasAndAllocas.insert(RelevantAllocas.begin(), RelevantAllocas.end()); return AliasAndAllocas; } -bool hasMatchingTypeName(const llvm::Type *Ty, const std::string &Pattern) { + +bool IDETypeStateAnalysisBase::hasMatchingTypeName(const llvm::Type *Ty) { if (const auto *StructTy = llvm::dyn_cast(Ty)) { - return StructTy->getName().contains(Pattern); + return isTypeNameOfInterest(StructTy->getName()); } // primitive type std::string Str; llvm::raw_string_ostream S(Str); S << *Ty; S.flush(); - return Str.find(Pattern) != std::string::npos; + return isTypeNameOfInterest(Str); } -bool IDETypeStateAnalysis::hasMatchingType(IDETypeStateAnalysis::d_t V) { + +bool IDETypeStateAnalysisBase::hasMatchingType(d_t V) { // General case if (V->getType()->isPointerTy()) { - if (hasMatchingTypeName(V->getType()->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + if (hasMatchingTypeName(V->getType()->getPointerElementType())) { return true; } } if (const auto *Alloca = llvm::dyn_cast(V)) { if (Alloca->getAllocatedType()->isPointerTy()) { if (hasMatchingTypeName( - Alloca->getAllocatedType()->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + Alloca->getAllocatedType()->getPointerElementType())) { return true; } } return false; } if (const auto *Load = llvm::dyn_cast(V)) { - if (Load->getPointerOperand() - ->getType() - ->getPointerElementType() - ->isPointerTy()) { - if (hasMatchingTypeName(Load->getPointerOperand() - ->getType() - ->getPointerElementType() - ->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + if (Load->getType()->isPointerTy()) { + if (hasMatchingTypeName(Load->getType()->getPointerElementType())) { return true; } } @@ -714,8 +336,7 @@ bool IDETypeStateAnalysis::hasMatchingType(IDETypeStateAnalysis::d_t V) { if (const auto *Store = llvm::dyn_cast(V)) { if (Store->getValueOperand()->getType()->isPointerTy()) { if (hasMatchingTypeName( - Store->getValueOperand()->getType()->getPointerElementType(), - TSD->getTypeNameOfInterest())) { + Store->getValueOperand()->getType()->getPointerElementType())) { return true; } } @@ -724,76 +345,4 @@ bool IDETypeStateAnalysis::hasMatchingType(IDETypeStateAnalysis::d_t V) { return false; } -void IDETypeStateAnalysis::emitTextReport( - const SolverResults &SR, - llvm::raw_ostream &OS) { - - LLVMBasedCFG CFG; - OS << "\n======= TYPE STATE RESULTS =======\n"; - for (const auto &F : IRDB->getAllFunctions()) { - OS << '\n' << getFunctionNameFromIR(F) << '\n'; - for (const auto &BB : *F) { - for (const auto &I : BB) { - auto Results = SR.resultsAt(&I, true); - if (CFG.isExitInst(&I)) { - OS << "\nAt exit stmt: " << NtoString(&I) << '\n'; - for (auto Res : Results) { - if (const auto *Alloca = - llvm::dyn_cast(Res.first)) { - if (Res.second == TSD->error()) { - OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " - << DtoString(Res.first) << '\n'; - for (const auto *Pred : CFG.getPredsOf(&I)) { - OS << "\nPredecessor: " << NtoString(Pred) << '\n'; - auto PredResults = SR.resultsAt(Pred, true); - for (auto Res : PredResults) { - if (Res.first == Alloca) { - OS << "Pred State: " << LtoString(Res.second) << '\n'; - } - } - } - OS << "============================\n"; - } else { - OS << "\nAlloca : " << DtoString(Res.first) - << "\nState : " << LtoString(Res.second) << '\n'; - } - } else { - OS << "\nInst: " << NtoString(&I) << '\n' - << "Fact: " << DtoString(Res.first) << '\n' - << "State: " << LtoString(Res.second) << '\n'; - } - } - } else { - for (auto Res : Results) { - if (const auto *Alloca = - llvm::dyn_cast(Res.first)) { - if (Res.second == TSD->error()) { - OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " - << DtoString(Res.first) << '\n' - << "\nAt IR Inst: " << NtoString(&I) << '\n'; - for (const auto *Pred : CFG.getPredsOf(&I)) { - OS << "\nPredecessor: " << NtoString(Pred) << '\n'; - auto PredResults = SR.resultsAt(Pred, true); - for (auto Res : PredResults) { - if (Res.first == Alloca) { - OS << "Pred State: " << LtoString(Res.second) << '\n'; - } - } - } - OS << "============================\n"; - } - } else { - OS << "\nInst: " << NtoString(&I) << '\n' - << "Fact: " << DtoString(Res.first) << '\n' - << "State: " << LtoString(Res.second) << '\n'; - } - } - } - } - } - OS << "\n--------------------------------------------\n"; - } -} - -} // namespace psr +} // namespace psr::detail diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp index 7a9d83212..c98996653 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp @@ -177,21 +177,6 @@ bool IFDSConstAnalysis::isZeroValue(IFDSConstAnalysis::d_t Fact) const { return LLVMZeroValue::isLLVMZeroValue(Fact); } -void IFDSConstAnalysis::printNode(llvm::raw_ostream &OS, - IFDSConstAnalysis::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IFDSConstAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - IFDSConstAnalysis::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IFDSConstAnalysis::printFunction(llvm::raw_ostream &OS, - IFDSConstAnalysis::f_t Func) const { - OS << Func->getName(); -} - void IFDSConstAnalysis::printInitMemoryLocations() { PHASAR_LOG_LEVEL( DEBUG, "Printing all initialized memory location (or one of its alias)"); diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp index 1f1674dc4..8b1eb7341 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp @@ -34,6 +34,8 @@ #include #include +#include + namespace psr { IFDSFieldSensTaintAnalysis::IFDSFieldSensTaintAnalysis( @@ -259,3 +261,25 @@ void IFDSFieldSensTaintAnalysis::emitTextReport( } } // namespace psr + +std::string psr::DToString(const ExtendedValue &EV) { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + OS << llvmIRToString(EV.getValue()) << "\n"; + for (const auto *MemLocationPart : EV.getMemLocationSeq()) { + OS << "A:\t" << llvmIRToString(MemLocationPart) << "\n"; + } + if (!EV.getEndOfTaintedBlockLabel().empty()) { + OS << "L:\t" << EV.getEndOfTaintedBlockLabel() << "\n"; + } + if (EV.isVarArg()) { + OS << "VT:\t" << EV.isVarArgTemplate() << "\n"; + for (const auto *VAListMemLocationPart : EV.getVaListMemLocationSeq()) { + OS << "VLA:\t" << llvmIRToString(VAListMemLocationPart) << "\n"; + } + OS << "VI:\t" << EV.getVarArgIndex() << "\n"; + OS << "CI:\t" << EV.getCurrentVarArgIndex() << "\n"; + } + + return Ret; +} diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp index 1e3f7b459..c28cb8b0e 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp @@ -78,19 +78,4 @@ bool IFDSProtoAnalysis::isZeroValue(IFDSProtoAnalysis::d_t Fact) const { return LLVMZeroValue::isLLVMZeroValue(Fact); } -void IFDSProtoAnalysis::printNode(llvm::raw_ostream &OS, - IFDSProtoAnalysis::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IFDSProtoAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - IFDSProtoAnalysis::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IFDSProtoAnalysis::printFunction(llvm::raw_ostream &OS, - IFDSProtoAnalysis::f_t Func) const { - OS << Func->getName(); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.cpp index 9bf5c0a59..2fea082af 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.cpp @@ -73,19 +73,4 @@ bool IFDSSignAnalysis::isZeroValue(IFDSSignAnalysis::d_t Fact) const { return LLVMZeroValue::isLLVMZeroValue(Fact); } -void IFDSSignAnalysis::printNode(llvm::raw_ostream &OS, - IFDSSignAnalysis::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IFDSSignAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - IFDSSignAnalysis::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IFDSSignAnalysis::printFunction(llvm::raw_ostream &OS, - IFDSSignAnalysis::f_t Func) const { - OS << Func->getName(); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.cpp index 6499eebb6..e67d54fbf 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.cpp @@ -73,19 +73,4 @@ bool IFDSSolverTest::isZeroValue(IFDSSolverTest::d_t Fact) const { return LLVMZeroValue::isLLVMZeroValue(Fact); } -void IFDSSolverTest::printNode(llvm::raw_ostream &OS, - IFDSSolverTest::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IFDSSolverTest::printDataFlowFact(llvm::raw_ostream &OS, - IFDSSolverTest::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IFDSSolverTest::printFunction(llvm::raw_ostream &OS, - IFDSSolverTest::f_t Func) const { - OS << Func->getName(); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index ddf60d016..4306af47c 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -359,19 +359,6 @@ bool IFDSTaintAnalysis::isZeroValue(d_t FlowFact) const { return LLVMZeroValue::isLLVMZeroValue(FlowFact); } -void IFDSTaintAnalysis::printNode(llvm::raw_ostream &Os, n_t Inst) const { - Os << llvmIRToString(Inst); -} - -void IFDSTaintAnalysis::printDataFlowFact(llvm::raw_ostream &Os, - d_t FlowFact) const { - Os << llvmIRToString(FlowFact); -} - -void IFDSTaintAnalysis::printFunction(llvm::raw_ostream &Os, f_t Fun) const { - Os << Fun->getName(); -} - void IFDSTaintAnalysis::emitTextReport( const SolverResults & /*SR*/, llvm::raw_ostream &OS) { diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp index 53ff5c972..e798db4f2 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp @@ -98,19 +98,4 @@ bool IFDSTypeAnalysis::isZeroValue(IFDSTypeAnalysis::d_t Fact) const { return LLVMZeroValue::isLLVMZeroValue(Fact); } -void IFDSTypeAnalysis::printNode(llvm::raw_ostream &OS, - IFDSTypeAnalysis::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IFDSTypeAnalysis::printDataFlowFact(llvm::raw_ostream &OS, - IFDSTypeAnalysis::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IFDSTypeAnalysis::printFunction(llvm::raw_ostream &OS, - IFDSTypeAnalysis::f_t Func) const { - OS << Func->getName(); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp index 2537972d9..b75979ed6 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp @@ -16,6 +16,7 @@ #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/Printer.h" #include "llvm/IR/AbstractCallSite.h" #include "llvm/IR/Constants.h" @@ -405,21 +406,6 @@ bool IFDSUninitializedVariables::isZeroValue( return LLVMZeroValue::isLLVMZeroValue(Fact); } -void IFDSUninitializedVariables::printNode( - llvm::raw_ostream &OS, IFDSUninitializedVariables::n_t Stmt) const { - OS << llvmIRToString(Stmt); -} - -void IFDSUninitializedVariables::printDataFlowFact( - llvm::raw_ostream &OS, IFDSUninitializedVariables::d_t Fact) const { - OS << llvmIRToShortString(Fact); -} - -void IFDSUninitializedVariables::printFunction( - llvm::raw_ostream &OS, IFDSUninitializedVariables::f_t Func) const { - OS << Func->getName(); -} - void IFDSUninitializedVariables::emitTextReport( const SolverResults & /*Result*/, @@ -439,13 +425,11 @@ void IFDSUninitializedVariables::emitTextReport( for (const auto &User : UndefValueUses) { OS << "\n--------------------------------- " << ++Count << ". Use ---------------------------------\n\n"; - OS << "At IR statement: "; - printNode(OS, User.first); + OS << "At IR statement: " << NToString(User.first); OS << "\n in function: " << getFunctionNameFromIR(User.first); OS << "\n in module : " << getModuleIDFromIR(User.first) << "\n\n"; for (const auto *UndefV : User.second) { - OS << " Uninit Value: "; - printDataFlowFact(OS, UndefV); + OS << " Uninit Value: " << DToString(UndefV); OS << '\n'; } } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp index b6b8895ed..ba640d0ba 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp @@ -9,70 +9,114 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" + +#include "llvm/ADT/StringMap.h" #include "llvm/Support/ErrorHandling.h" +#include + namespace psr { +/** + * We use the following lattice + * BOT = all information + * + * UNINIT OPENED CLOSED ERROR + * + * TOP = no information + */ +// enum class CSTDFILEIOState { +// TOP = 42, +// UNINIT = 0, +// OPENED = 1, +// CLOSED = 2, +// ERROR = 3, +// BOT = 4 +// }; + +namespace { + +/** + * The STAR token represents all API functions besides fopen(), fdopen() and + * fclose(). FOPEN covers fopen() and fdopen() since both functions are + * modeled the same in our case. + */ +enum class CSTDFILEIOToken { FOPEN = 0, FCLOSE = 1, STAR = 2 }; + +constexpr CSTDFILEIOState Delta[3][5] = { + /* FOPEN */ + {CSTDFILEIOState::OPENED, CSTDFILEIOState::OPENED, CSTDFILEIOState::OPENED, + CSTDFILEIOState::ERROR, CSTDFILEIOState::OPENED}, + /* FCLOSE */ + {CSTDFILEIOState::ERROR, CSTDFILEIOState::CLOSED, CSTDFILEIOState::ERROR, + CSTDFILEIOState::ERROR, CSTDFILEIOState::BOT}, + /* STAR */ + {CSTDFILEIOState::ERROR, CSTDFILEIOState::OPENED, CSTDFILEIOState::ERROR, + CSTDFILEIOState::ERROR, CSTDFILEIOState::BOT}, +}; + +const llvm::StringMap> &getStdFileIOFuncs() noexcept { + // Return value is modeled as -1 + static const llvm::StringMap> StdFileIOFuncs = { + {"fopen", {-1}}, {"fdopen", {-1}}, {"fclose", {0}}, + {"fread", {3}}, {"fwrite", {3}}, {"fgetc", {0}}, + {"fgetwc", {0}}, {"fgets", {2}}, {"getc", {0}}, + {"getwc", {0}}, {"_IO_getc", {0}}, {"ungetc", {1}}, + {"ungetwc", {1}}, {"fputc", {1}}, {"fputwc", {1}}, + {"fputs", {1}}, {"putc", {1}}, {"putwc", {1}}, + {"_IO_putc", {1}}, {"fprintf", {0}}, {"fwprintf", {0}}, + {"vfprintf", {0}}, {"vfwprintf", {0}}, {"__isoc99_fscanf", {0}}, + {"fscanf", {0}}, {"fwscanf", {0}}, {"vfscanf", {0}}, + {"vfwscanf", {0}}, {"fflush", {0}}, {"fseek", {0}}, + {"ftell", {0}}, {"rewind", {0}}, {"fgetpos", {0}}, + {"fsetpos", {0}}, {"fileno", {0}}}; + return StdFileIOFuncs; +} + +CSTDFILEIOToken funcNameToToken(llvm::StringRef F) { + if (F == "fopen" || F == "fdopen") { + return CSTDFILEIOToken::FOPEN; + } + if (F == "fclose") { + return CSTDFILEIOToken::FCLOSE; + } + return CSTDFILEIOToken::STAR; +} -// Return value is modeled as -1 -const std::map> - CSTDFILEIOTypeStateDescription::StdFileIOFuncs = { - {"fopen", {-1}}, {"fdopen", {-1}}, {"fclose", {0}}, - {"fread", {3}}, {"fwrite", {3}}, {"fgetc", {0}}, - {"fgetwc", {0}}, {"fgets", {2}}, {"getc", {0}}, - {"getwc", {0}}, {"_IO_getc", {0}}, {"ungetc", {1}}, - {"ungetwc", {1}}, {"fputc", {1}}, {"fputwc", {1}}, - {"fputs", {1}}, {"putc", {1}}, {"putwc", {1}}, - {"_IO_putc", {1}}, {"fprintf", {0}}, {"fwprintf", {0}}, - {"vfprintf", {0}}, {"vfwprintf", {0}}, {"__isoc99_fscanf", {0}}, - {"fscanf", {0}}, {"fwscanf", {0}}, {"vfscanf", {0}}, - {"vfwscanf", {0}}, {"fflush", {0}}, {"fseek", {0}}, - {"ftell", {0}}, {"rewind", {0}}, {"fgetpos", {0}}, - {"fsetpos", {0}}, {"fileno", {0}}}; +} // namespace // delta[Token][State] = next State // Token: FOPEN = 0, FCLOSE = 1, STAR = 2 // States: UNINIT = 0, OPENED = 1, CLOSED = 2, ERROR = 3, BOT = 4 -const CSTDFILEIOTypeStateDescription::CSTDFILEIOState - CSTDFILEIOTypeStateDescription::Delta[3][5] = { - /* FOPEN */ - {CSTDFILEIOState::OPENED, CSTDFILEIOState::OPENED, - CSTDFILEIOState::OPENED, CSTDFILEIOState::ERROR, - CSTDFILEIOState::OPENED}, - /* FCLOSE */ - {CSTDFILEIOState::ERROR, CSTDFILEIOState::CLOSED, - CSTDFILEIOState::ERROR, CSTDFILEIOState::ERROR, CSTDFILEIOState::BOT}, - /* STAR */ - {CSTDFILEIOState::ERROR, CSTDFILEIOState::OPENED, - CSTDFILEIOState::ERROR, CSTDFILEIOState::ERROR, CSTDFILEIOState::BOT}, -}; bool CSTDFILEIOTypeStateDescription::isFactoryFunction( - const std::string &F) const { + llvm::StringRef F) const { if (isAPIFunction(F)) { - return StdFileIOFuncs.at(F).find(-1) != StdFileIOFuncs.at(F).end(); + return getStdFileIOFuncs().lookup(F).count(-1); } return false; } bool CSTDFILEIOTypeStateDescription::isConsumingFunction( - const std::string &F) const { + llvm::StringRef F) const { if (isAPIFunction(F)) { - return StdFileIOFuncs.at(F).find(-1) == StdFileIOFuncs.at(F).end(); + return !getStdFileIOFuncs().lookup(F).count(-1); } return false; } -bool CSTDFILEIOTypeStateDescription::isAPIFunction(const std::string &F) const { - return StdFileIOFuncs.find(F) != StdFileIOFuncs.end(); +bool CSTDFILEIOTypeStateDescription::isAPIFunction(llvm::StringRef F) const { + return getStdFileIOFuncs().count(F); } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::getNextState( - std::string Tok, TypeStateDescription::State S) const { +CSTDFILEIOState +CSTDFILEIOTypeStateDescription::getNextState(llvm::StringRef Tok, + State S) const { if (isAPIFunction(Tok)) { auto X = static_cast>( funcNameToToken(Tok)); - auto Ret = Delta[X][S]; + auto Ret = Delta[X][int(S)]; // if (ret == error()) { // std::cerr << "getNextState(" << Tok << ", " << stateToString(S) // << ") = " << stateToString(Ret) << std::endl; @@ -86,16 +130,16 @@ std::string CSTDFILEIOTypeStateDescription::getTypeNameOfInterest() const { return "struct._IO_FILE"; } -std::set CSTDFILEIOTypeStateDescription::getConsumerParamIdx( - const std::string &F) const { +std::set +CSTDFILEIOTypeStateDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { - return StdFileIOFuncs.at(F); + return getStdFileIOFuncs().lookup(F); } return {}; } std::set -CSTDFILEIOTypeStateDescription::getFactoryParamIdx(const std::string &F) const { +CSTDFILEIOTypeStateDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -103,9 +147,8 @@ CSTDFILEIOTypeStateDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -std::string CSTDFILEIOTypeStateDescription::stateToString( - TypeStateDescription::State S) const { - switch (S) { +llvm::StringRef to_string(CSTDFILEIOState State) noexcept { + switch (State) { case CSTDFILEIOState::TOP: return "TOP"; break; @@ -124,41 +167,31 @@ std::string CSTDFILEIOTypeStateDescription::stateToString( case CSTDFILEIOState::BOT: return "BOT"; break; - default: - llvm::report_fatal_error("received unknown state!"); - break; } + + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::bottom() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::bottom() const { return CSTDFILEIOState::BOT; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::top() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::top() const { return CSTDFILEIOState::TOP; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::uninit() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::uninit() const { return CSTDFILEIOState::UNINIT; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::start() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::start() const { return CSTDFILEIOState::OPENED; } -TypeStateDescription::State CSTDFILEIOTypeStateDescription::error() const { +CSTDFILEIOState CSTDFILEIOTypeStateDescription::error() const { return CSTDFILEIOState::ERROR; } -CSTDFILEIOTypeStateDescription::CSTDFILEIOToken -CSTDFILEIOTypeStateDescription::funcNameToToken(const std::string &F) { - if (F == "fopen" || F == "fdopen") { - return CSTDFILEIOToken::FOPEN; - } - if (F == "fclose") { - return CSTDFILEIOToken::FCLOSE; - } - return CSTDFILEIOToken::STAR; -} +template class IDETypeStateAnalysis; } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp index ec2957402..df37f0bcb 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp @@ -21,12 +21,11 @@ namespace psr { // Return value is modeled as -1 -const std::map> - OpenSSLEVPKDFCTXDescription::OpenSSLEVPKDFFuncs = { - {"EVP_KDF_CTX_new", {-1}}, - {"EVP_KDF_CTX_set_params", {0}}, - {"EVP_KDF_derive", {0}}, - {"EVP_KDF_CTX_free", {0}} +static const std::map> OpenSSLEVPKDFFuncs = { + {"EVP_KDF_CTX_new", {-1}}, + {"EVP_KDF_CTX_set_params", {0}}, + {"EVP_KDF_derive", {0}}, + {"EVP_KDF_CTX_free", {0}} }; @@ -39,86 +38,82 @@ const std::map> // // States: UNINIT = 5, CTX_ATTACHED =1, PARAM_INIT = 2, // DERIVED = 3, ERROR = 4, BOT = 0 -const OpenSSLEVPKDFCTXDescription::OpenSSLEVPKDFState - OpenSSLEVPKDFCTXDescription::Delta[5][6] = { - - /* EVP_KDF_CTX_NEW */ - {OpenSSLEVPKDFState::CTX_ATTACHED, OpenSSLEVPKDFState::CTX_ATTACHED, - OpenSSLEVPKDFState::CTX_ATTACHED, OpenSSLEVPKDFState::CTX_ATTACHED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::CTX_ATTACHED}, - /* EVP_KDF_CTX_SET_PARAMS */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::PARAM_INIT, - OpenSSLEVPKDFState::PARAM_INIT, OpenSSLEVPKDFState::PARAM_INIT, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, - /* DERIVE */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR, - OpenSSLEVPKDFState::DERIVED, OpenSSLEVPKDFState::DERIVED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, - /* EVP_KDF_CTX_FREE */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::UNINIT, - OpenSSLEVPKDFState::UNINIT, OpenSSLEVPKDFState::UNINIT, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, - - /* STAR */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::CTX_ATTACHED, - OpenSSLEVPKDFState::PARAM_INIT, OpenSSLEVPKDFState::DERIVED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::ERROR}, +const OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::Delta[5][6] = { + + /* EVP_KDF_CTX_NEW */ + {OpenSSLEVPKDFCTXState::CTX_ATTACHED, OpenSSLEVPKDFCTXState::CTX_ATTACHED, + OpenSSLEVPKDFCTXState::CTX_ATTACHED, OpenSSLEVPKDFCTXState::CTX_ATTACHED, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + /* EVP_KDF_CTX_SET_PARAMS */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::PARAM_INIT, + OpenSSLEVPKDFCTXState::PARAM_INIT, OpenSSLEVPKDFCTXState::PARAM_INIT, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, + /* DERIVE */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR, + OpenSSLEVPKDFCTXState::DERIVED, OpenSSLEVPKDFCTXState::DERIVED, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, + /* EVP_KDF_CTX_FREE */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::UNINIT, + OpenSSLEVPKDFCTXState::UNINIT, OpenSSLEVPKDFCTXState::UNINIT, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, + + /* STAR */ + {OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::CTX_ATTACHED, + OpenSSLEVPKDFCTXState::PARAM_INIT, OpenSSLEVPKDFCTXState::DERIVED, + OpenSSLEVPKDFCTXState::ERROR, OpenSSLEVPKDFCTXState::ERROR}, }; -bool OpenSSLEVPKDFCTXDescription::isFactoryFunction( - const std::string &F) const { +bool OpenSSLEVPKDFCTXDescription::isFactoryFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) != OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFCTXDescription::isConsumingFunction( - const std::string &F) const { +bool OpenSSLEVPKDFCTXDescription::isConsumingFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) == OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFCTXDescription::isAPIFunction(const std::string &F) const { +bool OpenSSLEVPKDFCTXDescription::isAPIFunction(llvm::StringRef F) const { return OpenSSLEVPKDFFuncs.find(F) != OpenSSLEVPKDFFuncs.end(); } -TypeStateDescription::State -OpenSSLEVPKDFCTXDescription::getNextState(std::string Tok, +OpenSSLEVPKDFCTXState +OpenSSLEVPKDFCTXDescription::getNextState(llvm::StringRef Tok, TypeStateDescription::State S) const { if (isAPIFunction(Tok)) { auto NameToTok = funcNameToToken(Tok); auto Ret = Delta[static_cast>( - NameToTok)][S]; + NameToTok)][int(S)]; // std::cout << "delta[" << Tok << ", " << stateToString(S) // << "] = " << stateToString(ret) << std::endl; return Ret; } - return OpenSSLEVPKDFState::BOT; + return OpenSSLEVPKDFCTXState::BOT; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::getNextState( - const std::string &Tok, TypeStateDescription::State S, +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S, const llvm::CallBase *CallSite) const { if (isAPIFunction(Tok)) { auto NameToTok = funcNameToToken(Tok); auto Ret = Delta[static_cast>( - NameToTok)][S]; + NameToTok)][int(S)]; if (NameToTok == OpenSSLEVTKDFToken::EVP_KDF_CTX_NEW) { // require the kdf here to be in KDF_FETCHED state // requiredKDFState[make_pair(CS.getInstruction(), CS.getArgOperand(0))] = - // (OpenSSLEVPKDFDescription::OpenSSLEVPKDFState::KDF_FETCHED); + // (OpenSSLEVPKDFDescription::OpenSSLEVPKDFCTXState::KDF_FETCHED); // cout << "## Factory-Call: "; // cout.flush(); // cout << llvmIRToShortString(CS.getInstruction()) << endl; auto KdfState = KDFAnalysisResults.resultAt(CallSite, CallSite->getArgOperand(0)); - if (KdfState != - OpenSSLEVPKDFDescription::OpenSSLEVPKDFState::KDF_FETCHED) { + if (KdfState != OpenSSLEVPKDFState::KDF_FETCHED) { return error(); } } @@ -126,7 +121,7 @@ TypeStateDescription::State OpenSSLEVPKDFCTXDescription::getNextState( // << "] = " << stateToString(ret) << std::endl; return Ret; } - return OpenSSLEVPKDFState::BOT; + return OpenSSLEVPKDFCTXState::BOT; } std::string OpenSSLEVPKDFCTXDescription::getTypeNameOfInterest() const { @@ -134,7 +129,7 @@ std::string OpenSSLEVPKDFCTXDescription::getTypeNameOfInterest() const { } std::set -OpenSSLEVPKDFCTXDescription::getConsumerParamIdx(const std::string &F) const { +OpenSSLEVPKDFCTXDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { return OpenSSLEVPKDFFuncs.at(F); } @@ -142,7 +137,7 @@ OpenSSLEVPKDFCTXDescription::getConsumerParamIdx(const std::string &F) const { } std::set -OpenSSLEVPKDFCTXDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLEVPKDFCTXDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -150,59 +145,57 @@ OpenSSLEVPKDFCTXDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -std::string OpenSSLEVPKDFCTXDescription::stateToString( - TypeStateDescription::State S) const { - switch (S) { - case OpenSSLEVPKDFState::TOP: +llvm::StringRef to_string(OpenSSLEVPKDFCTXState State) noexcept { + switch (State) { + case OpenSSLEVPKDFCTXState::TOP: return "TOP"; break; - case OpenSSLEVPKDFState::UNINIT: + case OpenSSLEVPKDFCTXState::UNINIT: return "UNINIT"; break; - case OpenSSLEVPKDFState::CTX_ATTACHED: + case OpenSSLEVPKDFCTXState::CTX_ATTACHED: return "CTX_ATTACHED"; break; - case OpenSSLEVPKDFState::PARAM_INIT: + case OpenSSLEVPKDFCTXState::PARAM_INIT: return "PARAM_INIT"; break; - case OpenSSLEVPKDFState::DERIVED: + case OpenSSLEVPKDFCTXState::DERIVED: return "DERIVED"; break; - case OpenSSLEVPKDFState::ERROR: + case OpenSSLEVPKDFCTXState::ERROR: return "ERROR"; break; - case OpenSSLEVPKDFState::BOT: + case OpenSSLEVPKDFCTXState::BOT: return "BOT"; break; - default: - llvm::report_fatal_error("received unknown state!"); - break; } + + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::bottom() const { - return OpenSSLEVPKDFState::BOT; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::bottom() const { + return OpenSSLEVPKDFCTXState::BOT; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::top() const { - return OpenSSLEVPKDFState::TOP; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::top() const { + return OpenSSLEVPKDFCTXState::TOP; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::uninit() const { - return OpenSSLEVPKDFState::UNINIT; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::uninit() const { + return OpenSSLEVPKDFCTXState::UNINIT; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::start() const { - return OpenSSLEVPKDFState::CTX_ATTACHED; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::start() const { + return OpenSSLEVPKDFCTXState::CTX_ATTACHED; } -TypeStateDescription::State OpenSSLEVPKDFCTXDescription::error() const { - return OpenSSLEVPKDFState::ERROR; +OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::error() const { + return OpenSSLEVPKDFCTXState::ERROR; } OpenSSLEVPKDFCTXDescription::OpenSSLEVTKDFToken -OpenSSLEVPKDFCTXDescription::funcNameToToken(const std::string &F) { +OpenSSLEVPKDFCTXDescription::funcNameToToken(llvm::StringRef F) { if (F == "EVP_KDF_CTX_new") { return OpenSSLEVTKDFToken::EVP_KDF_CTX_NEW; } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp index 89068b96f..4c0973cf7 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp @@ -9,6 +9,8 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" + #include "llvm/Support/ErrorHandling.h" #include @@ -16,9 +18,8 @@ namespace psr { // Return value is modeled as -1 -const std::map> - OpenSSLEVPKDFDescription::OpenSSLEVPKDFFuncs = {{"EVP_KDF_fetch", {-1}}, - {"EVP_KDF_free", {0}} +static const std::map> OpenSSLEVPKDFFuncs = { + {"EVP_KDF_fetch", {-1}}, {"EVP_KDF_free", {0}} }; @@ -28,44 +29,43 @@ const std::map> // STAR = 2 // // States: UNINIT = 0, KDF_FETCHED = 1, ERROR = 2, BOT = 3 -const OpenSSLEVPKDFDescription::OpenSSLEVPKDFState - OpenSSLEVPKDFDescription::Delta[3][4] = { - /* EVP_KDF_FETCH */ - {OpenSSLEVPKDFState::KDF_FETCHED, OpenSSLEVPKDFState::ERROR, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED}, - /* EVP_KDF_CTX_FREE */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::UNINIT, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, - - /* STAR */ - {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED, - OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, +const OpenSSLEVPKDFState OpenSSLEVPKDFDescription::Delta[3][4] = { + /* EVP_KDF_FETCH */ + {OpenSSLEVPKDFState::KDF_FETCHED, OpenSSLEVPKDFState::ERROR, + OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED}, + /* EVP_KDF_CTX_FREE */ + {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::UNINIT, + OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, + + /* STAR */ + {OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::KDF_FETCHED, + OpenSSLEVPKDFState::ERROR, OpenSSLEVPKDFState::BOT}, }; -bool OpenSSLEVPKDFDescription::isFactoryFunction(const std::string &F) const { +bool OpenSSLEVPKDFDescription::isFactoryFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) != OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFDescription::isConsumingFunction(const std::string &F) const { +bool OpenSSLEVPKDFDescription::isConsumingFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLEVPKDFFuncs.at(F).find(-1) == OpenSSLEVPKDFFuncs.at(F).end(); } return false; } -bool OpenSSLEVPKDFDescription::isAPIFunction(const std::string &F) const { +bool OpenSSLEVPKDFDescription::isAPIFunction(llvm::StringRef F) const { return OpenSSLEVPKDFFuncs.find(F) != OpenSSLEVPKDFFuncs.end(); } -TypeStateDescription::State -OpenSSLEVPKDFDescription::getNextState(std::string Tok, +OpenSSLEVPKDFState +OpenSSLEVPKDFDescription::getNextState(llvm::StringRef Tok, TypeStateDescription::State S) const { if (isAPIFunction(Tok)) { auto Ret = Delta[static_cast>( - funcNameToToken(Tok))][S]; + funcNameToToken(Tok))][int(S)]; // std::cout << "Delta[" << Tok << ", " << stateToString(S) // << "] = " << stateToString(ret) << std::endl; return Ret; @@ -78,7 +78,7 @@ std::string OpenSSLEVPKDFDescription::getTypeNameOfInterest() const { } std::set -OpenSSLEVPKDFDescription::getConsumerParamIdx(const std::string &F) const { +OpenSSLEVPKDFDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { return OpenSSLEVPKDFFuncs.at(F); } @@ -86,7 +86,7 @@ OpenSSLEVPKDFDescription::getConsumerParamIdx(const std::string &F) const { } std::set -OpenSSLEVPKDFDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLEVPKDFDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -94,9 +94,8 @@ OpenSSLEVPKDFDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -std::string -OpenSSLEVPKDFDescription::stateToString(TypeStateDescription::State S) const { - switch (S) { +llvm::StringRef to_string(OpenSSLEVPKDFState State) noexcept { + switch (State) { case OpenSSLEVPKDFState::TOP: return "TOP"; case OpenSSLEVPKDFState::UNINIT: @@ -107,34 +106,32 @@ OpenSSLEVPKDFDescription::stateToString(TypeStateDescription::State S) const { return "ERROR"; case OpenSSLEVPKDFState::BOT: return "BOT"; - default: - llvm::report_fatal_error("received unknown state!"); - break; } + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLEVPKDFDescription::bottom() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::bottom() const { return OpenSSLEVPKDFState::BOT; } -TypeStateDescription::State OpenSSLEVPKDFDescription::top() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::top() const { return OpenSSLEVPKDFState::TOP; } -TypeStateDescription::State OpenSSLEVPKDFDescription::uninit() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::uninit() const { return OpenSSLEVPKDFState::UNINIT; } -TypeStateDescription::State OpenSSLEVPKDFDescription::start() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::start() const { return OpenSSLEVPKDFState::KDF_FETCHED; } -TypeStateDescription::State OpenSSLEVPKDFDescription::error() const { +OpenSSLEVPKDFState OpenSSLEVPKDFDescription::error() const { return OpenSSLEVPKDFState::ERROR; } OpenSSLEVPKDFDescription::OpenSSLEVTKDFToken -OpenSSLEVPKDFDescription::funcNameToToken(const std::string &FuncName) { +OpenSSLEVPKDFDescription::funcNameToToken(llvm::StringRef FuncName) { if (FuncName == "EVP_KDF_fetch") { return OpenSSLEVTKDFToken::EVP_KDF_FETCH; } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp index b0cc0cc87..3c0a90a67 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp @@ -18,48 +18,45 @@ using namespace psr; namespace psr { // Return value is modeled as -1 -const std::map> - OpenSSLSecureHeapDescription::OpenSSLSecureHeapFuncs = { - {"CRYPTO_secure_malloc", {-1}}, - {"CRYPTO_secure_zalloc", {-1}}, - {"CRYPTO_secure_free", {0}}, - {"CRYPTO_secure_clear_free", {0}}}; +static const std::map> OpenSSLSecureHeapFuncs = { + {"CRYPTO_secure_malloc", {-1}}, + {"CRYPTO_secure_zalloc", {-1}}, + {"CRYPTO_secure_free", {0}}, + {"CRYPTO_secure_clear_free", {0}}}; // delta[Token][State] = next State // Token: SECURE_MALLOC = 0, SECURE_ZALLOC = 1, SECURE_FREE = 2, // SECURE_CLEAR_FREE = 3, STAR = 4 // // States: BOT = 0, UNINIT = 1, ALLOCATED = 2, ZEROED = 3, FREED = 4, ERROR = 5 -const OpenSSLSecureHeapDescription::OpenSSLSecureHeapState - OpenSSLSecureHeapDescription::Delta[5][6] = { - // SECURE_MALLOC - {OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, - OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, - OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED}, - // SECURE_ZALLOC - {OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, - OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, - OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED}, - // SECURE_FREE - {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, - OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::FREED, - OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, - // SECURE_CLEAR_FREE - {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, - OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::FREED, - OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, - // STAR - {OpenSSLSecureHeapState::BOT, OpenSSLSecureHeapState::UNINIT, - OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ZEROED, - OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::ERROR}, +const OpenSSLSecureHeapState OpenSSLSecureHeapDescription::Delta[5][6] = { + // SECURE_MALLOC + {OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, + OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED, + OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ALLOCATED}, + // SECURE_ZALLOC + {OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, + OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED, + OpenSSLSecureHeapState::ZEROED, OpenSSLSecureHeapState::ZEROED}, + // SECURE_FREE + {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, + OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::FREED, + OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, + // SECURE_CLEAR_FREE + {OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR, + OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::FREED, + OpenSSLSecureHeapState::ERROR, OpenSSLSecureHeapState::ERROR}, + // STAR + {OpenSSLSecureHeapState::BOT, OpenSSLSecureHeapState::UNINIT, + OpenSSLSecureHeapState::ALLOCATED, OpenSSLSecureHeapState::ZEROED, + OpenSSLSecureHeapState::FREED, OpenSSLSecureHeapState::ERROR}, }; OpenSSLSecureHeapDescription::OpenSSLSecureHeapDescription( IDESolver &SecureHeapPropagationResults) : SecureHeapPropagationResults(SecureHeapPropagationResults) {} -bool OpenSSLSecureHeapDescription::isFactoryFunction( - const std::string &F) const { +bool OpenSSLSecureHeapDescription::isFactoryFunction(llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLSecureHeapFuncs.at(F).find(-1) != OpenSSLSecureHeapFuncs.at(F).end(); @@ -68,7 +65,7 @@ bool OpenSSLSecureHeapDescription::isFactoryFunction( } bool OpenSSLSecureHeapDescription::isConsumingFunction( - const std::string &F) const { + llvm::StringRef F) const { if (isAPIFunction(F)) { return OpenSSLSecureHeapFuncs.at(F).find(-1) == OpenSSLSecureHeapFuncs.at(F).end(); @@ -76,23 +73,23 @@ bool OpenSSLSecureHeapDescription::isConsumingFunction( return false; } -bool OpenSSLSecureHeapDescription::isAPIFunction(const std::string &F) const { +bool OpenSSLSecureHeapDescription::isAPIFunction(llvm::StringRef F) const { return OpenSSLSecureHeapFuncs.find(F) != OpenSSLSecureHeapFuncs.end(); } -TypeStateDescription::State OpenSSLSecureHeapDescription::getNextState( - std::string Tok, TypeStateDescription::State S) const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S) const { if (isAPIFunction(Tok)) { auto Ftok = static_cast>( funcNameToToken(Tok)); - return Delta[Ftok][S]; + return Delta[Ftok][int(S)]; } return OpenSSLSecureHeapState::BOT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::getNextState( - const std::string &Tok, TypeStateDescription::State S, +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S, const llvm::CallBase *CallSite) const { if (isAPIFunction(Tok)) { auto Ftok = static_cast>( @@ -104,7 +101,7 @@ TypeStateDescription::State OpenSSLSecureHeapDescription::getNextState( // << llvmIRToShortString(CS.getInstruction()) << std::endl; return error(); } - return Delta[Ftok][S]; + return Delta[Ftok][int(S)]; } return error(); } @@ -114,7 +111,7 @@ std::string OpenSSLSecureHeapDescription::getTypeNameOfInterest() const { } set -OpenSSLSecureHeapDescription::getConsumerParamIdx(const std::string &F) const { +OpenSSLSecureHeapDescription::getConsumerParamIdx(llvm::StringRef F) const { if (isConsumingFunction(F)) { return OpenSSLSecureHeapFuncs.at(F); } @@ -122,7 +119,7 @@ OpenSSLSecureHeapDescription::getConsumerParamIdx(const std::string &F) const { } set -OpenSSLSecureHeapDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLSecureHeapDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -130,9 +127,8 @@ OpenSSLSecureHeapDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -std::string OpenSSLSecureHeapDescription::stateToString( - TypeStateDescription::State S) const { - switch (S) { +llvm::StringRef to_string(OpenSSLSecureHeapState State) noexcept { + switch (State) { case OpenSSLSecureHeapState::TOP: return "TOP"; case OpenSSLSecureHeapState::BOT: @@ -145,35 +141,35 @@ std::string OpenSSLSecureHeapDescription::stateToString( return "FREED"; case OpenSSLSecureHeapState::ERROR: return "ERROR"; - default: - llvm::report_fatal_error("received unknown state!"); - break; + case OpenSSLSecureHeapState::ZEROED: + return "ZEROED"; } + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLSecureHeapDescription::bottom() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::bottom() const { return OpenSSLSecureHeapState::BOT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::top() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::top() const { return OpenSSLSecureHeapState::TOP; } -TypeStateDescription::State OpenSSLSecureHeapDescription::start() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::start() const { llvm::report_fatal_error("TypeStateDescription::start() is deprecated"); return OpenSSLSecureHeapState::BOT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::uninit() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::uninit() const { return OpenSSLSecureHeapState::UNINIT; } -TypeStateDescription::State OpenSSLSecureHeapDescription::error() const { +OpenSSLSecureHeapState OpenSSLSecureHeapDescription::error() const { return OpenSSLSecureHeapState::ERROR; } OpenSSLSecureHeapDescription::OpenSSLSecureHeapToken -OpenSSLSecureHeapDescription::funcNameToToken(const std::string &F) { +OpenSSLSecureHeapDescription::funcNameToToken(llvm::StringRef F) { return llvm::StringSwitch(F) .Case("CRYPTO_secure_malloc", OpenSSLSecureHeapToken::SECURE_MALLOC) .Case("CRYPTO_secure_zalloc", OpenSSLSecureHeapToken::SECURE_ZALLOC) diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp index f5b383ef2..e71e30b0e 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp @@ -13,75 +13,99 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include + +#include + using namespace std; using namespace psr; namespace psr { - -// Return value is modeled as -1 -const std::map> - OpenSSLSecureMemoryDescription::OpenSSLSecureMemoryFuncs = { - {"CRYPTO_malloc", {-1}}, - {"CRYPTO_zalloc", {-1}}, - {"OPENSSL_cleanse", {0}}, - {"CRYPTO_free", {0}}}; +enum class OpenSSLSecureMemoryState { + TOP = 42, + BOT = 0, + ZEROED = 1, + FREED = 2, + ERROR = 3, + ALLOCATED = 4 +}; + +namespace { + +enum class OpenSSLSecureMemoryToken { + CRYPTO_MALLOC = 0, + CRYPTO_ZALLOC = 1, + CRYPTO_FREE = 2, + OPENSSL_CLEANSE = 3, + STAR = 4 +}; + +constexpr std::array FactoryFuncs = {"CRYPTO_malloc", + "CRYPTO_zalloc"}; +constexpr std::array, 2> ConsumingFuncs = { + {{"CRYPTO_free", 0}, {"OPENSSL_cleanse", 0}}, +}; // delta[Token][State] = next State // Token: CRYPTO_MALLOC=0, CRYPTO_ZALLOC=1, CRYPTO_FREE=2, OPENSSL_CLEANSE=3, // STAR = 4 // // States: ALLOCATED=4, ZEROED=1, FREED=2, ERROR=3, BOT=0 -const OpenSSLSecureMemoryDescription::OpenSSLSecureMemoryState - OpenSSLSecureMemoryDescription::Delta[6][7] = { - // CRYPTO_malloc - {OpenSSLSecureMemoryState::ALLOCATED, - OpenSSLSecureMemoryState::ALLOCATED, - OpenSSLSecureMemoryState::ALLOCATED, OpenSSLSecureMemoryState::ERROR, - OpenSSLSecureMemoryState::ALLOCATED}, - // CRYPTO_ZALLOC - {OpenSSLSecureMemoryState::ZEROED, OpenSSLSecureMemoryState::ZEROED, - OpenSSLSecureMemoryState::ZEROED, OpenSSLSecureMemoryState::ERROR, - OpenSSLSecureMemoryState::ZEROED}, - // CRYPTO_FREE - {OpenSSLSecureMemoryState::ERROR, OpenSSLSecureMemoryState::FREED, - OpenSSLSecureMemoryState::ERROR, OpenSSLSecureMemoryState::ERROR, - OpenSSLSecureMemoryState::ERROR}, - // OPENSSL_CLEANSE - {OpenSSLSecureMemoryState::BOT, OpenSSLSecureMemoryState::ZEROED, - OpenSSLSecureMemoryState::ERROR, OpenSSLSecureMemoryState::ERROR, - OpenSSLSecureMemoryState::ZEROED}, - // STAR (kills ZEROED) - {OpenSSLSecureMemoryState::BOT, OpenSSLSecureMemoryState::ALLOCATED, - OpenSSLSecureMemoryState::FREED, OpenSSLSecureMemoryState::ERROR, - OpenSSLSecureMemoryState::ALLOCATED}}; +constexpr OpenSSLSecureMemoryState Delta[6][7] = { + // CRYPTO_malloc + {OpenSSLSecureMemoryState::ALLOCATED, OpenSSLSecureMemoryState::ALLOCATED, + OpenSSLSecureMemoryState::ALLOCATED, OpenSSLSecureMemoryState::ERROR, + OpenSSLSecureMemoryState::ALLOCATED}, + // CRYPTO_ZALLOC + {OpenSSLSecureMemoryState::ZEROED, OpenSSLSecureMemoryState::ZEROED, + OpenSSLSecureMemoryState::ZEROED, OpenSSLSecureMemoryState::ERROR, + OpenSSLSecureMemoryState::ZEROED}, + // CRYPTO_FREE + {OpenSSLSecureMemoryState::ERROR, OpenSSLSecureMemoryState::FREED, + OpenSSLSecureMemoryState::ERROR, OpenSSLSecureMemoryState::ERROR, + OpenSSLSecureMemoryState::ERROR}, + // OPENSSL_CLEANSE + {OpenSSLSecureMemoryState::BOT, OpenSSLSecureMemoryState::ZEROED, + OpenSSLSecureMemoryState::ERROR, OpenSSLSecureMemoryState::ERROR, + OpenSSLSecureMemoryState::ZEROED}, + // STAR (kills ZEROED) + {OpenSSLSecureMemoryState::BOT, OpenSSLSecureMemoryState::ALLOCATED, + OpenSSLSecureMemoryState::FREED, OpenSSLSecureMemoryState::ERROR, + OpenSSLSecureMemoryState::ALLOCATED}}; + +OpenSSLSecureMemoryToken funcNameToToken(llvm::StringRef F) { + return llvm::StringSwitch(F) + .Case("CRYPTO_malloc", OpenSSLSecureMemoryToken::CRYPTO_MALLOC) + .Case("CRYPTO_zalloc", OpenSSLSecureMemoryToken::CRYPTO_ZALLOC) + .Case("CRYPTO_free", OpenSSLSecureMemoryToken::CRYPTO_FREE) + .Case("OPENSSL_cleanse", OpenSSLSecureMemoryToken::OPENSSL_CLEANSE) + .Default(OpenSSLSecureMemoryToken::STAR); +} + +} // namespace bool OpenSSLSecureMemoryDescription::isFactoryFunction( - const std::string &F) const { - if (isAPIFunction(F)) { - return OpenSSLSecureMemoryFuncs.at(F).find(-1) != - OpenSSLSecureMemoryFuncs.at(F).end(); - } - return false; + llvm::StringRef F) const { + return llvm::is_contained(FactoryFuncs, F); } bool OpenSSLSecureMemoryDescription::isConsumingFunction( - const std::string &F) const { - if (isAPIFunction(F)) { - return OpenSSLSecureMemoryFuncs.at(F).find(-1) == - OpenSSLSecureMemoryFuncs.at(F).end(); - } - return false; + llvm::StringRef F) const { + return llvm::find_if(ConsumingFuncs, [&F](const auto &Pair) { + return F == Pair.first; + }) != ConsumingFuncs.end(); } -bool OpenSSLSecureMemoryDescription::isAPIFunction(const std::string &F) const { - return OpenSSLSecureMemoryFuncs.find(F) != OpenSSLSecureMemoryFuncs.end(); +bool OpenSSLSecureMemoryDescription::isAPIFunction(llvm::StringRef F) const { + return funcNameToToken(F) != OpenSSLSecureMemoryToken::STAR; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::getNextState( - std::string Tok, TypeStateDescription::State S) const { - if (isAPIFunction(Tok)) { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::getNextState( + llvm::StringRef Tok, TypeStateDescription::State S) const { + auto Token = funcNameToToken(Tok); + if (Token != OpenSSLSecureMemoryToken::STAR) { return Delta[static_cast>( - funcNameToToken(Tok))][S]; + Token)][int(S)]; } return OpenSSLSecureMemoryState::BOT; } @@ -90,16 +114,18 @@ std::string OpenSSLSecureMemoryDescription::getTypeNameOfInterest() const { return "i8"; // NOT SURE WHAT TO DO WITH THIS } -set OpenSSLSecureMemoryDescription::getConsumerParamIdx( - const std::string &F) const { - if (isConsumingFunction(F)) { - return OpenSSLSecureMemoryFuncs.at(F); +set +OpenSSLSecureMemoryDescription::getConsumerParamIdx(llvm::StringRef F) const { + if (const auto *It = llvm::find_if( + ConsumingFuncs, [&F](const auto &Pair) { return F == Pair.first; }); + It != ConsumingFuncs.end()) { + return {It->second}; } return {}; } set -OpenSSLSecureMemoryDescription::getFactoryParamIdx(const std::string &F) const { +OpenSSLSecureMemoryDescription::getFactoryParamIdx(llvm::StringRef F) const { if (isFactoryFunction(F)) { // Trivial here, since we only generate via return value return {-1}; @@ -107,9 +133,8 @@ OpenSSLSecureMemoryDescription::getFactoryParamIdx(const std::string &F) const { return {}; } -std::string OpenSSLSecureMemoryDescription::stateToString( - TypeStateDescription::State S) const { - switch (S) { +llvm::StringRef to_string(OpenSSLSecureMemoryState State) noexcept { + switch (State) { case OpenSSLSecureMemoryState::TOP: return "TOP"; case OpenSSLSecureMemoryState::BOT: @@ -122,40 +147,28 @@ std::string OpenSSLSecureMemoryDescription::stateToString( return "ZEROED"; case OpenSSLSecureMemoryState::ERROR: return "ERROR"; - default: - llvm::report_fatal_error("received unknown state!"); - break; } + llvm::report_fatal_error("received unknown state!"); } -TypeStateDescription::State OpenSSLSecureMemoryDescription::bottom() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::bottom() const { return OpenSSLSecureMemoryState::BOT; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::top() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::top() const { return OpenSSLSecureMemoryState::TOP; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::start() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::start() const { return OpenSSLSecureMemoryState::ALLOCATED; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::uninit() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::uninit() const { return OpenSSLSecureMemoryState::BOT; } -TypeStateDescription::State OpenSSLSecureMemoryDescription::error() const { +OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::error() const { return OpenSSLSecureMemoryState::ERROR; } -OpenSSLSecureMemoryDescription::OpenSSLSecureMemoryToken -OpenSSLSecureMemoryDescription::funcNameToToken(const std::string &F) { - return llvm::StringSwitch(F) - .Case("CRYPTO_malloc", OpenSSLSecureMemoryToken::CRYPTO_MALLOC) - .Case("CRYPTO_zalloc", OpenSSLSecureMemoryToken::CRYPTO_ZALLOC) - .Case("CRYPTO_free", OpenSSLSecureMemoryToken::CRYPTO_FREE) - .Case("OPENSSL_cleanse", OpenSSLSecureMemoryToken::OPENSSL_CLEANSE) - .Default(OpenSSLSecureMemoryToken::STAR); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.cpp b/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.cpp index ec4ce482b..ca19e4c6f 100644 --- a/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.cpp +++ b/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.cpp @@ -154,21 +154,6 @@ InterMonoFullConstantPropagation::callToRetFlow( return In; } -void InterMonoFullConstantPropagation::printNode( - llvm::raw_ostream &OS, InterMonoFullConstantPropagation::n_t Inst) const { - IntraMonoFullConstantPropagation::printNode(OS, Inst); -} - -void InterMonoFullConstantPropagation::printDataFlowFact( - llvm::raw_ostream &OS, InterMonoFullConstantPropagation::d_t Fact) const { - IntraMonoFullConstantPropagation::printDataFlowFact(OS, Fact); -} - -void InterMonoFullConstantPropagation::printFunction( - llvm::raw_ostream &OS, InterMonoFullConstantPropagation::f_t Fun) const { - IntraMonoFullConstantPropagation::printFunction(OS, Fun); -} - void InterMonoFullConstantPropagation::printContainer( llvm::raw_ostream &OS, InterMonoFullConstantPropagation::mono_container_t Con) const { diff --git a/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.cpp b/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.cpp index c86df2593..5d14d7fa4 100644 --- a/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.cpp +++ b/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.cpp @@ -102,19 +102,4 @@ InterMonoSolverTest::initialSeeds() { return Seeds; } -void InterMonoSolverTest::printNode(llvm::raw_ostream &OS, - InterMonoSolverTest::n_t Inst) const { - OS << llvmIRToString(Inst); -} - -void InterMonoSolverTest::printDataFlowFact( - llvm::raw_ostream &OS, InterMonoSolverTest::d_t Fact) const { - OS << llvmIRToString(Fact) << '\n'; -} - -void InterMonoSolverTest::printFunction(llvm::raw_ostream &OS, - InterMonoSolverTest::f_t Fun) const { - OS << Fun->getName(); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.cpp index 4a9e48a99..04830d72c 100644 --- a/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.cpp @@ -181,20 +181,6 @@ InterMonoTaintAnalysis::initialSeeds() { return Seeds; } -void InterMonoTaintAnalysis::printNode(llvm::raw_ostream &OS, - InterMonoTaintAnalysis::n_t Inst) const { - OS << llvmIRToString(Inst); -} - -void InterMonoTaintAnalysis::printDataFlowFact( - llvm::raw_ostream &OS, InterMonoTaintAnalysis::d_t Fact) const { - OS << llvmIRToString(Fact) << '\n'; -} - -void InterMonoTaintAnalysis::printFunction(llvm::raw_ostream &OS, - const llvm::Function *Fun) const { - OS << Fun->getName(); -} const std::map> & InterMonoTaintAnalysis::getAllLeaks() const { diff --git a/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.cpp b/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.cpp index 4c223bcd7..2c415cd17 100644 --- a/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.cpp +++ b/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Value.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -222,30 +223,11 @@ IntraMonoFullConstantPropagation::executeBinOperation( return Res; } -void IntraMonoFullConstantPropagation::printNode( - llvm::raw_ostream &OS, IntraMonoFullConstantPropagation::n_t Inst) const { - OS << llvmIRToString(Inst); -} - -void IntraMonoFullConstantPropagation::printDataFlowFact( - llvm::raw_ostream &OS, IntraMonoFullConstantPropagation::d_t Fact) const { - OS << "< " + llvmIRToString(Fact.first) << ", "; - if (std::holds_alternative(Fact.second)) { - OS << std::get(Fact.second); - } - if (std::holds_alternative(Fact.second)) { - OS << std::get(Fact.second); - } - if (std::holds_alternative( - Fact.second)) { - OS << std::get(Fact.second); - } - OS << " >\n"; -} +} // namespace psr -void IntraMonoFullConstantPropagation::printFunction( - llvm::raw_ostream &OS, IntraMonoFullConstantPropagation::f_t Fun) const { - OS << Fun->getName(); +std::string psr::DToString(const IntraMonoFCAFact &Fact) { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + OS << "< " << llvmIRToString(Fact.Fact) << ", " << Fact.Value << " >\n"; + return Ret; } - -} // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.cpp b/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.cpp index 5becbc3c6..dc0a9782d 100644 --- a/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.cpp +++ b/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.cpp @@ -73,19 +73,4 @@ IntraMonoSolverTest::initialSeeds() { return {}; } -void IntraMonoSolverTest::printNode(llvm::raw_ostream &OS, - IntraMonoSolverTest::n_t Inst) const { - OS << llvmIRToString(Inst); -} - -void IntraMonoSolverTest::printDataFlowFact( - llvm::raw_ostream &OS, IntraMonoSolverTest::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IntraMonoSolverTest::printFunction(llvm::raw_ostream &OS, - IntraMonoSolverTest::f_t Fun) const { - OS << Fun->getName(); -} - } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.cpp b/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.cpp index 892cf558d..3d7aa3a8a 100644 --- a/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.cpp +++ b/lib/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.cpp @@ -90,19 +90,4 @@ IntraMonoUninitVariables::initialSeeds() { return Seeds; } -void IntraMonoUninitVariables::printNode( - llvm::raw_ostream &OS, IntraMonoUninitVariables::n_t Inst) const { - OS << llvmIRToString(Inst); -} - -void IntraMonoUninitVariables::printDataFlowFact( - llvm::raw_ostream &OS, IntraMonoUninitVariables::d_t Fact) const { - OS << llvmIRToString(Fact); -} - -void IntraMonoUninitVariables::printFunction( - llvm::raw_ostream &OS, IntraMonoUninitVariables::f_t Fun) const { - OS << Fun->getName(); -} - } // namespace psr diff --git a/lib/PhasarLLVM/Utils/LLVMPrinter.cpp b/lib/PhasarLLVM/Utils/LLVMPrinter.cpp new file mode 100644 index 000000000..23910b444 --- /dev/null +++ b/lib/PhasarLLVM/Utils/LLVMPrinter.cpp @@ -0,0 +1,14 @@ +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/Printer.h" + +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" + +std::string psr::NToString(const llvm::Value *V) { return llvmIRToString(V); } +std::string psr::NToString(const llvm::Instruction *V) { + return llvmIRToString(V); +} + +std::string psr::DToString(const llvm::Value *V) { return llvmIRToString(V); } + +llvm::StringRef psr::FToString(const llvm::Function *V) { return V->getName(); } diff --git a/tools/example-tool/myphasartool.cpp b/tools/example-tool/myphasartool.cpp index 642c6fd97..f95f34ce2 100644 --- a/tools/example-tool/myphasartool.cpp +++ b/tools/example-tool/myphasartool.cpp @@ -42,14 +42,14 @@ int main(int Argc, const char **Argv) { auto L = createAnalysisProblem(HA, EntryPoints); IFDSSolver S(L, &HA.getICFG()); auto IFDSResults = S.solve(); - IFDSResults.dumpResults(HA.getICFG(), L); + IFDSResults.dumpResults(HA.getICFG()); // IDE template parametrization test llvm::outs() << "Testing IDE:\n"; auto M = createAnalysisProblem(HA, EntryPoints); // Alternative way of solving an IFDS/IDEProblem: auto IDEResults = solveIDEProblem(M, HA.getICFG()); - IDEResults.dumpResults(HA.getICFG(), M); + IDEResults.dumpResults(HA.getICFG()); } else { llvm::errs() << "error: file does not contain a 'main' function!\n"; diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp index a8bf83d15..0b2d4fa52 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisFileIOTest.cpp @@ -37,7 +37,7 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { std::optional HA; CSTDFILEIOTypeStateDescription CSTDFILEIODesc{}; - std::optional TSProblem; + std::optional> TSProblem; enum IOSTATE { TOP = 42, UNINIT = 0, @@ -53,7 +53,8 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { void initialize(const llvm::Twine &IRFile) { HA.emplace(IRFile, EntryPoints); - TSProblem = createAnalysisProblem( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>( *HA, &CSTDFILEIODesc, EntryPoints); } @@ -69,7 +70,8 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { */ void compareResults( const std::map> &GroundTruth, - IDESolver_P &Solver) { + IDESolver_P> + &Solver) { for (const auto &InstToGroundTruth : GroundTruth) { const auto *Inst = HA->getProjectIRDB().getInstruction(InstToGroundTruth.first); @@ -80,7 +82,7 @@ class IDETSAnalysisFileIOTest : public ::testing::Test { for (auto Result : Solver.resultsAt(Inst, true)) { if (GT.find(getMetaDataID(Result.first)) != GT.end()) { Results.insert(std::pair( - getMetaDataID(Result.first), Result.second)); + getMetaDataID(Result.first), int(Result.second))); } } EXPECT_EQ(Results, GT) << "At " << llvmIRToShortString(Inst); diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp index c02802f96..bc74fadfd 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLEVPKDFTest.cpp @@ -20,6 +20,7 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "TestConfig.h" #include "gtest/gtest.h" #include @@ -30,44 +31,51 @@ using namespace psr; /* ============== TEST FIXTURE ============== */ class IDETSAnalysisOpenSSLEVPKDFTest : public ::testing::Test { protected: - const std::string PathToLlFiles = - PhasarConfig::PhasarDirectory() + - "build/test/llvm_test_code/openssl/key_derivation/"; + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("openssl/key_derivation/"); const std::vector EntryPoints = {"main"}; std::optional HA; std::optional OpenSSLEVPKeyDerivationDesc; OpenSSLEVPKDFDescription OpenSSLEVPKDFDesc{}; - std::optional TSProblem, TSKDFProblem; - unique_ptr> Llvmtssolver, KdfSolver; - - enum OpenSSLEVPKeyDerivationState { - TOP = 42, - UNINIT = 5, - CTX_ATTACHED = 1, - PARAM_INIT = 2, - DERIVED = 3, - ERROR = 4, - BOT = 0 - }; + std::optional> TSProblem; + std::optional> TSKDFProblem; + unique_ptr>> + Llvmtssolver; + unique_ptr>> + KdfSolver; + + // enum OpenSSLEVPKDFCTXState { + // TOP = 42, + // UNINIT = 5, + // CTX_ATTACHED = 1, + // PARAM_INIT = 2, + // DERIVED = 3, + // ERROR = 4, + // BOT = 0 + // }; IDETSAnalysisOpenSSLEVPKDFTest() = default; ~IDETSAnalysisOpenSSLEVPKDFTest() override = default; - void initialize(const std::string &IRFile) { - HA.emplace(IRFile, EntryPoints); + void initialize(const llvm::Twine &IRFile) { + HA.emplace(PathToLlFiles + IRFile, EntryPoints); - TSKDFProblem = createAnalysisProblem( - *HA, &OpenSSLEVPKDFDesc, EntryPoints); + TSKDFProblem = + createAnalysisProblem>( + *HA, &OpenSSLEVPKDFDesc, EntryPoints); - KdfSolver = make_unique>( + KdfSolver = make_unique< + IDESolver>>( *TSKDFProblem, &HA->getICFG()); OpenSSLEVPKeyDerivationDesc.emplace(*KdfSolver); - TSProblem = createAnalysisProblem( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>( *HA, &*OpenSSLEVPKeyDerivationDesc, EntryPoints); - Llvmtssolver = make_unique>( + Llvmtssolver = make_unique< + IDESolver>>( *TSProblem, &HA->getICFG()); KdfSolver->solve(); Llvmtssolver->solve(); @@ -85,16 +93,17 @@ class IDETSAnalysisOpenSSLEVPKDFTest : public ::testing::Test { * @param solver provides the results */ void compareResults( - const std::map> &GroundTruth) { + const std::map> + &GroundTruth) { for (const auto &InstToGroundTruth : GroundTruth) { const auto *Inst = HA->getProjectIRDB().getInstruction(InstToGroundTruth.first); auto GT = InstToGroundTruth.second; - std::map Results; + std::map Results; for (auto Result : Llvmtssolver->resultsAt(Inst, true)) { - if (Result.second != OpenSSLEVPKeyDerivationState::BOT && + if (Result.second != OpenSSLEVPKDFCTXState::BOT && GT.count(getMetaDataID(Result.first))) { - Results.insert(std::pair( + Results.insert(std::pair( getMetaDataID(Result.first), Result.second)); } } @@ -104,234 +113,234 @@ class IDETSAnalysisOpenSSLEVPKDFTest : public ::testing::Test { }; // Test Fixture TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation1) { - initialize({PathToLlFiles + "key-derivation1_c.ll"}); + initialize("key-derivation1_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; - - Gt[48] = {{"46", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"20", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[50] = {{"46", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"20", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - - Gt[92] = {{"46", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"20", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"88", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[98] = {{"95", OpenSSLEVPKeyDerivationState::DERIVED}, - {"46", OpenSSLEVPKeyDerivationState::DERIVED}, - {"20", OpenSSLEVPKeyDerivationState::DERIVED}, - {"88", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[146] = {{"144", OpenSSLEVPKeyDerivationState::UNINIT}, - {"95", OpenSSLEVPKeyDerivationState::UNINIT}, - {"46", OpenSSLEVPKeyDerivationState::UNINIT}, - {"20", OpenSSLEVPKeyDerivationState::UNINIT}, - {"88", OpenSSLEVPKeyDerivationState::UNINIT}}; + std::map> Gt; + + Gt[48] = {{"46", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"20", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[50] = {{"46", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"20", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + + Gt[92] = {{"46", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"20", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"88", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[98] = {{"95", OpenSSLEVPKDFCTXState::DERIVED}, + {"46", OpenSSLEVPKDFCTXState::DERIVED}, + {"20", OpenSSLEVPKDFCTXState::DERIVED}, + {"88", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[146] = {{"144", OpenSSLEVPKDFCTXState::UNINIT}, + {"95", OpenSSLEVPKDFCTXState::UNINIT}, + {"46", OpenSSLEVPKDFCTXState::UNINIT}, + {"20", OpenSSLEVPKDFCTXState::UNINIT}, + {"88", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation2) { - initialize({PathToLlFiles + "key-derivation2_c.ll"}); + initialize("key-derivation2_c.ll"); - std::map> Gt; - // gt[40] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; // killed by + std::map> Gt; + // gt[40] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; // killed by // null-initialization - // gt[57] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; // killed by + // gt[57] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; // killed by // null-initialization - Gt[60] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"103", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[106] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[112] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"110", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[113] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[160] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}, - {"159", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[161] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}, - {"58", OpenSSLEVPKeyDerivationState::UNINIT}, - {"103", OpenSSLEVPKeyDerivationState::UNINIT}, - {"110", OpenSSLEVPKeyDerivationState::UNINIT}, - {"159", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[60] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"103", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[106] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[112] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"110", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[113] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[160] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}, + {"159", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[161] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}, + {"58", OpenSSLEVPKDFCTXState::UNINIT}, + {"103", OpenSSLEVPKDFCTXState::UNINIT}, + {"110", OpenSSLEVPKDFCTXState::UNINIT}, + {"159", OpenSSLEVPKDFCTXState::UNINIT}}; // Fails due to merge conflicts: ID43 and ID162 have both value UNINIT on 22, // but it is implicit at ID43, so merging gives BOT - // gt[164] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; + // gt[164] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation3) { - initialize({PathToLlFiles + "key-derivation3_c.ll"}); - std::map> Gt; + initialize("key-derivation3_c.ll"); + std::map> Gt; - // gt[56] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[56] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 21 - Gt[58] = {{"56", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[93] = {{"56", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"91", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[94] = {{"56", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"91", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[100] = {{"56", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"91", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"98", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[101] = {{"56", OpenSSLEVPKeyDerivationState::DERIVED}, - {"21", OpenSSLEVPKeyDerivationState::DERIVED}, - {"91", OpenSSLEVPKeyDerivationState::DERIVED}, - {"98", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[148] = {{"56", OpenSSLEVPKeyDerivationState::DERIVED}, - {"21", OpenSSLEVPKeyDerivationState::DERIVED}, - {"91", OpenSSLEVPKeyDerivationState::DERIVED}, - {"98", OpenSSLEVPKeyDerivationState::DERIVED}, - {"147", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[149] = {{"56", OpenSSLEVPKeyDerivationState::UNINIT}, - {"21", OpenSSLEVPKeyDerivationState::UNINIT}, - {"91", OpenSSLEVPKeyDerivationState::UNINIT}, - {"98", OpenSSLEVPKeyDerivationState::UNINIT}, - {"147", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[58] = {{"56", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[93] = {{"56", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"91", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[94] = {{"56", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"91", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[100] = {{"56", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"91", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"98", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[101] = {{"56", OpenSSLEVPKDFCTXState::DERIVED}, + {"21", OpenSSLEVPKDFCTXState::DERIVED}, + {"91", OpenSSLEVPKDFCTXState::DERIVED}, + {"98", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[148] = {{"56", OpenSSLEVPKDFCTXState::DERIVED}, + {"21", OpenSSLEVPKDFCTXState::DERIVED}, + {"91", OpenSSLEVPKDFCTXState::DERIVED}, + {"98", OpenSSLEVPKDFCTXState::DERIVED}, + {"147", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[149] = {{"56", OpenSSLEVPKDFCTXState::UNINIT}, + {"21", OpenSSLEVPKDFCTXState::UNINIT}, + {"91", OpenSSLEVPKDFCTXState::UNINIT}, + {"98", OpenSSLEVPKDFCTXState::UNINIT}, + {"147", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation4) { - initialize({PathToLlFiles + "key-derivation4_c.ll"}); + initialize("key-derivation4_c.ll"); - std::map> Gt; + std::map> Gt; - // gt[57] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[57] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 21 - Gt[59] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[104] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"102", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"57", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"102", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; + Gt[59] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[104] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"102", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"57", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"102", OpenSSLEVPKDFCTXState::PARAM_INIT}}; // TODO: Should FREE on PARAM_INIT result in UNINIT, or in ERROR? (currently // it is UNINIT) - Gt[152] = {{"21", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"57", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"102", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"151", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[153] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}, - {"57", OpenSSLEVPKeyDerivationState::UNINIT}, - {"102", OpenSSLEVPKeyDerivationState::UNINIT}, - {"151", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[152] = {{"21", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"57", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"102", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"151", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[153] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}, + {"57", OpenSSLEVPKDFCTXState::UNINIT}, + {"102", OpenSSLEVPKDFCTXState::UNINIT}, + {"151", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation5) { - initialize({PathToLlFiles + "key-derivation5_c.ll"}); + initialize("key-derivation5_c.ll"); - std::map> Gt; + std::map> Gt; - // gt[58] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}};// + // gt[58] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}};// // null-initialization kills 22 - Gt[60] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"103", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[106] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[112] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"110", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[113] = Gt[160] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}}; + Gt[60] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"103", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[106] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[112] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"110", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[113] = Gt[160] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}}; // should report an error at 160? (kdf_ctx is not freed) compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, DISABLED_KeyDerivation6) { - initialize({PathToLlFiles + "key-derivation6_c.ll"}); + initialize("key-derivation6_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; - Gt[102] = {{"100", OpenSSLEVPKeyDerivationState::BOT}, - {"22", OpenSSLEVPKeyDerivationState::BOT}}; - Gt[103] = {{"100", OpenSSLEVPKeyDerivationState::ERROR}, - {"22", OpenSSLEVPKeyDerivationState::ERROR}}; - Gt[109] = Gt[110] = {{"100", OpenSSLEVPKeyDerivationState::ERROR}, - {"22", OpenSSLEVPKeyDerivationState::ERROR}, - {"107", OpenSSLEVPKeyDerivationState::ERROR}}; + std::map> Gt; + Gt[102] = {{"100", OpenSSLEVPKDFCTXState::BOT}, + {"22", OpenSSLEVPKDFCTXState::BOT}}; + Gt[103] = {{"100", OpenSSLEVPKDFCTXState::ERROR}, + {"22", OpenSSLEVPKDFCTXState::ERROR}}; + Gt[109] = Gt[110] = {{"100", OpenSSLEVPKDFCTXState::ERROR}, + {"22", OpenSSLEVPKDFCTXState::ERROR}, + {"107", OpenSSLEVPKDFCTXState::ERROR}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation7) { - initialize({PathToLlFiles + "key-derivation7_c.ll"}); + initialize("key-derivation7_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; + std::map> Gt; - // gt[57] = {{"21", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[57] = {{"21", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 21 - Gt[59] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[104] = {{"21", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"57", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"102", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"21", OpenSSLEVPKeyDerivationState::ERROR}, - {"57", OpenSSLEVPKeyDerivationState::ERROR}, - {"102", OpenSSLEVPKeyDerivationState::ERROR}}; - Gt[152] = Gt[153] = {{"21", OpenSSLEVPKeyDerivationState::ERROR}, - {"57", OpenSSLEVPKeyDerivationState::ERROR}, - {"102", OpenSSLEVPKeyDerivationState::ERROR}, - {"151", OpenSSLEVPKeyDerivationState::ERROR}}; + Gt[59] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[104] = {{"21", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"57", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"102", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"21", OpenSSLEVPKDFCTXState::ERROR}, + {"57", OpenSSLEVPKDFCTXState::ERROR}, + {"102", OpenSSLEVPKDFCTXState::ERROR}}; + Gt[152] = Gt[153] = {{"21", OpenSSLEVPKDFCTXState::ERROR}, + {"57", OpenSSLEVPKDFCTXState::ERROR}, + {"102", OpenSSLEVPKDFCTXState::ERROR}, + {"151", OpenSSLEVPKDFCTXState::ERROR}}; compareResults(Gt); } TEST_F(IDETSAnalysisOpenSSLEVPKDFTest, KeyDerivation8) { - initialize({PathToLlFiles + "key-derivation8_c.ll"}); + initialize("key-derivation8_c.ll"); // llvmtssolver->printReport(); - std::map> Gt; + std::map> Gt; - // gt[58] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}}; // + // gt[58] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}}; // // null-initialization kills 22 - Gt[60] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[105] = {{"22", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"58", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}, - {"103", OpenSSLEVPKeyDerivationState::CTX_ATTACHED}}; - Gt[107] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[112] = {{"22", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"58", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"103", OpenSSLEVPKeyDerivationState::PARAM_INIT}, - {"110", OpenSSLEVPKeyDerivationState::PARAM_INIT}}; - Gt[113] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[160] = {{"22", OpenSSLEVPKeyDerivationState::DERIVED}, - {"58", OpenSSLEVPKeyDerivationState::DERIVED}, - {"103", OpenSSLEVPKeyDerivationState::DERIVED}, - {"110", OpenSSLEVPKeyDerivationState::DERIVED}, - {"159", OpenSSLEVPKeyDerivationState::DERIVED}}; - Gt[161] = {{"22", OpenSSLEVPKeyDerivationState::UNINIT}, - {"58", OpenSSLEVPKeyDerivationState::UNINIT}, - {"103", OpenSSLEVPKeyDerivationState::UNINIT}, - {"110", OpenSSLEVPKeyDerivationState::UNINIT}, - {"159", OpenSSLEVPKeyDerivationState::UNINIT}}; + Gt[60] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[105] = {{"22", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"58", OpenSSLEVPKDFCTXState::CTX_ATTACHED}, + {"103", OpenSSLEVPKDFCTXState::CTX_ATTACHED}}; + Gt[107] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[112] = {{"22", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"58", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"103", OpenSSLEVPKDFCTXState::PARAM_INIT}, + {"110", OpenSSLEVPKDFCTXState::PARAM_INIT}}; + Gt[113] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[160] = {{"22", OpenSSLEVPKDFCTXState::DERIVED}, + {"58", OpenSSLEVPKDFCTXState::DERIVED}, + {"103", OpenSSLEVPKDFCTXState::DERIVED}, + {"110", OpenSSLEVPKDFCTXState::DERIVED}, + {"159", OpenSSLEVPKDFCTXState::DERIVED}}; + Gt[161] = {{"22", OpenSSLEVPKDFCTXState::UNINIT}, + {"58", OpenSSLEVPKDFCTXState::UNINIT}, + {"103", OpenSSLEVPKDFCTXState::UNINIT}, + {"110", OpenSSLEVPKDFCTXState::UNINIT}, + {"159", OpenSSLEVPKDFCTXState::UNINIT}}; compareResults(Gt); } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp index 4546dc44c..a4cc5eb86 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureHeapTest.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/Twine.h" +#include "TestConfig.h" #include "gtest/gtest.h" #include @@ -33,17 +34,18 @@ using namespace psr; /* ============== TEST FIXTURE ============== */ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { protected: - const std::string PathToLlFiles = - PhasarConfig::PhasarDirectory() + - "build/test/llvm_test_code/openssl/secure_heap/"; + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("openssl/secure_heap/"); const std::vector EntryPoints = {"main"}; std::optional HA; std::optional Desc; - std::optional TSProblem; + std::optional> TSProblem; std::optional SecureHeapPropagationProblem; - unique_ptr> Llvmtssolver; + unique_ptr< + IDESolver>> + Llvmtssolver; unique_ptr> SecureHeapPropagationResults; enum OpenSSLSecureHeapState { @@ -58,7 +60,7 @@ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { IDETSAnalysisOpenSSLSecureHeapTest() = default; ~IDETSAnalysisOpenSSLSecureHeapTest() override = default; - void initialize(const std::string &IRFile) { + void initialize(const llvm::Twine &IRFile) { HA.emplace(IRFile, EntryPoints); SecureHeapPropagationProblem = @@ -68,9 +70,11 @@ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { *SecureHeapPropagationProblem, &HA->getICFG()); Desc.emplace(*SecureHeapPropagationResults); - TSProblem = - createAnalysisProblem(*HA, &*Desc, EntryPoints); - Llvmtssolver = make_unique>( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>(*HA, &*Desc, + EntryPoints); + Llvmtssolver = make_unique< + IDESolver>>( *TSProblem, &HA->getICFG()); SecureHeapPropagationResults->solve(); @@ -97,7 +101,7 @@ class IDETSAnalysisOpenSSLSecureHeapTest : public ::testing::Test { for (auto Result : Llvmtssolver->resultsAt(Inst, true)) { if (GT.find(getMetaDataID(Result.first)) != GT.end()) { Results.insert(std::pair( - getMetaDataID(Result.first), Result.second)); + getMetaDataID(Result.first), int(Result.second))); } // else { // std::cout << "Unused result at " << InstToGroundTruth.first << ": " // << llvmIRToShortString(Result.first) << " => " diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp index 3006943b7..558c8007c 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETSAnalysisOpenSSLSecureMemoryTest.cpp @@ -19,6 +19,7 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "TestConfig.h" #include "gtest/gtest.h" #include @@ -30,15 +31,15 @@ using namespace psr; /* ============== TEST FIXTURE ============== */ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { protected: - const std::string PathToLlFiles = - PhasarConfig::PhasarDirectory() + - "build/test/llvm_test_code/openssl/secure_memory/"; + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("openssl/secure_memory/"); const std::vector EntryPoints = {"main"}; std::optional HA; OpenSSLSecureMemoryDescription Desc{}; - std::optional TSProblem; - unique_ptr> Llvmtssolver; + std::optional> TSProblem; + unique_ptr>> + Llvmtssolver; enum OpenSSLSecureMemoryState { TOP = 42, @@ -51,12 +52,14 @@ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { IDETSAnalysisOpenSSLSecureMemoryTest() = default; ~IDETSAnalysisOpenSSLSecureMemoryTest() override = default; - void initialize(const std::string &IRFile) { + void initialize(const llvm::Twine &&IRFile) { HA.emplace(IRFile, EntryPoints); - TSProblem = - createAnalysisProblem(*HA, &Desc, EntryPoints); - Llvmtssolver = make_unique>( + TSProblem = createAnalysisProblem< + IDETypeStateAnalysis>(*HA, &Desc, + EntryPoints); + Llvmtssolver = make_unique< + IDESolver_P>>( *TSProblem, &HA->getICFG()); Llvmtssolver->solve(); @@ -82,7 +85,7 @@ class IDETSAnalysisOpenSSLSecureMemoryTest : public ::testing::Test { for (auto Result : Llvmtssolver->resultsAt(Inst, true)) { if (GT.find(getMetaDataID(Result.first)) != GT.end()) { Results.insert(std::pair( - getMetaDataID(Result.first), Result.second)); + getMetaDataID(Result.first), int(Result.second))); } // else { // std::cout << "Unused result at " << InstToGroundTruth.first << ": " // << llvmIRToShortString(Result.first) << " => " From 7340a4690623ed883f80d80f9cfc956d15d89942 Mon Sep 17 00:00:00 2001 From: Martin Mory Date: Mon, 28 Aug 2023 18:35:47 +0200 Subject: [PATCH 27/59] link llvm Demangle component to controller, otherwise build in vara fails (#662) Co-authored-by: Martin Mory --- lib/Controller/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Controller/CMakeLists.txt b/lib/Controller/CMakeLists.txt index 242ffcf4c..8b3df9478 100644 --- a/lib/Controller/CMakeLists.txt +++ b/lib/Controller/CMakeLists.txt @@ -16,6 +16,7 @@ set(PHASAR_LINK_LIBS set(LLVM_LINK_COMPONENTS Core Support + Demangle ) if(BUILD_SHARED_LIBS) From 1d0b6e4acfad0c5954344c47af048c43bff7cdc5 Mon Sep 17 00:00:00 2001 From: Martin Mory Date: Mon, 28 Aug 2023 19:30:28 +0200 Subject: [PATCH 28/59] don't link fat LLVM lib in myphasartool, needs to be transitively pulled in through phasar (#663) Co-authored-by: Martin Mory Co-authored-by: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> --- tools/example-tool/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/example-tool/CMakeLists.txt b/tools/example-tool/CMakeLists.txt index c5aa75c2a..aab2a9a7d 100644 --- a/tools/example-tool/CMakeLists.txt +++ b/tools/example-tool/CMakeLists.txt @@ -14,7 +14,6 @@ endif() target_link_libraries(myphasartool LINK_PUBLIC phasar - LLVM LINK_PRIVATE ${PHASAR_STD_FILESYSTEM} ) From b763b5f347a044aaa12f249eeb691d2091447e0b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Mon, 28 Aug 2023 21:04:16 +0200 Subject: [PATCH 29/59] Cleaning up IDETabulationProblem (#653) * Add default implementation for allTopFunction() * Move the default flow function templates to their own class allowing container_type to be deduced (towards specifying sth else than std::set) * pre-commit TypeTraits.h * Merge branch 'development' into f-DefaultAllTopFn --------- Co-authored-by: Martin Mory --- .clang-tidy | 2 +- .../phasar/DataFlow/IfdsIde/FlowFunctions.h | 940 +++++++++--------- .../DataFlow/IfdsIde/IDETabulationProblem.h | 45 +- .../DataFlow/IfdsIde/IFDSTabulationProblem.h | 2 - .../DataFlow/IfdsIde/LLVMFlowFunctions.h | 21 - .../DataFlow/IfdsIde/LLVMZeroValue.h | 2 +- .../Problems/IDEExtendedTaintAnalysis.h | 12 +- .../IDEGeneralizedLCA/IDEGeneralizedLCA.h | 2 +- .../Problems/IDEInstInteractionAnalysis.h | 34 +- .../Problems/IDELinearConstantAnalysis.h | 4 +- .../IfdsIde/Problems/IDEProtoAnalysis.h | 2 +- .../Problems/IDESecureHeapPropagation.h | 10 +- .../DataFlow/IfdsIde/Problems/IDESolverTest.h | 2 +- .../IfdsIde/Problems/IDETypeStateAnalysis.h | 27 +- .../IfdsIde/Problems/IFDSConstAnalysis.h | 2 +- .../Problems/IFDSFieldSensTaintAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSProtoAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSSignAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSSolverTest.h | 2 +- .../IfdsIde/Problems/IFDSTaintAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSTypeAnalysis.h | 2 +- .../Problems/IFDSUninitializedVariables.h | 2 +- include/phasar/Utils/TypeTraits.h | 12 + .../Problems/IDEExtendedTaintAnalysis.cpp | 50 +- .../IDEGeneralizedLCA/IDEGeneralizedLCA.cpp | 35 +- .../Problems/IDELinearConstantAnalysis.cpp | 20 +- .../IfdsIde/Problems/IDEProtoAnalysis.cpp | 10 +- .../Problems/IDESecureHeapPropagation.cpp | 36 +- .../IfdsIde/Problems/IDESolverTest.cpp | 10 +- .../IfdsIde/Problems/IDETypeStateAnalysis.cpp | 30 +- .../IfdsIde/Problems/IFDSConstAnalysis.cpp | 13 +- .../IfdsIde/Problems/IFDSProtoAnalysis.cpp | 13 +- .../IfdsIde/Problems/IFDSSignAnalysis.cpp | 12 +- .../IfdsIde/Problems/IFDSSolverTest.cpp | 10 +- .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 22 +- .../IfdsIde/Problems/IFDSTypeAnalysis.cpp | 2 +- .../Problems/IFDSUninitializedVariables.cpp | 72 +- 37 files changed, 705 insertions(+), 763 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 847f4660f..063d1090a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,7 +55,7 @@ CheckOptions: - key: readability-identifier-naming.ParameterIgnoredRegexp value: (d|d1|d2|d3|d4|d5|eP|f|n) - key: readability-identifier-naming.FunctionIgnoredRegexp - value: (try_emplace|from_json|to_json|equal_to|to_string,DToString|NToString|FToString|LToString) + value: (try_emplace|from_json|to_json|equal_to|to_string|DToString|NToString|FToString|LToString) - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: 1 - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index dda69748e..87a3db452 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -97,533 +97,529 @@ using FlowFunctionPtrTypeOf = std::shared_ptr; template > using FlowFunctionPtrType = FlowFunctionPtrTypeOf>; -/// A flow function that propagates all incoming facts unchanged. -/// -/// Given a flow-function f = identityFlow(), then for all incoming -/// dataflow-facts x, f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x1 x1 x3 ... -/// | | | ... -/// id-instruction | | | ... -/// v v v ... -/// x1 x2 x3 ... -/// -template > auto identityFlow() { - struct IdFF final : public FlowFunction { - Container computeTargets(D Source) override { return {std::move(Source)}; } - }; - static auto TheIdentity = std::make_shared(); - - return TheIdentity; -} +/// Wrapper flow function that is automatically used by the IDESolver if the +/// autoAddZero configuration option is set to true (default). +/// Ensures that the tautological zero-flow fact (Λ) does not get killed. +template > +class ZeroedFlowFunction : public FlowFunction { + using typename FlowFunction::container_type; + using typename FlowFunction::FlowFunctionPtrType; -/// The most generic flow function. Invokes the passed function object F to -/// retrieve the desired data-flows. -/// -/// So, given a flow function f = lambdaFlow(F), then for all incoming -/// dataflow-facts x, f(x) = F(x). -/// -/// In the exploded supergraph it may look as follows: -/// -/// x -/// | -/// inst F -/// / / | \ \ ... -/// v v v v v -/// x1 x2 x x3 x4 -/// -template auto lambdaFlow(Fn &&F) { - using Container = std::invoke_result_t; - struct LambdaFlow final : public FlowFunction { - LambdaFlow(Fn &&F) : Flow(std::forward(F)) {} - Container computeTargets(D Source) override { - return std::invoke(Flow, std::move(Source)); +public: + ZeroedFlowFunction(FlowFunctionPtrType FF, D ZV) + : Delegate(std::move(FF)), ZeroValue(ZV) {} + container_type computeTargets(D Source) override { + if (Source == ZeroValue) { + container_type Result = Delegate->computeTargets(Source); + Result.insert(ZeroValue); + return Result; } + return Delegate->computeTargets(Source); + } - [[no_unique_address]] std::decay_t Flow; - }; +private: + FlowFunctionPtrType Delegate; + D ZeroValue; +}; - return std::make_shared(std::forward(F)); -} +namespace detail { +template +Container makeContainer(Range &&Rng) { + if constexpr (std::is_convertible_v, Container>) { + return std::forward(Rng); + } else { + Container C; + reserveIfPossible(C, Rng.size()); + for (auto &&Fact : Rng) { + C.insert(std::forward(Fact)); + } + return C; + } +}; +} // namespace detail //===----------------------------------------------------------------------===// -// Gen flow functions +// Flow Function Templates +//===----------------------------------------------------------------------===// -/// A flow function that generates a new dataflow fact (FactToGenerate) if -/// called with an already known dataflow fact (From). All other facts are -/// propagated like with the identityFlow. -/// -/// Given a flow function f = generateFlow(v, w), then for all incoming dataflow -/// facts x: -/// f(w) = {v, w}, -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ | ... -/// inst | | \ | ... -/// v v v v ... -/// x w v u -/// -/// \note If the FactToGenerate already holds at the beginning of the statement, -/// this flow function does not kill it. For IFDS analysis it makes no -/// difference, but in the case of IDE, the corresponding edge functions are -/// being joined together potentially lowing precition. If that is an issue, use -/// transferFlow instead. -template > -auto generateFlow(psr::type_identity_t FactToGenerate, D From) { - struct GenFrom final : public FlowFunction { - GenFrom(D GenValue, D FromValue) - : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - return {std::move(Source), GenValue}; - } - return {std::move(Source)}; - } +template class FlowFunctionTemplates { +public: + using d_t = D; + using container_type = Container; - D GenValue; - D FromValue; - }; + /// A flow function that propagates all incoming facts unchanged. + /// + /// Given a flow-function f = identityFlow(), then for all incoming + /// dataflow-facts x, f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x1 x1 x3 ... + /// | | | ... + /// id-instruction | | | ... + /// v v v ... + /// x1 x2 x3 ... + /// + static auto identityFlow() { + struct IdFF final : public FlowFunction { + container_type computeTargets(d_t Source) override { + return {std::move(Source)}; + } + }; + static auto TheIdentity = std::make_shared(); - return std::make_shared(std::move(FactToGenerate), std::move(From)); -} + return TheIdentity; + } -/// A flow function similar to generateFlow, that generates a new dataflow fact -/// (FactToGenerate), if the given Predicate evaluates to true on an incoming -/// dataflow fact -/// -/// So, given a flow function f = generateFlowIf(v, p), for all incoming -/// dataflow facts x: -/// f(x) = {v, x} if p(x) == true -/// f(x) = {x} else. -/// -template , - typename Fn = psr::TrueFn, - typename = std::enable_if_t>> -auto generateFlowIf(D FactToGenerate, Fn Predicate) { - struct GenFlowIf final : public FlowFunction { - GenFlowIf(D GenValue, Fn &&Predicate) - : GenValue(std::move(GenValue)), - Predicate(std::forward(Predicate)) {} - - Container computeTargets(D Source) override { - if (std::invoke(Predicate, Source)) { - return {std::move(Source), GenValue}; + /// The most generic flow function. Invokes the passed function object F to + /// retrieve the desired data-flows. + /// + /// So, given a flow function f = lambdaFlow(F), then for all incoming + /// dataflow-facts x, f(x) = F(x). + /// + /// In the exploded supergraph it may look as follows: + /// + /// x + /// | + /// inst F + /// / / | \ \ ... + /// v v v v v + /// x1 x2 x x3 x4 + /// + template static auto lambdaFlow(Fn &&F) { + struct LambdaFlow final : public FlowFunction { + LambdaFlow(Fn &&F) : Flow(std::forward(F)) {} + container_type computeTargets(d_t Source) override { + return std::invoke(Flow, std::move(Source)); } - return {std::move(Source)}; - } - D GenValue; - [[no_unique_address]] std::decay_t Predicate; - }; + [[no_unique_address]] std::decay_t Flow; + }; - return std::make_shared(std::move(FactToGenerate), - std::forward(Predicate)); -} + return std::make_shared(std::forward(F)); + } -/// A flow function that generates multiple new dataflow facts (FactsToGenerate) -/// if called from an already known dataflow fact (From). -/// -/// Given a flow function f = generateManyFlows({v1, v2, ..., vN}, w), for all -/// incoming dataflow facts x: -/// f(w) = {v1, v2, ..., vN, w} -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ \ ... \ | ... -/// inst | | \ \ ... \ | ... -/// v v v v ... \ v ... -/// x w v1 v2 ... vN u -/// -template , - typename Range = std::initializer_list, - typename = std::enable_if_t>> -auto generateManyFlows(Range &&FactsToGenerate, D From) { - struct GenMany final : public FlowFunction { - GenMany(Container &&GenValues, D FromValue) - : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - auto Ret = GenValues; - Ret.insert(std::move(Source)); - return Ret; + //===----------------------------------------------------------------------===// + // Gen flow functions + + /// A flow function that generates a new dataflow fact (FactToGenerate) if + /// called with an already known dataflow fact (From). All other facts are + /// propagated like with the identityFlow. + /// + /// Given a flow function f = generateFlow(v, w), then for all incoming + /// dataflow facts x: + /// f(w) = {v, w}, + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ | ... + /// inst | | \ | ... + /// v v v v ... + /// x w v u + /// + /// \note If the FactToGenerate already holds at the beginning of the + /// statement, this flow function does not kill it. For IFDS analysis it makes + /// no difference, but in the case of IDE, the corresponding edge functions + /// are being joined together potentially lowing precition. If that is an + /// issue, use transferFlow instead. + static auto generateFlow(d_t FactToGenerate, d_t From) { + struct GenFrom final : public FlowFunction { + GenFrom(d_t GenValue, d_t FromValue) + : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + return {std::move(Source), GenValue}; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } - Container GenValues; - D FromValue; - }; - - auto MakeContainer = [](Range &&Rng) -> Container { - if constexpr (std::is_convertible_v, Container>) { - return std::forward(Rng); - } else { - Container C; - for (auto &&Fact : Rng) { - C.insert(std::forward(Fact)); - } - return C; - } - }; - return std::make_shared( - MakeContainer(std::forward(FactsToGenerate)), std::move(From)); -} + d_t GenValue; + d_t FromValue; + }; -//===----------------------------------------------------------------------===// -// Kill flow functions + return std::make_shared(std::move(FactToGenerate), + std::move(From)); + } -/// A flow function that stops propagating a specific dataflow fact -/// (FactToKill). -/// -/// Given a flow function f = killFlow(v), for all incoming dataflow facts x: -/// f(v) = {} -/// f(x) = {x} -/// -/// In the exploded supergraph it may look as follows: -/// -/// u v w ... -/// | | | -/// inst | | -/// v v -/// u v w ... -/// -template > -auto killFlow(D FactToKill) { - struct KillFlow final : public FlowFunction { - KillFlow(D KillValue) : KillValue(std::move(KillValue)) {} - Container computeTargets(D Source) override { - if (Source == KillValue) { - return {}; + /// A flow function similar to generateFlow, that generates a new dataflow + /// fact (FactToGenerate), if the given Predicate evaluates to true on an + /// incoming dataflow fact + /// + /// So, given a flow function f = generateFlowIf(v, p), for all incoming + /// dataflow facts x: + /// f(x) = {v, x} if p(x) == true + /// f(x) = {x} else. + /// + template >> + static auto generateFlowIf(d_t FactToGenerate, Fn Predicate) { + struct GenFlowIf final : public FlowFunction { + GenFlowIf(d_t GenValue, Fn &&Predicate) + : GenValue(std::move(GenValue)), + Predicate(std::forward(Predicate)) {} + + container_type computeTargets(d_t Source) override { + if (std::invoke(Predicate, Source)) { + return {std::move(Source), GenValue}; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } - D KillValue; - }; - return std::make_shared(std::move(FactToKill)); -} + d_t GenValue; + [[no_unique_address]] std::decay_t Predicate; + }; -/// A flow function similar to killFlow that stops propagating all dataflow -/// facts for that the given Predicate evaluates to true. -/// -/// Given a flow function f = killFlowIf(p), for all incoming dataflow facts x: -/// f(x) = {} if p(x) == true -/// f(x) = {x} else. -/// -template , - typename Fn = psr::TrueFn, - typename = std::enable_if_t>> -auto killFlowIf(Fn Predicate) { - struct KillFlowIf final : public FlowFunction { - KillFlowIf(Fn &&Predicate) : Predicate(std::forward(Predicate)) {} - - Container computeTargets(D Source) override { - if (std::invoke(Predicate, Source)) { - return {}; + return std::make_shared(std::move(FactToGenerate), + std::forward(Predicate)); + } + + /// A flow function that generates multiple new dataflow facts + /// (FactsToGenerate) if called from an already known dataflow fact (From). + /// + /// Given a flow function f = generateManyFlows({v1, v2, ..., vN}, w), for all + /// incoming dataflow facts x: + /// f(w) = {v1, v2, ..., vN, w} + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ \ ... \ | ... + /// inst | | \ \ ... \ | ... + /// v v v v ... \ v ... + /// x w v1 v2 ... vN u + /// + template , + typename = std::enable_if_t>> + static auto generateManyFlows(Range &&FactsToGenerate, d_t From) { + struct GenMany final : public FlowFunction { + GenMany(container_type &&GenValues, d_t FromValue) + : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + auto Ret = GenValues; + Ret.insert(std::move(Source)); + return Ret; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } - [[no_unique_address]] std::decay_t Predicate; - }; + container_type GenValues; + d_t FromValue; + }; - return std::make_shared(std::forward(Predicate)); -} + return std::make_shared(detail::makeContainer( + std::forward(FactsToGenerate)), + std::move(From)); + } -/// A flow function that stops propagating a specific set of dataflow facts -/// (FactsToKill). -/// -/// Given a flow function f = killManyFlows({v1, v2, ..., vN}), for all incoming -/// dataflow facts x: -/// f(v1) = {} -/// f(v2) = {} -/// ... -/// f(vN) = {} -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// u v1 v2 ... vN w ... -/// | | | | | -/// inst | | -/// v v -/// u v1 v2 ... vN w ... -/// -template , - typename Range = std::initializer_list, - typename = std::enable_if_t>> -auto killManyFlows(Range &&FactsToKill) { - struct KillMany final : public FlowFunction { - KillMany(Container &&KillValues) : KillValues(std::move(KillValues)) {} - - Container computeTargets(D Source) override { - if (KillValues.count(Source)) { - return {}; + //===----------------------------------------------------------------------===// + // Kill flow functions + + /// A flow function that stops propagating a specific dataflow fact + /// (FactToKill). + /// + /// Given a flow function f = killFlow(v), for all incoming dataflow facts x: + /// f(v) = {} + /// f(x) = {x} + /// + /// In the exploded supergraph it may look as follows: + /// + /// u v w ... + /// | | | + /// inst | | + /// v v + /// u v w ... + /// + static auto killFlow(d_t FactToKill) { + struct KillFlow final : public FlowFunction { + KillFlow(d_t KillValue) : KillValue(std::move(KillValue)) {} + container_type computeTargets(d_t Source) override { + if (Source == KillValue) { + return {}; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } + d_t KillValue; + }; - Container KillValues; - }; + return std::make_shared(std::move(FactToKill)); + } - auto MakeContainer = [](Range &&Rng) -> Container { - if constexpr (std::is_convertible_v, Container>) { - return std::forward(Rng); - } else { - Container C; - for (auto &&Fact : Rng) { - C.insert(std::forward(Fact)); + /// A flow function similar to killFlow that stops propagating all dataflow + /// facts for that the given Predicate evaluates to true. + /// + /// Given a flow function f = killFlowIf(p), for all incoming dataflow facts + /// x: + /// f(x) = {} if p(x) == true + /// f(x) = {x} else. + /// + template >> + static auto killFlowIf(Fn Predicate) { + struct KillFlowIf final : public FlowFunction { + KillFlowIf(Fn &&Predicate) : Predicate(std::forward(Predicate)) {} + + container_type computeTargets(d_t Source) override { + if (std::invoke(Predicate, Source)) { + return {}; + } + return {std::move(Source)}; } - return C; - } - }; - return std::make_shared( - MakeContainer(std::forward(FactsToKill))); -} -/// A flow function that stops propagating *all* incoming dataflow facts. -/// -/// Given a flow function f = killAllFlows(), for all incoming dataflow facts x, -/// f(x) = {}. -/// -template > auto killAllFlows() { - struct KillAllFF final : public FlowFunction { - Container computeTargets(D Source) override { return {std::move(Source)}; } - }; - static auto TheKillAllFlow = std::make_shared(); + [[no_unique_address]] std::decay_t Predicate; + }; - return TheKillAllFlow; -} - -//===----------------------------------------------------------------------===// -// Gen-and-kill flow functions + return std::make_shared(std::forward(Predicate)); + } -/// A flow function that composes kill and generate flow functions. -/// Like generateFlow it generates a new dataflow fact (FactToGenerate), if -/// called with a specific dataflow fact (From). -/// However, like killFlowIf it stops propagating all other dataflow facts. -/// -/// Given a flow function f = generateFlowAndKillAllOthers(v, w), for all -/// incoming dataflow facts x: -/// f(w) = {v, w} -/// f(x) = {}. -/// -/// Equivalent to: killFlowIf(λz.z!=w) o generateFlow(v, w) (where o denotes -/// function composition) -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ | -/// inst | \ ... -/// v v -/// x w v u -/// -template > -auto generateFlowAndKillAllOthers(psr::type_identity_t FactToGenerate, - D From) { - struct GenFlowAndKillAllOthers final : public FlowFunction { - GenFlowAndKillAllOthers(D GenValue, D FromValue) - : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - return {std::move(Source), GenValue}; + /// A flow function that stops propagating a specific set of dataflow facts + /// (FactsToKill). + /// + /// Given a flow function f = killManyFlows({v1, v2, ..., vN}), for all + /// incoming dataflow facts x: + /// f(v1) = {} + /// f(v2) = {} + /// ... + /// f(vN) = {} + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// u v1 v2 ... vN w ... + /// | | | | | + /// inst | | + /// v v + /// u v1 v2 ... vN w ... + /// + template , + typename = std::enable_if_t>> + static auto killManyFlows(Range &&FactsToKill) { + struct KillMany final : public FlowFunction { + KillMany(Container &&KillValues) : KillValues(std::move(KillValues)) {} + + container_type computeTargets(d_t Source) override { + if (KillValues.count(Source)) { + return {}; + } + return {std::move(Source)}; } - return {}; - } - D GenValue; - D FromValue; - }; + container_type KillValues; + }; - return std::make_shared(std::move(FactToGenerate), - std::move(From)); -} + return std::make_shared(detail::makeContainer( + std::forward(FactsToKill))); + } -/// A flow function similar to generateFlowAndKillAllOthers that may generate -/// multiple dataflow facts (FactsToGenerate) is called with a specific fact -/// (From) and stops propagating all other dataflow facts. -/// -/// Given a flow function f = generateManyFlowsAndKillAllOthers({v1, v2, ..., -/// vN}, w), for all incoming dataflow facts x: -/// f(w) = {v1, v2, ..., vN, w} -/// f(x) = {}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ \ ... \ | ... -/// inst | \ \ ... \ ... -/// v v v ... \ ... -/// x w v1 v2 ... vN u -/// -template , - typename Range = std::initializer_list, - typename = std::enable_if_t>> -auto generateManyFlowsAndKillAllOthers(Range &&FactsToGenerate, D From) { - struct GenManyAndKillAllOthers final : public FlowFunction { - GenManyAndKillAllOthers(Container &&GenValues, D FromValue) - : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - auto Ret = GenValues; - Ret.insert(std::move(Source)); - return Ret; + /// A flow function that stops propagating *all* incoming dataflow facts. + /// + /// Given a flow function f = killAllFlows(), for all incoming dataflow facts + /// x, f(x) = {}. + /// + static auto killAllFlows() { + struct KillAllFF final : public FlowFunction { + Container computeTargets(d_t Source) override { + return {std::move(Source)}; } - return {}; - } + }; + static auto TheKillAllFlow = std::make_shared(); + + return TheKillAllFlow; + } - Container GenValues; - D FromValue; - }; - - auto MakeContainer = [](Range &&Rng) -> Container { - if constexpr (std::is_convertible_v, Container>) { - return std::forward(Rng); - } else { - Container C; - for (auto &&Fact : Rng) { - C.insert(std::forward(Fact)); + //===----------------------------------------------------------------------===// + // Gen-and-kill flow functions + + /// A flow function that composes kill and generate flow functions. + /// Like generateFlow it generates a new dataflow fact (FactToGenerate), if + /// called with a specific dataflow fact (From). + /// However, like killFlowIf it stops propagating all other dataflow facts. + /// + /// Given a flow function f = generateFlowAndKillAllOthers(v, w), for all + /// incoming dataflow facts x: + /// f(w) = {v, w} + /// f(x) = {}. + /// + /// Equivalent to: killFlowIf(λz.z!=w) o generateFlow(v, w) (where o denotes + /// function composition) + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ | + /// inst | \ ... + /// v v + /// x w v u + /// + static auto generateFlowAndKillAllOthers(d_t FactToGenerate, d_t From) { + struct GenFlowAndKillAllOthers final + : public FlowFunction { + GenFlowAndKillAllOthers(d_t GenValue, d_t FromValue) + : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + return {std::move(Source), GenValue}; + } + return {}; } - return C; - } - }; - return std::make_shared( - MakeContainer(std::forward(FactsToGenerate)), std::move(From)); -} -//===----------------------------------------------------------------------===// -// Miscellaneous flow functions + d_t GenValue; + d_t FromValue; + }; -/// A flow function that, similar to generateFlow, generates a new dataflow fact -/// (FactsToGenerate) when called with a specific dataflow fact (From). -/// Unlike generateFlow, it kills FactToGenerate if it is part of the incoming -/// facts. THis has no additional effect for IFDS analyses (which in fact should -/// use generateFlow instead), but for IDE analyses it may avoid joining the -/// edge functions reaching the FactToGenerate together which may improve the -/// analysis' precision. -/// -/// Given a flow function f = transferFlow(v, w), for all incoming dataflow -/// facts x: -/// f(v) = {} -/// f(w) = {v, w} -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w v u ... -/// | |\ | | ... -/// | | \ | ... -/// inst | | \ | ... -/// v v v v ... -/// x w v u -/// -template > -auto transferFlow(psr::type_identity_t FactToGenerate, D From) { - struct TransferFlow final : public FlowFunction { - TransferFlow(D GenValue, D FromValue) - : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - return {std::move(Source), GenValue}; - } - if (Source == GenValue) { + return std::make_shared(std::move(FactToGenerate), + std::move(From)); + } + + /// A flow function similar to generateFlowAndKillAllOthers that may generate + /// multiple dataflow facts (FactsToGenerate) is called with a specific fact + /// (From) and stops propagating all other dataflow facts. + /// + /// Given a flow function f = generateManyFlowsAndKillAllOthers({v1, v2, ..., + /// vN}, w), for all incoming dataflow facts x: + /// f(w) = {v1, v2, ..., vN, w} + /// f(x) = {}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ \ ... \ | ... + /// inst | \ \ ... \ ... + /// v v v ... \ ... + /// x w v1 v2 ... vN u + /// + template , + typename = std::enable_if_t>> + static auto generateManyFlowsAndKillAllOthers(Range &&FactsToGenerate, + d_t From) { + struct GenManyAndKillAllOthers final + : public FlowFunction { + GenManyAndKillAllOthers(Container &&GenValues, d_t FromValue) + : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + auto Ret = GenValues; + Ret.insert(std::move(Source)); + return Ret; + } return {}; } - return {std::move(Source)}; - } - D GenValue; - D FromValue; - }; + container_type GenValues; + d_t FromValue; + }; - return std::make_shared(std::move(FactToGenerate), - std::move(From)); -} + return std::make_shared( + detail::makeContainer( + std::forward(FactsToGenerate)), + std::move(From)); + } -/// A flow function that takes two other flow functions OneFF and OtherFF and -/// applies both flow functions on each input merging the results together with -/// set-union. -/// -/// Given a flow function f = unionFlows(g, h), for all incoming dataflow facts -/// x: -/// f(x) = g(x) u h(x). (where u denotes set-union) -/// -template && - std::is_same_v>> -auto unionFlows(FlowFunctionPtrTypeOf OneFF, - FlowFunctionPtrTypeOf OtherFF) { - struct UnionFlow final : public FlowFunction { - UnionFlow(FlowFunctionPtrTypeOf OneFF, - FlowFunctionPtrTypeOf OtherFF) noexcept - : OneFF(std::move(OneFF)), OtherFF(std::move(OtherFF)) {} - - Container computeTargets(D Source) override { - auto OneRet = OneFF->computeTargets(Source); - auto OtherRet = OtherFF->computeTargets(std::move(Source)); - if (OneRet.size() < OtherRet.size()) { - std::swap(OneRet, OtherRet); + //===----------------------------------------------------------------------===// + // Miscellaneous flow functions + + /// A flow function that, similar to generateFlow, generates a new dataflow + /// fact (FactsToGenerate) when called with a specific dataflow fact (From). + /// Unlike generateFlow, it kills FactToGenerate if it is part of the incoming + /// facts. THis has no additional effect for IFDS analyses (which in fact + /// should use generateFlow instead), but for IDE analyses it may avoid + /// joining the edge functions reaching the FactToGenerate together which may + /// improve the analysis' precision. + /// + /// Given a flow function f = transferFlow(v, w), for all incoming dataflow + /// facts x: + /// f(v) = {} + /// f(w) = {v, w} + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w v u ... + /// | |\ | | ... + /// | | \ | ... + /// inst | | \ | ... + /// v v v v ... + /// x w v u + /// + static auto transferFlow(d_t FactToGenerate, d_t From) { + struct TransferFlow final : public FlowFunction { + TransferFlow(d_t GenValue, d_t FromValue) + : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + return {std::move(Source), GenValue}; + } + if (Source == GenValue) { + return {}; + } + return {std::move(Source)}; } - OneRet.insert(std::make_move_iterator(OtherRet.begin()), - std::make_move_iterator(OtherRet.end())); - return OneRet; - } + d_t GenValue; + d_t FromValue; + }; - FlowFunctionPtrTypeOf OneFF; - FlowFunctionPtrTypeOf OtherFF; - }; + return std::make_shared(std::move(FactToGenerate), + std::move(From)); + } - return std::make_shared(std::move(OneFF), std::move(OtherFF)); -} + /// A flow function that takes two other flow functions OneFF and OtherFF and + /// applies both flow functions on each input merging the results together + /// with set-union. + /// + /// Given a flow function f = unionFlows(g, h), for all incoming dataflow + /// facts x: + /// f(x) = g(x) u h(x). (where u denotes set-union) + /// + template && + std::is_same_v && + std::is_same_v>> + auto unionFlows(FlowFunctionPtrTypeOf OneFF, + FlowFunctionPtrTypeOf OtherFF) { + struct UnionFlow final : public FlowFunction { + UnionFlow(FlowFunctionPtrTypeOf OneFF, + FlowFunctionPtrTypeOf OtherFF) noexcept + : OneFF(std::move(OneFF)), OtherFF(std::move(OtherFF)) {} + + container_type computeTargets(d_t Source) override { + auto OneRet = OneFF->computeTargets(Source); + auto OtherRet = OtherFF->computeTargets(std::move(Source)); + if (OneRet.size() < OtherRet.size()) { + std::swap(OneRet, OtherRet); + } + + OneRet.insert(std::make_move_iterator(OtherRet.begin()), + std::make_move_iterator(OtherRet.end())); + return OneRet; + } -/// Wrapper flow function that is automatically used by the IDESolver if the -/// autoAddZero configuration option is set to true (default). -/// Ensures that the tautological zero-flow fact (Λ) does not get killed. -template > -class ZeroedFlowFunction : public FlowFunction { - using typename FlowFunction::container_type; - using typename FlowFunction::FlowFunctionPtrType; + FlowFunctionPtrTypeOf OneFF; + FlowFunctionPtrTypeOf OtherFF; + }; -public: - ZeroedFlowFunction(FlowFunctionPtrType FF, D ZV) - : Delegate(std::move(FF)), ZeroValue(ZV) {} - container_type computeTargets(D Source) override { - if (Source == ZeroValue) { - container_type Result = Delegate->computeTargets(Source); - Result.insert(ZeroValue); - return Result; - } - return Delegate->computeTargets(Source); + return std::make_shared(std::move(OneFF), std::move(OtherFF)); } - -private: - FlowFunctionPtrType Delegate; - D ZeroValue; }; //===----------------------------------------------------------------------===// // FlowFunctions Class //===----------------------------------------------------------------------===// -template > -class FlowFunctions { +template +class FlowFunctions + : protected FlowFunctionTemplates { static_assert( std::is_same::value, @@ -858,7 +854,8 @@ class FlowFunctions { // The default implementation returns a nullptr to indicate that the mechanism // should not be used. // - virtual FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, f_t CalleeFun) { + virtual FlowFunctionPtrType getSummaryFlowFunction(n_t /*Curr*/, + f_t /*CalleeFun*/) { return nullptr; } }; @@ -868,7 +865,8 @@ class FlowFunctions { //////////////////////////////////////////////////////////////////////////////// template > -class Identity : public FlowFunction { +class [[deprecated("Use identityFlow() instead")]] Identity + : public FlowFunction { public: using typename FlowFunction::FlowFunctionType; using typename FlowFunction::FlowFunctionPtrType; @@ -913,7 +911,7 @@ typename FlowFunction::FlowFunctionPtrType makeLambdaFlow(Fn &&F) { } template > -class Compose : public FlowFunction { +class [[deprecated]] Compose : public FlowFunction { public: using typename FlowFunction::FlowFunctionType; using typename FlowFunction::FlowFunctionPtrType; diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index cf4970f1d..ab20dc3f6 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -12,6 +12,7 @@ #include "phasar/ControlFlow/ICFGBase.h" #include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" #include "phasar/DataFlow/IfdsIde/EntryPointUtils.h" #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" @@ -36,11 +37,29 @@ namespace psr { struct HasNoConfigurationType; +template class AllTopFnProvider { +public: + /// Returns an edge function that represents the top element of the analysis. + virtual EdgeFunction allTopFunction() = 0; +}; + +template +class AllTopFnProvider< + AnalysisDomainTy, + std::enable_if_t>> { +public: + /// Returns an edge function that represents the top element of the analysis. + virtual EdgeFunction allTopFunction() { + return AllTop{}; + } +}; + template > class IDETabulationProblem : public FlowFunctions, public EdgeFunctions, - public JoinLattice { + public JoinLattice, + public AllTopFnProvider { public: using ProblemAnalysisDomain = AnalysisDomainTy; using d_t = typename AnalysisDomainTy::d_t; @@ -54,9 +73,10 @@ class IDETabulationProblem : public FlowFunctions, using ConfigurationTy = HasNoConfigurationType; - explicit IDETabulationProblem(const ProjectIRDBBase *IRDB, - std::vector EntryPoints, - std::optional ZeroValue) + explicit IDETabulationProblem( + const ProjectIRDBBase *IRDB, std::vector EntryPoints, + std::optional + ZeroValue) noexcept(std::is_nothrow_move_constructible_v) : IRDB(IRDB), EntryPoints(std::move(EntryPoints)), ZeroValue(std::move(ZeroValue)) { assert(IRDB != nullptr); @@ -64,12 +84,9 @@ class IDETabulationProblem : public FlowFunctions, ~IDETabulationProblem() override = default; - /// Returns an edge function that represents the top element of the analysis. - virtual EdgeFunction allTopFunction() = 0; - /// Checks if the given data-flow fact is the special tautological lambda (or /// zero) fact. - [[nodiscard]] virtual bool isZeroValue(d_t FlowFact) const { + [[nodiscard]] virtual bool isZeroValue(d_t FlowFact) const noexcept { assert(ZeroValue.has_value()); return FlowFact == *ZeroValue; } @@ -79,23 +96,24 @@ class IDETabulationProblem : public FlowFunctions, [[nodiscard]] virtual InitialSeeds initialSeeds() = 0; /// Returns the special tautological lambda (or zero) fact. - [[nodiscard]] d_t getZeroValue() const { + [[nodiscard]] ByConstRef getZeroValue() const { assert(ZeroValue.has_value()); return *ZeroValue; } - void initializeZeroValue(d_t Zero) { + void initializeZeroValue(d_t Zero) noexcept( + std::is_nothrow_assignable_v &, d_t &&>) { assert(!ZeroValue.has_value()); ZeroValue = std::move(Zero); } /// Sets the configuration to be used by the IFDS/IDE solver. - void setIFDSIDESolverConfig(IFDSIDESolverConfig Config) { + void setIFDSIDESolverConfig(IFDSIDESolverConfig Config) noexcept { SolverConfig = Config; } /// Returns the configuration of the IFDS/IDE solver. - [[nodiscard]] IFDSIDESolverConfig &getIFDSIDESolverConfig() { + [[nodiscard]] IFDSIDESolverConfig &getIFDSIDESolverConfig() noexcept { return SolverConfig; } @@ -122,7 +140,8 @@ class IDETabulationProblem : public FlowFunctions, protected: typename FlowFunctions::FlowFunctionPtrType generateFromZero(d_t FactToGenerate) { - return generateFlow(std::move(FactToGenerate), getZeroValue()); + return FlowFunctions::generateFlow( + std::move(FactToGenerate), getZeroValue()); } /// Seeds that just start with ZeroValue and bottomElement() at the starting diff --git a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h index 5deddf1f9..e669a26a9 100644 --- a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h @@ -76,8 +76,6 @@ class IFDSTabulationProblem d_t /*SuccNode*/) final { return EdgeIdentity{}; } - - EdgeFunction allTopFunction() final { return AllTop{}; } }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h index 57bff2b65..dba21e5d5 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h @@ -355,27 +355,6 @@ mapFactsToCaller(const llvm::CallBase *CallSite, PropagateZeroToCaller); } -//===----------------------------------------------------------------------===// -// Propagation flow functions - -/// Utility function to simplify writing a flow function of the form: -/// generateFlow(Load, from: Load->getPointerOperand()). -template > -FlowFunctionPtrType -propagateLoad(const llvm::LoadInst *Load) { - return generateFlow( - Load, Load->getPointerOperand()); -} - -/// Utility function to simplify writing a flow function of the form: -/// generateFlow(Store->getValueOperand(), from: Store->getPointerOperand()). -template > -FlowFunctionPtrType -propagateStore(const llvm::StoreInst *Store) { - return generateFlow( - Store->getValueOperand(), Store->getPointerOperand()); -} - //===----------------------------------------------------------------------===// // Update flow functions diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h index e0f6d8b9e..ad55a9840 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h @@ -53,7 +53,7 @@ class LLVMZeroValue : public llvm::GlobalVariable { static const LLVMZeroValue *getInstance(); // NOLINTNEXTLINE(readability-identifier-naming) - static constexpr auto isLLVMZeroValue = [](const llvm::Value *V) { + static constexpr auto isLLVMZeroValue = [](const llvm::Value *V) noexcept { return V == getInstance(); }; }; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index e2ba69e2d..e7dceb8eb 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -246,17 +246,7 @@ class IDEExtendedTaintAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - EdgeFunctionType allTopFunction() override; - - // JoinLattice - - l_t topElement() override; - - l_t bottomElement() override; - - l_t join(l_t LHS, l_t RHS) override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // Printing functions diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h index 9461ff4f2..edde5b462 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h @@ -74,7 +74,7 @@ class IDEGeneralizedLCA : public IDETabulationProblem { [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index 207c9bdbe..8f9a71af7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -270,7 +270,7 @@ class IDEInstInteractionAnalysisT // if (const auto *Alloca = llvm::dyn_cast(Curr)) { PHASAR_LOG_LEVEL(DFADEBUG, "AllocaInst"); - return generateFromZero(Alloca); + return this->generateFromZero(Alloca); } // Handle indirect taints, i. e., propagate values that depend on branch @@ -293,7 +293,7 @@ class IDEInstInteractionAnalysisT // v v v v // 0 c x I // - return lambdaFlow([Br](d_t Src) { + return this->lambdaFlow([Br](d_t Src) { container_type Facts; Facts.insert(Src); if (Src == Br->getCondition()) { @@ -329,7 +329,7 @@ class IDEInstInteractionAnalysisT // v v v // 0 Y x // - return generateFlowIf( + return this->generateFlowIf( Load, [PointerOp = Load->getPointerOperand(), PTS = PT.getReachableAllocationSites( Load->getPointerOperand(), OnlyConsiderLocalAliases)]( @@ -355,7 +355,7 @@ class IDEInstInteractionAnalysisT // v v v // 0 x Y // - return lambdaFlow( + return this->lambdaFlow( [Store, PointerPTS = PT.getReachableAllocationSites( Store->getPointerOperand(), OnlyConsiderLocalAliases, Store)](d_t Src) -> container_type { @@ -396,7 +396,7 @@ class IDEInstInteractionAnalysisT // 0 y x // if (const auto *Load = llvm::dyn_cast(Curr)) { - return generateFlow(Load, Load->getPointerOperand()); + return this->generateFlow(Load, Load->getPointerOperand()); } // Handle store instructions // @@ -409,7 +409,7 @@ class IDEInstInteractionAnalysisT // 0 x y // if (const auto *Store = llvm::dyn_cast(Curr)) { - return lambdaFlow([Store](d_t Src) -> container_type { + return this->lambdaFlow([Store](d_t Src) -> container_type { // Override old value, i.e., kill value that is written to and // generate from value that is stored. if (Store->getPointerOperand() == Src) { @@ -448,7 +448,7 @@ class IDEInstInteractionAnalysisT // v v v v // 0 x o p // - return lambdaFlow([Inst = Curr](d_t Src) { + return this->lambdaFlow([Inst = Curr](d_t Src) { container_type Facts; if (IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { // keep the zero flow fact @@ -483,11 +483,11 @@ class IDEInstInteractionAnalysisT f_t DestFun) override { if (this->ICF->isHeapAllocatingFunction(DestFun)) { // Kill add facts and model the effects in getCallToRetFlowFunction(). - return killAllFlows(); + return this->killAllFlows(); } if (DestFun->isDeclaration()) { // We don't have anything that we could analyze, kill all facts. - return killAllFlows(); + return this->killAllFlows(); } const auto *CS = llvm::cast(CallSite); @@ -509,9 +509,9 @@ class IDEInstInteractionAnalysisT auto SRetFormal = CS->hasStructRetAttr() ? DestFun->getArg(0) : nullptr; if (SRetFormal) { - return unionFlows( + return this->unionFlows( std::move(MapFactsToCalleeFF), - generateFlowAndKillAllOthers(SRetFormal, this->getZeroValue())); + this->generateFlowAndKillAllOthers(SRetFormal, this->getZeroValue())); } return MapFactsToCalleeFF; @@ -582,9 +582,9 @@ class IDEInstInteractionAnalysisT } } - return lambdaFlow([CallSite = llvm::cast(CallSite), - OnlyDecls, - AllVoidRetTys](d_t Source) -> container_type { + return this->lambdaFlow([CallSite = llvm::cast(CallSite), + OnlyDecls, + AllVoidRetTys](d_t Source) -> container_type { // There are a few things to consider, in case only declarations of // callee targets are available. if (OnlyDecls) { @@ -659,7 +659,9 @@ class IDEInstInteractionAnalysisT return LLVMZeroValue::getInstance(); } - inline bool isZeroValue(d_t d) const override { return isZeroValueImpl(d); } + inline bool isZeroValue(d_t d) const noexcept override { + return isZeroValueImpl(d); + } // In addition provide specifications for the IDE parts. @@ -946,8 +948,6 @@ class IDEInstInteractionAnalysisT inline l_t join(l_t Lhs, l_t Rhs) override { return joinImpl(Lhs, Rhs); } - inline EdgeFunctionType allTopFunction() override { return AllTop(); } - // Provide some handy helper edge functions to improve reuse. // Edge function that kills all labels in a set (and may replaces them with diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h index d84f491cc..2e7c6d873 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -94,7 +94,7 @@ class IDELinearConstantAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts @@ -117,8 +117,6 @@ class IDELinearConstantAnalysis EdgeFunction getSummaryEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode) override; - EdgeFunction allTopFunction() override; - // Helper functions [[nodiscard]] lca_results_t getLCAResults(SolverResults SR); diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h index d4927219e..c4b9ab965 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h @@ -66,7 +66,7 @@ class IDEProtoAnalysis : public IDETabulationProblem { [[nodiscard]] d_t createZeroValue() const; - bool isZeroValue(d_t Fact) const override; + bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h index a41352335..81036cdbe 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h @@ -81,7 +81,7 @@ class IDESecureHeapPropagation [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts @@ -105,14 +105,6 @@ class IDESecureHeapPropagation n_t RetSite, d_t RetSiteNode) override; - l_t topElement() override; - - l_t bottomElement() override; - - l_t join(l_t Lhs, l_t Rhs) override; - - EdgeFunction allTopFunction() override; - void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS) override; }; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h index 2bc92e9db..3c1736fb5 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h @@ -67,7 +67,7 @@ class IDESolverTest : public IDETabulationProblem { [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 475e18ead..9335838f9 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -44,18 +44,29 @@ class LLVMBasedICFG; class LLVMTypeHierarchy; namespace detail { -class IDETypeStateAnalysisBase { + +class IDETypeStateAnalysisBaseCommon : public LLVMAnalysisDomainDefault { +public: + using container_type = std::set; + using FlowFunctionPtrType = FlowFunctionPtrType; +}; + +class IDETypeStateAnalysisBase + : private IDETypeStateAnalysisBaseCommon, + private FlowFunctionTemplates< + IDETypeStateAnalysisBaseCommon::d_t, + IDETypeStateAnalysisBaseCommon::container_type> { public: virtual ~IDETypeStateAnalysisBase() = default; protected: IDETypeStateAnalysisBase(LLVMAliasInfoRef PT) noexcept : PT(PT) {} - using d_t = const llvm::Value *; - using n_t = const llvm::Instruction *; - using f_t = const llvm::Function *; - using container_type = std::set; - using FlowFunctionPtrType = FlowFunctionPtrType; + using typename IDETypeStateAnalysisBaseCommon::container_type; + using typename IDETypeStateAnalysisBaseCommon::d_t; + using typename IDETypeStateAnalysisBaseCommon::f_t; + using typename IDETypeStateAnalysisBaseCommon::FlowFunctionPtrType; + using typename IDETypeStateAnalysisBaseCommon::n_t; // --- Flow Functions @@ -115,7 +126,7 @@ class IDETypeStateAnalysisBase { private: FlowFunctionPtrType generateFromZero(d_t FactToGenerate) { - return generateFlow(FactToGenerate, LLVMZeroValue::getInstance()); + return generateFlow(FactToGenerate, LLVMZeroValue::getInstance()); } bool hasMatchingTypeName(const llvm::Type *Ty); @@ -383,7 +394,7 @@ class IDETypeStateAnalysis return LLVMZeroValue::getInstance(); } - [[nodiscard]] bool isZeroValue(d_t Fact) const override { + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h index 0d4585614..590513a44 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h @@ -142,7 +142,7 @@ class IFDSConstAnalysis */ [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h index fc0f52a9a..135a51811 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h @@ -81,7 +81,7 @@ class IFDSFieldSensTaintAnalysis return ExtendedValue(LLVMZeroValue::getInstance()); } - [[nodiscard]] bool isZeroValue(ExtendedValue EV) const override { + [[nodiscard]] bool isZeroValue(ExtendedValue EV) const noexcept override { return LLVMZeroValue::isLLVMZeroValue(EV.getValue()); } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h index 9e3e43769..fb1db483c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h @@ -52,7 +52,7 @@ class IFDSProtoAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h index 5575275c4..54338de63 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h @@ -53,7 +53,7 @@ class IFDSSignAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h index 8099e5184..edf176f77 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h @@ -51,7 +51,7 @@ class IFDSSolverTest [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h index 49479bc1e..5e6d85ccf 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -77,7 +77,7 @@ class IFDSTaintAnalysis [[nodiscard]] d_t createZeroValue() const; - bool isZeroValue(d_t FlowFact) const override; + bool isZeroValue(d_t FlowFact) const noexcept override; void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h index 3f9edcfe8..8f5c8c04f 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h @@ -44,7 +44,7 @@ class IFDSTypeAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h index ee81523e0..c6a92f457 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h @@ -60,7 +60,7 @@ class IFDSUninitializedVariables [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; void emitTextReport(const SolverResults &Results, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 7aebbdb72..745cc4b42 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -68,6 +68,12 @@ template struct has_str().str())> : std::true_type { }; // NOLINT +template struct has_reserve : std::false_type {}; +template +struct has_reserve< + T, std::void_t().reserve(size_t(0)))>> + : std::true_type {}; + template struct has_adl_to_string { template ())))> @@ -251,6 +257,12 @@ template struct DefaultConstruct { } }; +template void reserveIfPossible(T &Container, size_t Capacity) { + if constexpr (detail::has_reserve::value) { + Container.reserve(Capacity); + } +} + template >> [[nodiscard]] decltype(auto) adl_to_string(const T &Val) { using std::to_string; diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp index 9c39547aa..02c08a309 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @@ -66,15 +66,10 @@ auto IDEExtendedTaintAnalysis::createZeroValue() const -> d_t { return FactFactory.getOrCreateZero(); } -bool IDEExtendedTaintAnalysis::isZeroValue(d_t Fact) const { +bool IDEExtendedTaintAnalysis::isZeroValue(d_t Fact) const noexcept { return Fact->isZero(); } -IDEExtendedTaintAnalysis::EdgeFunctionType -IDEExtendedTaintAnalysis::allTopFunction() { - return AllTop{}; -} - // Flow functions: IDEExtendedTaintAnalysis::FlowFunctionPtrType @@ -101,7 +96,7 @@ IDEExtendedTaintAnalysis::getNormalFlowFunction(n_t Curr, } if (const auto *Phi = llvm::dyn_cast(Curr)) { - return lambdaFlow([this, Phi](d_t Source) -> std::set { + return lambdaFlow([this, Phi](d_t Source) -> std::set { auto NumOps = Phi->getNumIncomingValues(); for (unsigned I = 0; I < NumOps; ++I) { if (equivalent(Source, makeFlowFact(Phi->getIncomingValue(I)))) { @@ -113,7 +108,7 @@ IDEExtendedTaintAnalysis::getNormalFlowFunction(n_t Curr, }); } - return Identity::getInstance(); + return identityFlow(); } IDEExtendedTaintAnalysis::FlowFunctionPtrType @@ -128,8 +123,8 @@ IDEExtendedTaintAnalysis::getStoreFF(const llvm::Value *PointerOp, AliasInfoRef::AliasSetPtrTy PTS = nullptr; auto Mem = makeFlowFact(PointerOp); - return lambdaFlow([this, TV, Mem, PTS, PointerOp, ValueOp, Store, - PALevel](d_t Source) mutable -> std::set { + return lambdaFlow([this, TV, Mem, PTS, PointerOp, ValueOp, Store, + PALevel](d_t Source) mutable -> std::set { if (Source->isZero()) { std::set Ret = {Source}; generateFromZero(Ret, Store, PointerOp, ValueOp, @@ -273,8 +268,8 @@ auto IDEExtendedTaintAnalysis::handleConfig(const llvm::Instruction *Inst, populateWithMayAliases(SourceConfig); } - return lambdaFlow([Inst, this, SourceConfig{std::move(SourceConfig)}, - SinkConfig{std::move(SinkConfig)}](d_t Source) { + return lambdaFlow([Inst, this, SourceConfig{std::move(SourceConfig)}, + SinkConfig{std::move(SinkConfig)}](d_t Source) { std::set Ret = {Source}; if (Source->isZero()) { @@ -299,14 +294,13 @@ IDEExtendedTaintAnalysis::getCallFlowFunction(n_t CallStmt, f_t DestFun) { const auto *Call = llvm::cast(CallStmt); assert(Call); if (DestFun->isDeclaration()) { - return Identity::getInstance(); + return identityFlow(); } bool HasVarargs = Call->arg_size() > DestFun->arg_size(); const auto *const VA = HasVarargs ? getVAListTagOrNull(DestFun) : nullptr; - return lambdaFlow([this, Call, DestFun, - VA](d_t Source) -> std::set { + return lambdaFlow([this, Call, DestFun, VA](d_t Source) -> std::set { if (isZeroValue(Source)) { return {Source}; } @@ -394,7 +388,7 @@ IDEExtendedTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t CalleeFun, if (!CallSite) { /// In case of unbalanced return, we may reach the artificial Global Ctor /// caller that has no caller - return killFlowIf([](d_t Source) { + return killFlowIf([](d_t Source) { return !llvm::isa_and_nonnull(Source->base()); }); } @@ -421,11 +415,11 @@ IDEExtendedTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t CalleeFun, }; const auto *Call = llvm::cast(CallSite); - return lambdaFlow([this, Call, CalleeFun, - ExitStmt{llvm::cast(ExitStmt)}, - PTC{ArgAliasCache(PT, Call->arg_size(), - HasPreciseAliasInfo)}]( - d_t Source) mutable -> std::set { + return lambdaFlow([this, Call, CalleeFun, + ExitStmt{llvm::cast(ExitStmt)}, + PTC{ArgAliasCache(PT, Call->arg_size(), + HasPreciseAliasInfo)}]( + d_t Source) mutable -> std::set { if (isZeroValue(Source)) { return {Source}; } @@ -497,7 +491,7 @@ IDEExtendedTaintAnalysis::getCallToRetFlowFunction( // into // // that function - // return lambdaFlow([CallSite, this](d_t Source) -> std::set + // return lambdaFlow([CallSite, this](d_t Source) -> std::set // { // if (isZeroValue(Source)) { // return {}; @@ -538,7 +532,7 @@ IDEExtendedTaintAnalysis::getCallToRetFlowFunction( [](const llvm::Function *F) { return F->isDeclaration(); }); if (HasDeclaration) { - return Identity::getInstance(); + return identityFlow(); } return killFlow(getZeroValue()); @@ -765,16 +759,6 @@ void IDEExtendedTaintAnalysis::emitTextReport( OS << '\n'; } -// JoinLattice - -auto IDEExtendedTaintAnalysis::topElement() -> l_t { return Top{}; } - -auto IDEExtendedTaintAnalysis::bottomElement() -> l_t { return Bottom{}; } - -auto IDEExtendedTaintAnalysis::join(l_t LHS, l_t RHS) -> l_t { - return LHS.join(RHS, &BBO); -} - // Helpers: auto IDEExtendedTaintAnalysis::makeFlowFact(const llvm::Value *V) -> d_t { diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp index cfb72c540..b49ecb872 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp @@ -39,12 +39,6 @@ namespace psr { using namespace glca; -template >> -inline auto flow(Fn Func) { - return lambdaFlow(std::forward(Func)); -} - IDEGeneralizedLCA::IDEGeneralizedLCA(const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, std::vector EntryPoints, @@ -63,9 +57,9 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, const auto *ValueOp = Store->getValueOperand(); if (isConstant(ValueOp)) { // llvm::outs() << "==> constant store" << std::endl; - return lambdaFlow([=](IDEGeneralizedLCA::d_t Source) - -> std::set { - // llvm::outs() << "##> normal lambdaFlow for: " << + return lambdaFlow([=](IDEGeneralizedLCA::d_t Source) + -> std::set { + // llvm::outs() << "##> normal lambdaFlow for: " << // llvmIRToString(curr) // << " with " << llvmIRToString(source) << std::endl; if (Source == PointerOp) { @@ -77,7 +71,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, return {Source}; }); } - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == PointerOp) { return {}; @@ -89,7 +83,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } if (const auto *Load = llvm::dyn_cast(Curr)) { - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { // llvm::outs() << "LOAD " << llvmIRToString(curr) << std::endl; // llvm::outs() << "\twith " << llvmIRToString(source) << " ==> "; @@ -102,7 +96,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } if (const auto *Gep = llvm::dyn_cast(Curr)) { - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == Gep->getPointerOperand()) { return {Source, Gep}; @@ -116,7 +110,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, Cast->getSrcTy()->isFloatingPointTy()) && (Cast->getDestTy()->isIntegerTy() || Cast->getDestTy()->isFloatingPointTy())) { - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == Cast->getOperand(0)) { return {Source, Cast}; @@ -132,7 +126,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, bool BothConst = LeftConst && RightConst; bool NoneConst = !LeftConst && !RightConst; - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == Lhs || Source == Rhs || ((BothConst || NoneConst) && isZeroValue(Source))) { @@ -142,7 +136,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } /*else if (llvm::isa(curr)) { auto op = curr->getOperand(0); - return lambdaFlow([=](IDEGeneralizedLCA::d_t source) + return lambdaFlow([=](IDEGeneralizedLCA::d_t source) -> std::set { if (source == op) return {source, curr}; @@ -151,7 +145,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } */ - return Identity::getInstance(); + return identityFlow(); } std::shared_ptr> @@ -160,7 +154,7 @@ IDEGeneralizedLCA::getCallFlowFunction(IDEGeneralizedLCA::n_t CallStmt, assert(llvm::isa(CallStmt)); if (isStringConstructor(DestMthd)) { // kill all data-flow facts at calls to string constructors - return killAllFlows(); + return killAllFlows(); } return std::make_shared( llvm::cast(CallStmt), DestMthd); @@ -196,7 +190,7 @@ IDEGeneralizedLCA::getCallToRetFlowFunction(IDEGeneralizedLCA::n_t CallSite, // found std::string ctor return generateFromZero(CS->getArgOperand(0)); } - // return lambdaFlow([Call](IDEGeneralizedLCA::d_t Source) + // return lambdaFlow([Call](IDEGeneralizedLCA::d_t Source) // -> std::set { // // llvm::outs() << "In getCallToRetFlowFunction\n"; // // llvm::outs() << llvmIRToString(Source) << '\n'; @@ -210,7 +204,7 @@ IDEGeneralizedLCA::getCallToRetFlowFunction(IDEGeneralizedLCA::n_t CallSite, // return {Source}; // }); } - return Identity::getInstance(); + return identityFlow(); } std::shared_ptr> @@ -249,7 +243,8 @@ IDEGeneralizedLCA::d_t IDEGeneralizedLCA::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDEGeneralizedLCA::isZeroValue(IDEGeneralizedLCA::d_t Fact) const { +bool IDEGeneralizedLCA::isZeroValue( + IDEGeneralizedLCA::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp index fef29aaf6..a8aa6e824 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp @@ -304,7 +304,7 @@ IDELinearConstantAnalysis::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) { if (const auto *Load = llvm::dyn_cast(Curr)) { // only consider i32 load if (Load->getType()->isIntegerTy()) { - return generateFlowIf(Load, [Load](d_t Source) { + return generateFlowIf(Load, [Load](d_t Source) { return Source == Load->getPointerOperand(); }); } @@ -313,7 +313,7 @@ IDELinearConstantAnalysis::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) { if (llvm::isa(Curr)) { auto *Lop = Curr->getOperand(0); auto *Rop = Curr->getOperand(1); - return generateFlowIf(Curr, [this, Lop, Rop](d_t Source) { + return generateFlowIf(Curr, [this, Lop, Rop](d_t Source) { /// Intentionally include nonlinear operations here for being able to /// explicitly set them to BOTTOM in the edge function return (Lop == Source) || (Rop == Source) || @@ -331,12 +331,12 @@ IDELinearConstantAnalysis::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) { if (const auto *BinIntrinsic = llvm::dyn_cast(Agg)) { if (Extract->getType()->isIntegerTy()) { - return generateFlow(Curr, Agg); + return generateFlow(Curr, Agg); } } } - return identityFlow(); + return identityFlow(); } IDELinearConstantAnalysis::FlowFunctionPtrType @@ -351,7 +351,7 @@ IDELinearConstantAnalysis::getCallFlowFunction(n_t CallSite, f_t DestFun) { } } // Pass everything else as identity - return identityFlow(); + return identityFlow(); } IDELinearConstantAnalysis::FlowFunctionPtrType @@ -372,7 +372,7 @@ IDELinearConstantAnalysis::FlowFunctionPtrType IDELinearConstantAnalysis::getCallToRetFlowFunction( n_t CallSite, n_t /*RetSite*/, llvm::ArrayRef Callees) { if (llvm::all_of(Callees, [](f_t Fun) { return Fun->isDeclaration(); })) { - return identityFlow(); + return identityFlow(); } return mapFactsAlongsideCallSite( @@ -413,7 +413,7 @@ IDELinearConstantAnalysis::getSummaryFlowFunction(n_t Curr, f_t /*CalleeFun*/) { auto *Lop = BinIntrinsic->getLHS(); auto *Rop = BinIntrinsic->getRHS(); - return generateFlowIf(BinIntrinsic, [this, Lop, Rop](d_t Source) { + return generateFlowIf(BinIntrinsic, [this, Lop, Rop](d_t Source) { /// Intentionally include nonlinear operations here for being able to /// explicitly set them to BOTTOM in the edge function return (Lop == Source) || (Rop == Source) || @@ -430,7 +430,7 @@ IDELinearConstantAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDELinearConstantAnalysis::isZeroValue(d_t Fact) const { +bool IDELinearConstantAnalysis::isZeroValue(d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } @@ -564,10 +564,6 @@ IDELinearConstantAnalysis::getSummaryEdgeFunction(n_t Curr, d_t CurrNode, return EdgeIdentity{}; } -EdgeFunction IDELinearConstantAnalysis::allTopFunction() { - return AllTop{}; -} - void IDELinearConstantAnalysis::emitTextReport( const SolverResults &SR, llvm::raw_ostream &OS) { OS << "\n====================== IDE-Linear-Constant-Analysis Report " diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp index a0a8619e4..d3cff2862 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp @@ -38,26 +38,26 @@ IDEProtoAnalysis::IDEProtoAnalysis(const LLVMProjectIRDB *IRDB, IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getNormalFlowFunction(IDEProtoAnalysis::n_t /*Curr*/, IDEProtoAnalysis::n_t /*Succ*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getCallFlowFunction(IDEProtoAnalysis::n_t /*CallSite*/, IDEProtoAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getRetFlowFunction( IDEProtoAnalysis::n_t /*CallSite*/, IDEProtoAnalysis::f_t /*CalleeFun*/, IDEProtoAnalysis::n_t /*ExitSite*/, IDEProtoAnalysis::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getCallToRetFlowFunction(IDEProtoAnalysis::n_t /*CallSite*/, IDEProtoAnalysis::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType @@ -79,7 +79,7 @@ IDEProtoAnalysis::d_t IDEProtoAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDEProtoAnalysis::isZeroValue(IDEProtoAnalysis::d_t Fact) const { +bool IDEProtoAnalysis::isZeroValue(IDEProtoAnalysis::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp index 116981c0a..a06853787 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp @@ -63,13 +63,13 @@ IDESecureHeapPropagation::IDESecureHeapPropagation( IDESecureHeapPropagation::FlowFunctionPtrType IDESecureHeapPropagation::getNormalFlowFunction(n_t /*Curr*/, n_t /*Succ*/) { - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType IDESecureHeapPropagation::getCallFlowFunction(n_t /*CallSite*/, f_t /*DestMthd*/) { - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType @@ -77,7 +77,7 @@ IDESecureHeapPropagation::getRetFlowFunction(n_t /*CallSite*/, f_t /*CalleeMthd*/, n_t /*ExitInst*/, n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType @@ -91,7 +91,7 @@ IDESecureHeapPropagation::getCallToRetFlowFunction( if (FName == InitializerFn) { return generateFromZero(SecureHeapFact::INITIALIZED); } - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType IDESecureHeapPropagation::getSummaryFlowFunction(n_t /*CallSite*/, @@ -110,7 +110,7 @@ IDESecureHeapPropagation::createZeroValue() const { return SecureHeapFact::ZERO; } -bool IDESecureHeapPropagation::isZeroValue(d_t Fact) const { +bool IDESecureHeapPropagation::isZeroValue(d_t Fact) const noexcept { return Fact == SecureHeapFact::ZERO; } @@ -163,32 +163,6 @@ IDESecureHeapPropagation::getSummaryEdgeFunction(n_t /*CallSite*/, return nullptr; } -IDESecureHeapPropagation::l_t IDESecureHeapPropagation::topElement() { - return l_t::TOP; -} - -IDESecureHeapPropagation::l_t IDESecureHeapPropagation::bottomElement() { - return l_t::BOT; -} - -IDESecureHeapPropagation::l_t IDESecureHeapPropagation::join(l_t Lhs, l_t Rhs) { - if (Lhs == Rhs) { - return Lhs; - } - if (Lhs == l_t::TOP) { - return Rhs; - } - if (Rhs == l_t::TOP) { - return Lhs; - } - return l_t::BOT; -} - -EdgeFunction -IDESecureHeapPropagation::allTopFunction() { - return AllTop{}; -} - void IDESecureHeapPropagation::emitTextReport( const SolverResults &SR, llvm::raw_ostream &Os) { LLVMBasedCFG CFG; diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp index a5b37ec6f..1324d61a5 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp @@ -42,26 +42,26 @@ IDESolverTest::IDESolverTest(const LLVMProjectIRDB *IRDB, IDESolverTest::FlowFunctionPtrType IDESolverTest::getNormalFlowFunction(IDESolverTest::n_t /*Curr*/, IDESolverTest::n_t /*Succ*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType IDESolverTest::getCallFlowFunction(IDESolverTest::n_t /*CallSite*/, IDESolverTest::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType IDESolverTest::getRetFlowFunction( IDESolverTest::n_t /*CallSite*/, IDESolverTest::f_t /*CalleeFun*/, IDESolverTest::n_t /*ExitStmt*/, IDESolverTest::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType IDESolverTest::getCallToRetFlowFunction(IDESolverTest::n_t /*CallSite*/, IDESolverTest::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType @@ -82,7 +82,7 @@ IDESolverTest::d_t IDESolverTest::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDESolverTest::isZeroValue(IDESolverTest::d_t Fact) const { +bool IDESolverTest::isZeroValue(IDESolverTest::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp index b646ea57f..3f20b5d97 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp @@ -55,13 +55,12 @@ auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) } if (const auto *Gep = llvm::dyn_cast(Curr)) { if (hasMatchingType(Gep->getPointerOperand())) { - return identityFlow(); - // return lambdaFlow([=](d_t Source) -> std::set { - // // if (Source == Gep->getPointerOperand()) { - // // return {Source, Gep}; - // //} - // return {Source}; - // }); + return lambdaFlow([=](d_t Source) -> std::set { + // if (Source == Gep->getPointerOperand()) { + // return {Source, Gep}; + //} + return {Source}; + }); } } // Check store instructions for target type. Perform a strong update, i.e. @@ -76,7 +75,7 @@ auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) Curr->getFunction()->getName().str()); RelevantAliasesAndAllocas.insert(Store->getValueOperand()); - return lambdaFlow( + return lambdaFlow( [Store, AliasesAndAllocas = std::move(RelevantAliasesAndAllocas)]( d_t Source) -> container_type { // We kill all relevant loacal aliases and alloca's @@ -93,7 +92,7 @@ auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) }); } } - return identityFlow(); + return identityFlow(); } auto IDETypeStateAnalysisBase::getCallFlowFunction(n_t CallSite, f_t DestFun) @@ -101,7 +100,7 @@ auto IDETypeStateAnalysisBase::getCallFlowFunction(n_t CallSite, f_t DestFun) // Kill all data-flow facts if we hit a function of the target API. // Those functions are modled within Call-To-Return. if (isAPIFunction(llvm::demangle(DestFun->getName().str()))) { - return killAllFlows(); + return killAllFlows(); } // Otherwise, if we have an ordinary function call, we can just use the // standard mapping. @@ -116,10 +115,9 @@ auto IDETypeStateAnalysisBase::getRetFlowFunction(n_t CallSite, f_t CalleeFun, -> FlowFunctionPtrType { /// TODO: Implement return-POI in LLVMFlowFunctions.h - return lambdaFlow([this, CalleeFun, - CS = llvm::cast(CallSite), - Ret = llvm::dyn_cast(ExitStmt)]( - d_t Source) -> container_type { + return lambdaFlow([this, CalleeFun, CS = llvm::cast(CallSite), + Ret = llvm::dyn_cast(ExitStmt)]( + d_t Source) -> container_type { if (LLVMZeroValue::isLLVMZeroValue(Source)) { return {Source}; } @@ -206,12 +204,12 @@ auto IDETypeStateAnalysisBase::getCallToRetFlowFunction( if (!isAPIFunction(DemangledFname) && !Callee->isDeclaration()) { for (const auto &Arg : CS->args()) { if (hasMatchingType(Arg)) { - return killManyFlows(getWMAliasesAndAllocas(Arg.get())); + return killManyFlows(getWMAliasesAndAllocas(Arg.get())); } } } } - return identityFlow(); + return identityFlow(); } auto IDETypeStateAnalysisBase::getSummaryFlowFunction(n_t /*CallSite*/, diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp index c98996653..69cd1f1a2 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp @@ -52,7 +52,7 @@ IFDSConstAnalysis::getNormalFlowFunction(IFDSConstAnalysis::n_t Curr, // If the store instruction sets up or updates the vtable, i.e. value // operand is vtable pointer, ignore it! if (isTouchVTableInst(Store)) { - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::d_t PointerOp = Store->getPointerOperand(); @@ -86,7 +86,7 @@ IFDSConstAnalysis::getNormalFlowFunction(IFDSConstAnalysis::n_t Curr, } /* end store instruction */ // Pass everything else as identity - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::FlowFunctionPtrType @@ -96,7 +96,7 @@ IFDSConstAnalysis::getCallFlowFunction(IFDSConstAnalysis::n_t CallSite, // memset) if (llvm::isa(CallSite)) { PHASAR_LOG_LEVEL(DEBUG, "Call statement is a LLVM MemIntrinsic!"); - return killAllFlows(); + return killAllFlows(); } // Check if its a Call Instruction or an Invoke Instruction. If so, we // need to map all actual parameters into formal parameters. @@ -110,7 +110,7 @@ IFDSConstAnalysis::getCallFlowFunction(IFDSConstAnalysis::n_t CallSite, } /* end call/invoke instruction */ // Pass everything else as identity - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::FlowFunctionPtrType IFDSConstAnalysis::getRetFlowFunction( @@ -151,7 +151,7 @@ IFDSConstAnalysis::getCallToRetFlowFunction(IFDSConstAnalysis::n_t CallSite, } // Pass everything else as identity - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::FlowFunctionPtrType @@ -173,7 +173,8 @@ IFDSConstAnalysis::d_t IFDSConstAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IFDSConstAnalysis::isZeroValue(IFDSConstAnalysis::d_t Fact) const { +bool IFDSConstAnalysis::isZeroValue( + IFDSConstAnalysis::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp index c28cb8b0e..d35ef58f9 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp @@ -34,32 +34,32 @@ IFDSProtoAnalysis::getNormalFlowFunction(IFDSProtoAnalysis::n_t Curr, if (const auto *Store = llvm::dyn_cast(Curr)) { return generateFromZero(Store->getPointerOperand()); } - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getCallFlowFunction(IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getRetFlowFunction( IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::f_t /*CalleeFun*/, IFDSProtoAnalysis::n_t /*ExitInst*/, IFDSProtoAnalysis::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getCallToRetFlowFunction(IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getSummaryFlowFunction(IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } InitialSeeds::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getCallFlowFunction(IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getRetFlowFunction( IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::f_t /*CalleeFun*/, IFDSSignAnalysis::n_t /*ExitStmt*/, IFDSSignAnalysis::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getCallToRetFlowFunction(IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getSummaryFlowFunction(IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } InitialSeeds::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType IFDSSolverTest::getCallFlowFunction(IFDSSolverTest::n_t /*CallSite*/, IFDSSolverTest::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType IFDSSolverTest::getRetFlowFunction( IFDSSolverTest::n_t /*CallSite*/, IFDSSolverTest::f_t /*CalleeFun*/, IFDSSolverTest::n_t /*ExitStmt*/, IFDSSolverTest::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType IFDSSolverTest::getCallToRetFlowFunction(IFDSSolverTest::n_t /*CallSite*/, IFDSSolverTest::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType @@ -69,7 +69,7 @@ IFDSSolverTest::d_t IFDSSolverTest::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IFDSSolverTest::isZeroValue(IFDSSolverTest::d_t Fact) const { +bool IFDSSolverTest::isZeroValue(IFDSSolverTest::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index 4306af47c..890c357ad 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -158,7 +158,7 @@ auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, populateWithMayAliases(Gen, Store); Gen.insert(Store->getValueOperand()); - return lambdaFlow( + return lambdaFlow( [Store, Gen{std::move(Gen)}](d_t Source) -> container_type { if (Store->getValueOperand() == Source) { return Gen; @@ -185,7 +185,7 @@ auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, } if (const auto *Insert = llvm::dyn_cast(Curr)) { - return lambdaFlow([Insert](d_t Source) -> container_type { + return lambdaFlow([Insert](d_t Source) -> container_type { if (Source == Insert->getAggregateOperand() || Source == Insert->getInsertedValueOperand()) { return {Source, Insert}; @@ -200,11 +200,11 @@ auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, } if (const auto *Cast = llvm::dyn_cast(Curr)) { - return transferFlow(Cast, Cast->getOperand(0)); + return transferFlow(Cast, Cast->getOperand(0)); } // Otherwise we do not care and leave everything as it is - return Identity::getInstance(); + return identityFlow(); } auto IFDSTaintAnalysis::getCallFlowFunction(n_t CallSite, f_t DestFun) @@ -215,7 +215,7 @@ auto IFDSTaintAnalysis::getCallFlowFunction(n_t CallSite, f_t DestFun) // The respective taints or leaks are then generated in the corresponding // call to return flow function. if (isSourceCall(CS, DestFun) || isSinkCall(CS, DestFun)) { - return killAllFlows(); + return killAllFlows(); } // Map the actual into the formal parameters @@ -262,7 +262,7 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, if (DestFun->getName().equals("$sSS1poiyS2S_SStFZ")) { const auto *CS = llvm::cast(CallSite); - return generateFlowIf(CallSite, [CS](d_t Source) { + return generateFlowIf(CallSite, [CS](d_t Source) { return ((Source == CS->getArgOperand(1)) || (Source == CS->getArgOperand(3))); }); @@ -295,8 +295,8 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, if (Gen.empty()) { if (!Leak.empty() || !Kill.empty()) { - return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, - this, CallSite](d_t Source) -> container_type { + return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, this, + CallSite](d_t Source) -> container_type { if (Leak.count(Source)) { Leaks[CallSite].insert(Source); } @@ -316,8 +316,8 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, // Gen nonempty Gen.insert(LLVMZeroValue::getInstance()); - return lambdaFlow([Gen{std::move(Gen)}, Leak{std::move(Leak)}, this, - CallSite](d_t Source) -> container_type { + return lambdaFlow([Gen{std::move(Gen)}, Leak{std::move(Leak)}, this, + CallSite](d_t Source) -> container_type { if (LLVMZeroValue::isLLVMZeroValue(Source)) { return Gen; } @@ -355,7 +355,7 @@ auto IFDSTaintAnalysis::createZeroValue() const -> d_t { return LLVMZeroValue::getInstance(); } -bool IFDSTaintAnalysis::isZeroValue(d_t FlowFact) const { +bool IFDSTaintAnalysis::isZeroValue(d_t FlowFact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(FlowFact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp index e798db4f2..f7521ff33 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp @@ -94,7 +94,7 @@ IFDSTypeAnalysis::d_t IFDSTypeAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IFDSTypeAnalysis::isZeroValue(IFDSTypeAnalysis::d_t Fact) const { +bool IFDSTypeAnalysis::isZeroValue(IFDSTypeAnalysis::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp index b75979ed6..7dea9e963 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp @@ -168,26 +168,24 @@ IFDSUninitializedVariables::getNormalFlowFunction( } if (const auto *Alloc = llvm::dyn_cast(Curr)) { - return lambdaFlow( - [Alloc, this](IFDSUninitializedVariables::d_t Source) - -> std::set { - if (isZeroValue(Source)) { - if (Alloc->getAllocatedType()->isIntegerTy() || - Alloc->getAllocatedType()->isFloatingPointTy() || - Alloc->getAllocatedType()->isPointerTy() || - Alloc->getAllocatedType()->isArrayTy()) { - //------------------------------------------------------------ - // Why not generate for structs, but for arrays? (would be - // consistent to generate either both or none of them) - //------------------------------------------------------------ - - // generate the alloca - return {Source, Alloc}; - } - } - // otherwise propagate all facts - return {Source}; - }); + return lambdaFlow([Alloc, this](d_t Source) -> std::set { + if (isZeroValue(Source)) { + if (Alloc->getAllocatedType()->isIntegerTy() || + Alloc->getAllocatedType()->isFloatingPointTy() || + Alloc->getAllocatedType()->isPointerTy() || + Alloc->getAllocatedType()->isArrayTy()) { + //------------------------------------------------------------ + // Why not generate for structs, but for arrays? (would be + // consistent to generate either both or none of them) + //------------------------------------------------------------ + + // generate the alloca + return {Source, Alloc}; + } + } + // otherwise propagate all facts + return {Source}; + }); } // check if some instruction is using an undefined value (in)directly struct UVFF : FlowFunction { @@ -304,7 +302,7 @@ IFDSUninitializedVariables::getCallFlowFunction( }; return std::make_shared(DestFun, CS, getZeroValue()); } - return Identity::getInstance(); + return identityFlow(); } IFDSUninitializedVariables::FlowFunctionPtrType @@ -349,7 +347,7 @@ IFDSUninitializedVariables::getRetFlowFunction( return std::make_shared(CS, ExitStmt); } // kill everything else - return killAllFlows(); + return killAllFlows(); } IFDSUninitializedVariables::FlowFunctionPtrType @@ -361,23 +359,21 @@ IFDSUninitializedVariables::getCallToRetFlowFunction( // Handle pointer/reference parameters //---------------------------------------------------------------------- if (const auto *CS = llvm::dyn_cast(CallSite)) { - return lambdaFlow( - [CS](IFDSUninitializedVariables::d_t Source) - -> std::set { - if (Source->getType()->isPointerTy()) { - for (const auto &Arg : CS->args()) { - if (Arg.get() == Source) { - // do not propagate pointer arguments, since the function may - // initialize them (would be much more precise with - // field-sensitivity) - return {}; - } - } + return lambdaFlow([CS](d_t Source) -> std::set { + if (Source->getType()->isPointerTy()) { + for (const auto &Arg : CS->args()) { + if (Arg.get() == Source) { + // do not propagate pointer arguments, since the function may + // initialize them (would be much more precise with + // field-sensitivity) + return {}; } - return {Source}; - }); + } + } + return {Source}; + }); } - return Identity::getInstance(); + return identityFlow(); } IFDSUninitializedVariables::FlowFunctionPtrType @@ -402,7 +398,7 @@ IFDSUninitializedVariables::createZeroValue() const { } bool IFDSUninitializedVariables::isZeroValue( - IFDSUninitializedVariables::d_t Fact) const { + IFDSUninitializedVariables::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } From c78dbe0e50e1bbc1e24a76351ad7190b159f6861 Mon Sep 17 00:00:00 2001 From: Martin Mory Date: Wed, 6 Sep 2023 09:35:29 +0200 Subject: [PATCH 30/59] Fix handling of unbalanced returns for IIA (#664) * fix handling of unbalanced returns for IIA, for the change in the IDE solver I am not sure yet how this should be done properly. * Update include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Fix error due to update from dev * Separate APi for side-effets of ret-FF in case of unbalanced-return end * pre-commit --------- Co-authored-by: Martin Mory Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Co-authored-by: Fabian Schiebel --- .../phasar/DataFlow/IfdsIde/FlowFunctions.h | 13 ++++++++ .../IfdsIde/Solver/FlowEdgeFunctionCache.h | 33 +++++++++++++++++++ .../DataFlow/IfdsIde/Solver/IDESolver.h | 12 +++---- .../Problems/IDEInstInteractionAnalysis.h | 4 ++- include/phasar/Utils/Utilities.h | 23 +++++++++++++ 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index 87a3db452..7ff1769d7 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -794,6 +794,19 @@ class FlowFunctions virtual FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) = 0; + // Performs any side-effects of a return-flow-function + // + // In case of unbalanced returns (if the option `followReturnsPastSeeds` is + // activated in the IfdsIdeSolverConfig), we will eventually reach a function + // that is not called from other functions. Still, we may want to apply a + // return-flow-function -- just for its side-effects, such as registering a + // taint + virtual void applyUnbalancedRetFlowFunctionSideEffects(f_t CalleeFun, + n_t ExitInst, + d_t Source) { + // By default, do nothing + } + // // Describes the data-flows alongsite a CallSite. // diff --git a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h index 484606935..b9d89a88e 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h @@ -15,6 +15,7 @@ #include "phasar/Utils/EquivalenceClassMap.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/PAMMMacros.h" +#include "phasar/Utils/Utilities.h" #include "llvm/ADT/DenseMap.h" @@ -185,6 +186,8 @@ class FlowEdgeFunctionCache { operator=(FlowEdgeFunctionCache &&FEFC) noexcept = default; FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) { + assertNotNull(Curr); + assertNotNull(Succ); PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Normal flow function factory call"); @@ -217,6 +220,8 @@ class FlowEdgeFunctionCache { } FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) { + assertNotNull(CallSite); + assertNotNull(DestFun); PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call flow function factory call"); @@ -241,6 +246,10 @@ class FlowEdgeFunctionCache { FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) { + assertNotNull(CallSite); + assertNotNull(CalleeFun); + assertNotNull(ExitInst); + assertNotNull(RetSite); PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Return flow function factory call"); @@ -270,6 +279,9 @@ class FlowEdgeFunctionCache { FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, llvm::ArrayRef Callees) { + assertNotNull(CallSite); + assertNotNull(RetSite); + assertAllNotNull(Callees); PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return flow function factory call"); @@ -300,6 +312,8 @@ class FlowEdgeFunctionCache { } FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) { + assertNotNull(CallSite); + assertNotNull(DestFun); // PAMM_GET_INSTANCE; // INC_COUNTER("Summary-FF Construction", 1, Full); IF_LOG_ENABLED( @@ -313,6 +327,9 @@ class FlowEdgeFunctionCache { EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode) { + assertNotNull(Curr); + assertNotNull(Succ); + PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Normal edge function factory call"); @@ -357,6 +374,10 @@ class FlowEdgeFunctionCache { EdgeFunction getCallEdgeFunction(n_t CallSite, d_t SrcNode, f_t DestinationFunction, d_t DestNode) { + + assertNotNull(CallSite); + assertNotNull(DestinationFunction); + PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call edge function factory call"); @@ -387,6 +408,11 @@ class FlowEdgeFunctionCache { EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, n_t ExitInst, d_t ExitNode, n_t RetSite, d_t RetNode) { + assertNotNull(CallSite); + assertNotNull(CalleeFunction); + assertNotNull(ExitInst); + assertNotNull(RetSite); + PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Return edge function factory call"); @@ -419,6 +445,10 @@ class FlowEdgeFunctionCache { EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, llvm::ArrayRef Callees) { + assertNotNull(CallSite); + assertNotNull(RetSite); + assertAllNotNull(Callees); + PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return edge function factory call"); @@ -472,6 +502,9 @@ class FlowEdgeFunctionCache { EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode) { + assertNotNull(CallSite); + assertNotNull(RetSite); + PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Summary edge function factory call"); diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 669bd108d..ac730de2a 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -886,8 +886,9 @@ class IDESolver // conditionally generated values should only // be propagated into callers that have an incoming edge for this // condition - if (SolverConfig.followReturnsPastSeeds() && Inc.empty() && - IDEProblem.isZeroValue(d1)) { + /// TODO: Add a check for "d1 is seed in functionOf(n)" + if (SolverConfig.followReturnsPastSeeds() && Inc.empty() /*&& + IDEProblem.isZeroValue(d1)*/) { const auto &Callers = ICF->getCallersOf(FunctionThatNeedsSummary); for (n_t Caller : Callers) { for (n_t RetSiteC : ICF->getReturnSitesOfCallAt(Caller)) { @@ -922,11 +923,8 @@ class IDESolver // the flow function has a side effect such as registering a taint; // instead we thus call the return flow function will a null caller if (Callers.empty()) { - FlowFunctionPtrType RetFunction = - CachedFlowEdgeFunctions.getRetFlowFunction( - nullptr, FunctionThatNeedsSummary, n, nullptr); - INC_COUNTER("FF Queries", 1, Full); - RetFunction->computeTargets(d2); + IDEProblem.applyUnbalancedRetFlowFunctionSideEffects( + FunctionThatNeedsSummary, n, d2); } } } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index 8f9a71af7..9e9972ac4 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -522,7 +522,9 @@ class IDEInstInteractionAnalysisT n_t /* RetSite */) override { // Map return value back to the caller. If pointer parameters hold at the // end of a callee function generate all of those in the caller context. - + if (CallSite == nullptr) { + return this->killAllFlows(); + } auto MapFactsToCallerFF = mapFactsToCaller(llvm::cast(CallSite), ExitInst, {}, [](const llvm::Value *RetVal, d_t Src) { diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 12154af21..762735bfe 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -14,9 +14,12 @@ #include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" +#include #include #include #include @@ -266,6 +269,26 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, return OS; } +template +LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const T &Value) {} + +template +LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const std::optional &Value) { + assert(Value.has_value()); +} + +template +LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const T *Value) { + assert(Value != nullptr); +} + +template void assertAllNotNull(const T &Range) { + assertNotNull(Range); + for (const auto &Elem : Range) { + assertNotNull(Elem); + } +} + } // namespace psr #endif From 76fe0804c67d567e0a9b874373928e8bb4f98511 Mon Sep 17 00:00:00 2001 From: Florian Sattler Date: Sun, 10 Sep 2023 13:38:21 +0200 Subject: [PATCH 31/59] Adds helper function to determine if a function was generated by phasar (#665) * Adds helper function to determine if a function was generated by phasar During global analysis, phasar generates helper function to correctly handle global ctors/dtors and other global code fragments. With the new checking function, users can determine whether a given function was generated by phasar or not, e.g., for global analysis. * get rid of magic string literals that name the various generated functions of phasar's global ctor/dtor modelling * minor style --------- Co-authored-by: Martin Mory Co-authored-by: Martin Mory Co-authored-by: Fabian Schiebel --- .../phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h | 12 ++++++++++++ lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp | 14 ++++++++++++++ .../ControlFlow/LLVMBasedICFGGlobalsImpl.cpp | 11 ++++++----- .../ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp | 13 ++++++++----- .../PhasarLLVM/ControlFlow/LLVMBasedICFGTest.cpp | 4 ++-- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index e2171a31a..db0b492a1 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -55,6 +55,15 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { static constexpr llvm::StringLiteral GlobalCRuntimeModelName = "__psrCRuntimeGlobalCtorsModel"; + static constexpr llvm::StringLiteral GlobalCRuntimeDtorModelName = + "__psrCRuntimeGlobalDtorsModel"; + + static constexpr llvm::StringLiteral GlobalCRuntimeDtorsCallerName = + "__psrGlobalDtorsCaller"; + + static constexpr llvm::StringLiteral GlobalCRuntimeUserEntrySelectorName = + "__psrCRuntimeUserEntrySelector"; + /// Constructs the ICFG based on the given IRDB and the entry-points using a /// fixpoint iteration. This may take a long time. /// @@ -119,6 +128,9 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { /// Gets the underlying IRDB [[nodiscard]] LLVMProjectIRDB *getIRDB() const noexcept { return IRDB; } + /// Returns true, if a function was generated by phasar. + [[nodiscard]] static bool isPhasarGenerated(const llvm::Function &) noexcept; + using CFGBase::print; using ICFGBase::print; diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index 42d715c27..20ca70d3b 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -29,6 +29,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/Support/ErrorHandling.h" @@ -380,6 +381,19 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, LLVMBasedICFG::~LLVMBasedICFG() = default; +bool LLVMBasedICFG::isPhasarGenerated(const llvm::Function &F) noexcept { + if (F.hasName()) { + llvm::StringRef FunctionName = F.getName(); + return llvm::StringSwitch(FunctionName) + .Cases(GlobalCRuntimeModelName, GlobalCRuntimeDtorModelName, + GlobalCRuntimeDtorsCallerName, + GlobalCRuntimeUserEntrySelectorName, true) + .Default(false); + } + + return false; +} + [[nodiscard]] FunctionRange LLVMBasedICFG::getAllFunctionsImpl() const { return IRDB->getAllFunctions(); } diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobalsImpl.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobalsImpl.cpp index 3e91de6f3..32e42b57c 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobalsImpl.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobalsImpl.cpp @@ -124,9 +124,10 @@ static llvm::Function *createDtorCallerForModule( &RegisteredDtors) { auto *PhasarDtorCaller = llvm::cast( - Mod.getOrInsertFunction("__psrGlobalDtorsCaller." + - getReducedModuleName(Mod), - llvm::Type::getVoidTy(Mod.getContext())) + Mod.getOrInsertFunction( + LLVMBasedICFG::GlobalCRuntimeDtorsCallerName.str() + '.' + + getReducedModuleName(Mod), + llvm::Type::getVoidTy(Mod.getContext())) .getCallee()); auto *BB = @@ -195,7 +196,7 @@ static std::pair buildCRuntimeGlobalDtorsModel( auto &CTX = M.getContext(); auto *Cleanup = llvm::cast( - M.getOrInsertFunction("__psrCRuntimeGlobalDtorsModel", + M.getOrInsertFunction(LLVMBasedICFG::GlobalCRuntimeDtorModelName, llvm::Type::getVoidTy(CTX)) .getCallee()); @@ -301,7 +302,7 @@ llvm::Function *LLVMBasedICFG::buildCRuntimeGlobalCtorsDtorsModel( } else { auto UEntrySelectorFn = M.getOrInsertFunction( - "__psrCRuntimeUserEntrySelector", llvm::Type::getInt32Ty(CTX)); + GlobalCRuntimeUserEntrySelectorName, llvm::Type::getInt32Ty(CTX)); auto *UEntrySelector = IRB.CreateCall(UEntrySelectorFn); diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp index f4e913c44..0977c8189 100644 --- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGGlobCtorDtorTest.cpp @@ -93,9 +93,10 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, CtorTest) { // GlobalCtor->print(llvm::outs()); - ensureFunctionOrdering(GlobalCtor, ICFG, - {{"_GLOBAL__sub_I_globals_ctor_1.cpp", "main"}, - {"main", "__psrCRuntimeGlobalDtorsModel"}}); + ensureFunctionOrdering( + GlobalCtor, ICFG, + {{"_GLOBAL__sub_I_globals_ctor_1.cpp", "main"}, + {"main", LLVMBasedICFG::GlobalCRuntimeDtorModelName}}); } TEST_F(LLVMBasedICFGGlobCtorDtorTest, CtorTest2) { @@ -144,10 +145,12 @@ TEST_F(LLVMBasedICFGGlobCtorDtorTest, DtorTest1) { ensureFunctionOrdering( GlobalCtor, ICFG, {{"_GLOBAL__sub_I_globals_dtor_1.cpp", "main"}, - {"main", "__psrGlobalDtorsCaller.globals_dtor_1_cpp.ll"}}); + {"main", LLVMBasedICFG::GlobalCRuntimeDtorsCallerName.str() + + ".globals_dtor_1_cpp.ll"}}); auto *GlobalDtor = - IRDB.getFunction("__psrGlobalDtorsCaller.globals_dtor_1_cpp.ll"); + IRDB.getFunction(LLVMBasedICFG::GlobalCRuntimeDtorsCallerName.str() + + ".globals_dtor_1_cpp.ll"); ASSERT_NE(nullptr, GlobalDtor); diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGTest.cpp index b3894ee04..249283fde 100644 --- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGTest.cpp +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGTest.cpp @@ -83,9 +83,9 @@ TEST(LLVMBasedICFGTest, StaticCallSite_2b) { const llvm::Function *FOO = IRDB.getFunctionDefinition("foo"); const llvm::Function *BAR = IRDB.getFunctionDefinition("bar"); const llvm::Function *CTOR = - IRDB.getFunctionDefinition("__psrCRuntimeGlobalCtorsModel"); + IRDB.getFunctionDefinition(LLVMBasedICFG::GlobalCRuntimeModelName); const llvm::Function *DTOR = - IRDB.getFunctionDefinition("__psrCRuntimeGlobalDtorsModel"); + IRDB.getFunctionDefinition(LLVMBasedICFG::GlobalCRuntimeDtorModelName); ASSERT_TRUE(F); ASSERT_TRUE(FOO); ASSERT_TRUE(BAR); From 94a0e47cba8601f286fbf02248b3395958458bc0 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 21 Sep 2023 16:48:42 +0200 Subject: [PATCH 32/59] Fix Backward ICFG (#660) * Fix backwards ICFG (not all required interface functions were implemented) + use explicit template instantiation to make sure, the interface is fully implemented in the future * pre-commit --- include/phasar/ControlFlow/ICFGBase.h | 9 +-------- .../PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h | 10 +++++++++- include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h | 2 ++ lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp | 9 ++++++++- lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp | 2 ++ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/phasar/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h index 1f62fb69a..fea37796c 100644 --- a/include/phasar/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -101,14 +101,7 @@ template class ICFGBase { n_t>); return self().getReturnSitesOfCallAtImpl(Inst); } - /// Returns an iterable range of all global initializer functions - [[nodiscard]] decltype(auto) - getGlobalInitializers(ByConstRef Fun) const { - static_assert( - is_iterable_over_v); - return self().getGlobalInitializersImpl(Fun); - } + /// Prints the underlying call-graph as DOT to the given output-stream void print(llvm::raw_ostream &OS = llvm::outs()) const { self().printImpl(OS); diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h index 10a342488..101718a42 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h @@ -19,9 +19,14 @@ namespace psr { class LLVMBasedICFG; +class LLVMBasedBackwardICFG; +template class CallGraph; + +template <> +struct CFGTraits : CFGTraits {}; class LLVMBasedBackwardICFG : public LLVMBasedBackwardCFG, - public ICFGBase { + public ICFGBase { friend ICFGBase; class LLVMBackwardRet { @@ -60,6 +65,7 @@ class LLVMBasedBackwardICFG : public LLVMBasedBackwardCFG, getReturnSitesOfCallAtImpl(n_t Inst) const; void printImpl(llvm::raw_ostream &OS) const; [[nodiscard]] nlohmann::json getAsJsonImpl() const; + [[nodiscard]] const CallGraph &getCallGraphImpl() const noexcept; llvm::LLVMContext BackwardRetsCtx; llvm::DenseMap BackwardRets; @@ -68,6 +74,8 @@ class LLVMBasedBackwardICFG : public LLVMBasedBackwardCFG, LLVMBasedICFG *ForwardICFG{}; }; + +extern template class ICFGBase; } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index db0b492a1..f1af71970 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -162,6 +162,8 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { LLVMProjectIRDB *IRDB = nullptr; MaybeUniquePtr TH; }; + +extern template class ICFGBase; } // namespace psr #endif diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp index 6edadac34..0ca199d25 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.cpp @@ -9,7 +9,6 @@ #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" namespace psr { @@ -68,4 +67,12 @@ void LLVMBasedBackwardICFG::printImpl(llvm::raw_ostream &OS) const { nlohmann::json LLVMBasedBackwardICFG::getAsJsonImpl() const { return ForwardICFG->getAsJson(); } + +auto LLVMBasedBackwardICFG::getCallGraphImpl() const noexcept + -> const CallGraph & { + return ForwardICFG->getCallGraph(); +} + +template class ICFGBase; + } // namespace psr diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index 20ca70d3b..87b2279f2 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -457,4 +457,6 @@ void LLVMBasedICFG::printImpl(llvm::raw_ostream &OS) const { [this](n_t Inst) { return IRDB->getInstructionId(Inst); }); } +template class ICFGBase; + } // namespace psr From 1fafc4467a553d5ca877709ec3b70e558e5fa2b7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:37:12 +0200 Subject: [PATCH 33/59] Fix Taint Analysis (#661) * Handle Alias indirection and return-POI in taint analysis * pre-commit --- .../DataFlow/IfdsIde/LLVMFlowFunctions.h | 46 ++-- .../IfdsIde/Problems/IFDSTaintAnalysis.h | 4 +- include/phasar/Utils/TypeTraits.h | 4 + .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 205 ++++++++++++++---- .../taint_analysis/CMakeLists.txt | 2 + .../taint_analysis/double_free_01.c | 7 + .../taint_analysis/double_free_02.c | 9 + .../Problems/IFDSTaintAnalysisTest.cpp | 112 +++++++--- 8 files changed, 294 insertions(+), 95 deletions(-) create mode 100644 test/llvm_test_code/taint_analysis/double_free_01.c create mode 100644 test/llvm_test_code/taint_analysis/double_free_02.c diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h index dba21e5d5..e994671bb 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h @@ -239,7 +239,8 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, /// /// Propagates the return value back to the call-site and based on the /// PropagateParameter predicate propagates back parameters holding as dataflow -/// facts. +/// facts. The resulting out-set of dataflow facts can be post-processed if +/// necessary. /// /// Let a call-site cs: r = fun(..., ax, ...) a function prototype fun(..., /// px, ...) and an exit statement exit: return rv. @@ -252,30 +253,30 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, /// f(x) = ({ax} if PropagateParameter(ax, x) else {}) union ({r} if /// PropagateRet(rv, x) else {}). /// -template , - typename FnParam = std::equal_to, - typename FnRet = std::equal_to, - typename DCtor = DefaultConstruct, - typename = std::enable_if_t< - std::is_invocable_r_v && - std::is_invocable_r_v>> -FlowFunctionPtrType -mapFactsToCaller(const llvm::CallBase *CallSite, - const llvm::Instruction *ExitInst, - FnParam &&PropagateParameter = {}, FnRet &&PropagateRet = {}, - DCtor &&FactConstructor = {}, bool PropagateGlobals = true, - bool PropagateZeroToCaller = true) { +template < + typename D = const llvm::Value *, typename Container = std::set, + typename FnParam = std::equal_to, typename FnRet = std::equal_to, + typename DCtor = DefaultConstruct, typename PostProcessFn = IgnoreArgs, + typename = std::enable_if_t< + std::is_invocable_r_v && + std::is_invocable_r_v>> +FlowFunctionPtrType mapFactsToCaller( + const llvm::CallBase *CallSite, const llvm::Instruction *ExitInst, + FnParam &&PropagateParameter = {}, FnRet &&PropagateRet = {}, + DCtor &&FactConstructor = {}, bool PropagateGlobals = true, + bool PropagateZeroToCaller = true, PostProcessFn &&PostProcess = {}) { struct Mapper : public FlowFunction { Mapper(const llvm::CallBase *CallSite, const llvm::Instruction *ExitInst, bool PropagateGlobals, FnParam &&PropagateParameter, FnRet &&PropagateRet, DCtor &&FactConstructor, - bool PropagateZeroToCaller) + bool PropagateZeroToCaller, PostProcessFn &&PostProcess) : CSAndPropGlob(CallSite, PropagateGlobals), ExitInstAndPropZero(ExitInst, PropagateZeroToCaller), PropArg(std::forward(PropagateParameter)), PropRet(std::forward(PropagateRet)), - FactConstructor(std::forward(FactConstructor)) {} + FactConstructor(std::forward(FactConstructor)), + PostProcess(std::forward(PostProcess)) {} Container computeTargets(D Source) override { Container Res; @@ -337,6 +338,8 @@ mapFactsToCaller(const llvm::CallBase *CallSite, } } + std::invoke(PostProcess, Res); + return Res; } @@ -346,13 +349,14 @@ mapFactsToCaller(const llvm::CallBase *CallSite, [[no_unique_address]] std::decay_t PropArg; [[no_unique_address]] std::decay_t PropRet; [[no_unique_address]] std::decay_t FactConstructor; + [[no_unique_address]] std::decay_t PostProcess; }; - return std::make_shared(CallSite, ExitInst, PropagateGlobals, - std::forward(PropagateParameter), - std::forward(PropagateRet), - std::forward(FactConstructor), - PropagateZeroToCaller); + return std::make_shared( + CallSite, ExitInst, PropagateGlobals, + std::forward(PropagateParameter), + std::forward(PropagateRet), std::forward(FactConstructor), + PropagateZeroToCaller, std::forward(PostProcess)); } //===----------------------------------------------------------------------===// diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h index 5e6d85ccf..6c58a032d 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -55,7 +55,8 @@ class IFDSTaintAnalysis */ IFDSTaintAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT, const LLVMTaintConfig *Config, - std::vector EntryPoints = {"main"}); + std::vector EntryPoints = {"main"}, + bool TaintMainArgs = true); ~IFDSTaintAnalysis() override = default; @@ -85,6 +86,7 @@ class IFDSTaintAnalysis private: const LLVMTaintConfig *Config{}; LLVMAliasInfoRef PT{}; + bool TaintMainArgs{}; bool isSourceCall(const llvm::CallBase *CB, const llvm::Function *Callee) const; diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 745cc4b42..77bcfa36a 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -257,6 +257,10 @@ template struct DefaultConstruct { } }; +struct IgnoreArgs { + template void operator()(U &&.../*Val*/) noexcept {} +}; + template void reserveIfPossible(T &Container, size_t Capacity) { if constexpr (detail::has_reserve::value) { Container.reserve(Capacity); diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index 890c357ad..c7b2b6f72 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -9,6 +9,8 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h" +#include "phasar/DataFlow/IfdsIde/EntryPointUtils.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" @@ -36,13 +38,16 @@ #include namespace psr { +using d_t = IFDSTaintAnalysis::d_t; +using container_type = IFDSTaintAnalysis::container_type; IFDSTaintAnalysis::IFDSTaintAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT, const LLVMTaintConfig *Config, - std::vector EntryPoints) + std::vector EntryPoints, + bool TaintMainArgs) : IFDSTabulationProblem(IRDB, std::move(EntryPoints), createZeroValue()), - Config(Config), PT(PT) { + Config(Config), PT(PT), TaintMainArgs(TaintMainArgs) { assert(Config != nullptr); assert(PT); } @@ -110,29 +115,58 @@ bool IFDSTaintAnalysis::isSanitizerCall(const llvm::CallBase * /*CB*/, [this](const auto &Arg) { return Config->isSanitizer(&Arg); }); } +static bool canSkipAtContext(const llvm::Value *Val, + const llvm::Instruction *Context) noexcept { + if (const auto *Inst = llvm::dyn_cast(Val)) { + /// Mapping instructions between functions is done via the call-FF and + /// ret-FF + if (Inst->getFunction() != Context->getFunction()) { + return true; + } + if (Inst->getParent() == Context->getParent() && + Context->comesBefore(Inst)) { + // We will see that inst later + return true; + } + return false; + } + + if (const auto *Arg = llvm::dyn_cast(Val)) { + // An argument is only valid in the function it belongs to + if (Arg->getParent() != Context->getFunction()) { + return true; + } + } + return false; +} + +static bool isCompiletimeConstantData(const llvm::Value *Val) noexcept { + if (const auto *Glob = llvm::dyn_cast(Val)) { + // Data cannot flow into the readonly-data section + return Glob->isConstant(); + } + + return llvm::isa(Val) || llvm::isa(Val); +} + void IFDSTaintAnalysis::populateWithMayAliases( container_type &Facts, const llvm::Instruction *Context) const { container_type Tmp = Facts; for (const auto *Fact : Facts) { auto Aliases = PT.getAliasSet(Fact); for (const auto *Alias : *Aliases) { - if (const auto *Inst = llvm::dyn_cast(Alias)) { - /// Mapping instructions between functions is done via the call-FF and - /// ret-FF - if (Inst->getFunction() != Context->getFunction()) { - continue; - } - if (Inst->getParent() == Context->getParent() && - Context->comesBefore(Inst)) { - // We will see that inst later - continue; - } - } else if (const auto *Glob = - llvm::dyn_cast(Alias)) { - if (Glob != Fact && Glob->isConstant()) { - // Data cannot flow into the readonly-data section - continue; - } + if (canSkipAtContext(Alias, Context)) { + continue; + } + + if (isCompiletimeConstantData(Alias)) { + continue; + } + + if (const auto *Load = llvm::dyn_cast(Alias)) { + // Handle at least one level of indirection... + const auto *PointerOp = Load->getPointerOperand()->stripPointerCasts(); + Tmp.insert(PointerOp); } Tmp.insert(Alias); @@ -148,6 +182,85 @@ void IFDSTaintAnalysis::populateWithMustAliases( /// may-aliases } +static IFDSTaintAnalysis::FlowFunctionPtrType transferAndKillFlow(d_t To, + d_t From) { + if (From->hasNUsesOrMore(2)) { + return FlowFunctionTemplates::transferFlow(To, From); + } + return FlowFunctionTemplates::lambdaFlow( + [To, From](d_t Source) -> container_type { + if (Source == From) { + return {To}; + } + if (Source == To) { + return {}; + } + return {Source}; + }); +} + +static IFDSTaintAnalysis::FlowFunctionPtrType +transferAndKillTwoFlows(d_t To, d_t From1, d_t From2) { + bool KillFrom1 = !From1->hasNUsesOrMore(2); + bool KillFrom2 = !From2->hasNUsesOrMore(2); + + if (KillFrom1) { + if (KillFrom2) { + return FlowFunctionTemplates::lambdaFlow( + [To, From1, From2](d_t Source) -> container_type { + if (Source == From1 || Source == From2) { + return {To}; + } + if (Source == To) { + return {}; + } + return {Source}; + }); + } + + return FlowFunctionTemplates::lambdaFlow( + [To, From1, From2](d_t Source) -> container_type { + if (Source == From1) { + return {To}; + } + if (Source == From2) { + return {Source, To}; + } + if (Source == To) { + return {}; + } + return {Source}; + }); + } + + if (KillFrom2) { + return FlowFunctionTemplates::lambdaFlow( + [To, From1, From2](d_t Source) -> container_type { + if (Source == From1) { + return {Source, To}; + } + if (Source == From2) { + return {To}; + } + if (Source == To) { + return {}; + } + return {Source}; + }); + } + + return FlowFunctionTemplates::lambdaFlow( + [To, From1, From2](d_t Source) -> container_type { + if (Source == From1 || Source == From2) { + return {Source, To}; + } + if (Source == To) { + return {}; + } + return {Source}; + }); +} + auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, [[maybe_unused]] n_t Succ) -> FlowFunctionPtrType { @@ -156,47 +269,40 @@ auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, container_type Gen; Gen.insert(Store->getPointerOperand()); populateWithMayAliases(Gen, Store); - Gen.insert(Store->getValueOperand()); + if (Store->getValueOperand()->hasNUsesOrMore(2)) { + Gen.insert(Store->getValueOperand()); + } return lambdaFlow( [Store, Gen{std::move(Gen)}](d_t Source) -> container_type { - if (Store->getValueOperand() == Source) { - return Gen; - } if (Store->getPointerOperand() == Source) { return {}; } + if (Store->getValueOperand() == Source) { + return Gen; + } + return {Source}; }); } // If a tainted value is loaded, the loaded value is of course tainted if (const auto *Load = llvm::dyn_cast(Curr)) { - return transferFlow(Load, Load->getPointerOperand()); + return transferAndKillFlow(Load, Load->getPointerOperand()); } // Check if an address is computed from a tainted base pointer of an // aggregated object if (const auto *GEP = llvm::dyn_cast(Curr)) { - return transferFlow(GEP, GEP->getPointerOperand()); + return transferAndKillFlow(GEP, GEP->getPointerOperand()); } // Check if a tainted value is extracted and taint the targets of // the extract operation accordingly if (const auto *Extract = llvm::dyn_cast(Curr)) { - return transferFlow(Extract, Extract->getAggregateOperand()); + return transferAndKillFlow(Extract, Extract->getAggregateOperand()); } if (const auto *Insert = llvm::dyn_cast(Curr)) { - return lambdaFlow([Insert](d_t Source) -> container_type { - if (Source == Insert->getAggregateOperand() || - Source == Insert->getInsertedValueOperand()) { - return {Source, Insert}; - } - - if (Source == Insert) { - return {}; - } - - return {Source}; - }); + return transferAndKillTwoFlows(Insert, Insert->getAggregateOperand(), + Insert->getInsertedValueOperand()); } if (const auto *Cast = llvm::dyn_cast(Curr)) { @@ -234,7 +340,11 @@ auto IFDSTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t /*CalleeFun*/, [](d_t Formal, d_t Source) { return Formal == Source && Formal->getType()->isPointerTy(); }, - [](d_t RetVal, d_t Source) { return RetVal == Source; }); + [](d_t RetVal, d_t Source) { return RetVal == Source; }, {}, true, true, + [this, CallSite](container_type &Res) { + // Correctly handling return-POIs + populateWithMayAliases(Res, CallSite); + }); // All other stuff is killed at this point } @@ -332,19 +442,24 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, auto IFDSTaintAnalysis::initialSeeds() -> InitialSeeds { PHASAR_LOG_LEVEL(DEBUG, "IFDSTaintAnalysis::initialSeeds()"); - // If main function is the entry point, commandline arguments have to be - // tainted. Otherwise we just use the zero value to initialize the analysis. + InitialSeeds Seeds; LLVMBasedCFG C; - forallStartingPoints(EntryPoints, IRDB, C, [this, &Seeds](n_t SP) { - Seeds.addSeed(SP, getZeroValue()); - if (SP->getFunction()->getName() == "main") { + addSeedsForStartingPoints(EntryPoints, IRDB, C, Seeds, getZeroValue(), + psr::BinaryDomain::BOTTOM); + + if (TaintMainArgs && llvm::is_contained(EntryPoints, "main")) { + // If main function is the entry point, commandline arguments have to be + // tainted. Otherwise we just use the zero value to initialize the analysis. + + const auto *MainF = IRDB->getFunction("main"); + for (const auto *SP : C.getStartPointsOf(MainF)) { for (const auto &Arg : SP->getFunction()->args()) { Seeds.addSeed(SP, &Arg); } } - }); + } return Seeds; } diff --git a/test/llvm_test_code/taint_analysis/CMakeLists.txt b/test/llvm_test_code/taint_analysis/CMakeLists.txt index 1571c8432..cbefe3382 100644 --- a/test/llvm_test_code/taint_analysis/CMakeLists.txt +++ b/test/llvm_test_code/taint_analysis/CMakeLists.txt @@ -33,6 +33,8 @@ set(NoMem2regSources struct_member.cpp dynamic_memory.cpp dynamic_memory_simple.cpp + double_free_01.c + double_free_02.c ) foreach(TEST_SRC ${NoMem2regSources}) diff --git a/test/llvm_test_code/taint_analysis/double_free_01.c b/test/llvm_test_code/taint_analysis/double_free_01.c new file mode 100644 index 000000000..9ef43c7db --- /dev/null +++ b/test/llvm_test_code/taint_analysis/double_free_01.c @@ -0,0 +1,7 @@ +#include + +int main() { + void *X = malloc(32); + free(X); + free(X); +} diff --git a/test/llvm_test_code/taint_analysis/double_free_02.c b/test/llvm_test_code/taint_analysis/double_free_02.c new file mode 100644 index 000000000..73d1d06ac --- /dev/null +++ b/test/llvm_test_code/taint_analysis/double_free_02.c @@ -0,0 +1,9 @@ +#include + +void doFree(void *P) { free(P); } + +int main() { + void *X = malloc(32); + doFree(X); + free(X); +} diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp index d5352abc9..0812fafcf 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp @@ -8,6 +8,7 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" #include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" +#include "phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "TestConfig.h" @@ -24,7 +25,7 @@ class IFDSTaintAnalysisTest : public ::testing::Test { protected: static constexpr auto PathToLlFiles = PHASAR_BUILD_SUBFOLDER("taint_analysis/"); - const std::vector EntryPoints = {"main"}; + static inline const std::vector EntryPoints = {"main"}; std::optional HA; @@ -34,42 +35,79 @@ class IFDSTaintAnalysisTest : public ::testing::Test { IFDSTaintAnalysisTest() = default; ~IFDSTaintAnalysisTest() override = default; + static LLVMTaintConfig getDefaultConfig() { + auto SourceCB = [](const llvm::Instruction *Inst) { + std::set Ret; + if (const auto *Call = llvm::dyn_cast(Inst); + Call && Call->getCalledFunction() && + Call->getCalledFunction()->getName() == "_Z6sourcev") { + Ret.insert(Call); + } + return Ret; + }; + auto SinkCB = [](const llvm::Instruction *Inst) { + std::set Ret; + if (const auto *Call = llvm::dyn_cast(Inst); + Call && Call->getCalledFunction() && + Call->getCalledFunction()->getName() == "_Z4sinki") { + assert(Call->arg_size() > 0); + Ret.insert(Call->getArgOperand(0)); + } + return Ret; + }; + return LLVMTaintConfig(std::move(SourceCB), std::move(SinkCB)); + } + + static LLVMTaintConfig getDoubleFreeConfig() { + auto SourceCB = [](const llvm::Instruction *Inst) { + std::set Ret; + if (const auto *Call = llvm::dyn_cast(Inst); + Call && Call->getCalledFunction() && + Call->getCalledFunction()->getName() == "free") { + Ret.insert(Call->getArgOperand(0)); + } + return Ret; + }; + + return LLVMTaintConfig(SourceCB, SourceCB); + } + void initialize(const llvm::Twine &IRFile) { HA.emplace(IRFile, EntryPoints); - LLVMTaintConfig::TaintDescriptionCallBackTy SourceCB = - [](const llvm::Instruction *Inst) { - std::set Ret; - if (const auto *Call = llvm::dyn_cast(Inst); - Call && Call->getCalledFunction() && - Call->getCalledFunction()->getName() == "_Z6sourcev") { - Ret.insert(Call); - } - return Ret; - }; - LLVMTaintConfig::TaintDescriptionCallBackTy SinkCB = - [](const llvm::Instruction *Inst) { - std::set Ret; - if (const auto *Call = llvm::dyn_cast(Inst); - Call && Call->getCalledFunction() && - Call->getCalledFunction()->getName() == "_Z4sinki") { - assert(Call->arg_size() > 0); - Ret.insert(Call->getArgOperand(0)); - } - return Ret; - }; - TSF.emplace(std::move(SourceCB), std::move(SinkCB)); + + if (!TSF) { + TSF = getDefaultConfig(); + } TaintProblem = createAnalysisProblem(*HA, &*TSF, EntryPoints); } - void SetUp() override { ValueAnnotationPass::resetValueID(); } + static void doAnalysis(const llvm::Twine &IRFile, + const LLVMTaintConfig &Config, + const map> &GroundTruth) { + HelperAnalyses HA(PathToLlFiles + IRFile, EntryPoints); + + auto TaintProblem = + createAnalysisProblem(HA, &Config, EntryPoints); - void TearDown() override {} + IFDSSolver TaintSolver(TaintProblem, &HA.getICFG()); + TaintSolver.solve(); - void compareResults(map> &GroundTruth) { - // std::map> Leaks; + TaintSolver.dumpResults(); + + compare(TaintProblem.Leaks, GroundTruth); + } + + static void doAnalysis(const llvm::Twine &IRFile, + const map> &GroundTruth) { + doAnalysis(IRFile, getDefaultConfig(), GroundTruth); + } + + template + static void compare(const LeaksTy &Leaks, + const map> &GroundTruth) { map> FoundLeaks; - for (const auto &Leak : TaintProblem->Leaks) { + for (const auto &Leak : Leaks) { int SinkId = stoi(getMetaDataID(Leak.first)); set LeakedValueIds; for (const auto *LV : Leak.second) { @@ -79,6 +117,10 @@ class IFDSTaintAnalysisTest : public ::testing::Test { } EXPECT_EQ(FoundLeaks, GroundTruth); } + + void compareResults(const map> &GroundTruth) noexcept { + compare(TaintProblem->Leaks, GroundTruth); + } }; // Test Fixture TEST_F(IFDSTaintAnalysisTest, TaintTest_01) { @@ -257,6 +299,20 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_10) { compareResults(GroundTruth); } +TEST_F(IFDSTaintAnalysisTest, TaintTest_DoubleFree_01) { + doAnalysis("double_free_01_c.ll", getDoubleFreeConfig(), + { + {6, {"5"}}, + }); +} + +TEST_F(IFDSTaintAnalysisTest, TaintTest_DoubleFree_02) { + doAnalysis("double_free_02_c.ll", getDoubleFreeConfig(), + { + {11, {"10"}}, + }); +} + int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); return RUN_ALL_TESTS(); From 06da95b2905bb3b8ba1db24337145e969ef7b9f0 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:58:36 +0200 Subject: [PATCH 34/59] HelperAnalyses with existing Module (#667) * Allow creating a HelperAnalyses object from an already existing LLVM Module * minor API extension of ProjectIRDB --- .../phasar/PhasarLLVM/DB/LLVMProjectIRDB.h | 21 +++-- include/phasar/PhasarLLVM/HelperAnalyses.h | 10 ++ .../phasar/PhasarLLVM/HelperAnalysisConfig.h | 3 + lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp | 92 +++++++++++-------- lib/PhasarLLVM/HelperAnalyses.cpp | 14 +++ 5 files changed, 95 insertions(+), 45 deletions(-) diff --git a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h index 51285ef8e..590ffafa6 100644 --- a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h +++ b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h @@ -41,19 +41,23 @@ class LLVMProjectIRDB : public ProjectIRDBBase { friend ProjectIRDBBase; public: - /// Reads and parses the given LLVM IR file and owns the resulting IR Module + /// Reads and parses the given LLVM IR file and owns the resulting IR Module. + /// If an error occurs, an error message is written to stderr and subsequent + /// calls to isValid() return false. explicit LLVMProjectIRDB(const llvm::Twine &IRFileName); /// Initializes the new ProjectIRDB with the given IR Module _without_ taking - /// ownership. The module is not being preprocessed. + /// ownership. The module is optionally being preprocessed. /// /// CAUTION: Do not manage the same LLVM Module with multiple LLVMProjectIRDB /// instances at the same time! This will confuse the ModulesToSlotTracker - explicit LLVMProjectIRDB(llvm::Module *Mod); + explicit LLVMProjectIRDB(llvm::Module *Mod, bool DoPreprocessing = true); /// Initializes the new ProjectIRDB with the given IR Module and takes - /// ownership of it + /// ownership of it. The module is optionally being preprocessed. explicit LLVMProjectIRDB(std::unique_ptr Mod, bool DoPreprocessing = true); - /// Parses the given LLVM IR file and owns the resulting IR Module + /// Parses the given LLVM IR file and owns the resulting IR Module. + /// If an error occurs, an error message is written to stderr and subsequent + /// calls to isValid() return false. explicit LLVMProjectIRDB(llvm::MemoryBufferRef Buf); LLVMProjectIRDB(const LLVMProjectIRDB &) = delete; @@ -64,6 +68,9 @@ class LLVMProjectIRDB : public ProjectIRDBBase { [[nodiscard]] static std::unique_ptr getParsedIRModuleOrNull(const llvm::Twine &IRFileName, llvm::LLVMContext &Ctx) noexcept; + [[nodiscard]] static std::unique_ptr + getParsedIRModuleOrNull(llvm::MemoryBufferRef IRFileContent, + llvm::LLVMContext &Ctx) noexcept; /// Also use the const overload using ProjectIRDBBase::getFunction; @@ -81,7 +88,7 @@ class LLVMProjectIRDB : public ProjectIRDBBase { /// Also use the const overload using ProjectIRDBBase::getModule; /// Non-const overload - [[nodiscard]] llvm::Module *getModule() { return Mod.get(); } + [[nodiscard]] llvm::Module *getModule() noexcept { return Mod.get(); } /// Similar to getInstruction(size_t), but is also able to return global /// variables by id @@ -96,6 +103,8 @@ class LLVMProjectIRDB : public ProjectIRDBBase { /// called twice for the same function. Use with care! void insertFunction(llvm::Function *F, bool DoPreprocessing = true); + explicit operator bool() const noexcept { return isValid(); } + private: [[nodiscard]] m_t getModuleImpl() const noexcept { return Mod.get(); } [[nodiscard]] bool debugInfoAvailableImpl() const; diff --git a/include/phasar/PhasarLLVM/HelperAnalyses.h b/include/phasar/PhasarLLVM/HelperAnalyses.h index 39a06ddf9..f8cb8029b 100644 --- a/include/phasar/PhasarLLVM/HelperAnalyses.h +++ b/include/phasar/PhasarLLVM/HelperAnalyses.h @@ -20,6 +20,10 @@ #include #include +namespace llvm { +class Module; +} // namespace llvm + namespace psr { class LLVMProjectIRDB; class LLVMTypeHierarchy; @@ -46,6 +50,12 @@ class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) explicit HelperAnalyses(const char *IRFile, std::vector EntryPoints, HelperAnalysisConfig Config = {}); + explicit HelperAnalyses(llvm::Module *IRModule, + std::vector EntryPoints, + HelperAnalysisConfig Config = {}); + explicit HelperAnalyses(std::unique_ptr IRModule, + std::vector EntryPoints, + HelperAnalysisConfig Config = {}); ~HelperAnalyses() noexcept; [[nodiscard]] LLVMProjectIRDB &getProjectIRDB(); diff --git a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h index 4fbd87c62..df59c41c5 100644 --- a/include/phasar/PhasarLLVM/HelperAnalysisConfig.h +++ b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h @@ -27,6 +27,9 @@ struct HelperAnalysisConfig { Soundness SoundnessLevel = Soundness::Soundy; bool AutoGlobalSupport = true; bool AllowLazyPTS = true; + /// Preprocess a ProjectIRDB even if it gets constructed by an already + /// existing llvm::Module + bool PreprocessExistingModule = true; HelperAnalysisConfig &&withCGType(CallGraphAnalysisType CGTy) &&noexcept { this->CGTy = CGTy; diff --git a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp index c498c2c91..d4632d49f 100644 --- a/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp +++ b/lib/PhasarLLVM/DB/LLVMProjectIRDB.cpp @@ -13,15 +13,57 @@ #include "llvm/IRReader/IRReader.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/SourceMgr.h" #include namespace psr { +std::unique_ptr +LLVMProjectIRDB::getParsedIRModuleOrNull(llvm::MemoryBufferRef IRFileContent, + llvm::LLVMContext &Ctx) noexcept { + + llvm::SMDiagnostic Diag; + std::unique_ptr M = llvm::parseIR(IRFileContent, Diag, Ctx); + bool BrokenDebugInfo = false; + if (M == nullptr) { + Diag.print(nullptr, llvm::errs()); + return nullptr; + } + /* Crash in presence of llvm-3.9.1 module (segfault) */ + if (M == nullptr || llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) { + PHASAR_LOG_LEVEL(ERROR, IRFileContent.getBufferIdentifier() + << " could not be parsed correctly!"); + return nullptr; + } + if (BrokenDebugInfo) { + PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!"); + } + return M; +} + +std::unique_ptr +LLVMProjectIRDB::getParsedIRModuleOrNull(const llvm::Twine &IRFileName, + llvm::LLVMContext &Ctx) noexcept { + // Look at LLVM's IRReader.cpp for reference + + auto FileOrErr = + llvm::MemoryBuffer::getFileOrSTDIN(IRFileName, /*IsText=*/true); + if (std::error_code EC = FileOrErr.getError()) { + llvm::SmallString<128> Buf; + auto Err = llvm::SMDiagnostic(IRFileName.toStringRef(Buf), + llvm::SourceMgr::DK_Error, + "Could not open input file: " + EC.message()); + Err.print(nullptr, llvm::errs()); + return nullptr; + } + return getParsedIRModuleOrNull(*FileOrErr.get(), Ctx); +} + LLVMProjectIRDB::LLVMProjectIRDB(const llvm::Twine &IRFileName) { - std::unique_ptr M = getParsedIRModuleOrNull(IRFileName, Ctx); + auto M = getParsedIRModuleOrNull(IRFileName, Ctx); if (!M) { return; @@ -87,10 +129,16 @@ void LLVMProjectIRDB::preprocessModule(llvm::Module *NonConstMod) { assert(InstToId.size() == IdToInst.size()); } -LLVMProjectIRDB::LLVMProjectIRDB(llvm::Module *Mod) : Mod(Mod) { +LLVMProjectIRDB::LLVMProjectIRDB(llvm::Module *Mod, bool DoPreprocessing) + : Mod(Mod) { assert(Mod != nullptr); ModulesToSlotTracker::setMSTForModule(Mod); - initInstructionIds(); + + if (DoPreprocessing) { + preprocessModule(Mod); + } else { + initInstructionIds(); + } } LLVMProjectIRDB::LLVMProjectIRDB(std::unique_ptr Mod, @@ -109,21 +157,10 @@ LLVMProjectIRDB::LLVMProjectIRDB(std::unique_ptr Mod, LLVMProjectIRDB::LLVMProjectIRDB(llvm::MemoryBufferRef Buf) { llvm::SMDiagnostic Diag; - std::unique_ptr M = llvm::parseIR(Buf, Diag, Ctx); - bool BrokenDebugInfo = false; - if (M == nullptr) { - Diag.print(nullptr, llvm::errs()); - return; - } - - if (llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) { - PHASAR_LOG_LEVEL(ERROR, Buf.getBufferIdentifier() - << " could not be parsed correctly!"); + auto M = getParsedIRModuleOrNull(Buf, Ctx); + if (!M) { return; } - if (BrokenDebugInfo) { - PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!"); - } auto *NonConst = M.get(); Mod = std::move(M); @@ -137,29 +174,6 @@ LLVMProjectIRDB::~LLVMProjectIRDB() { } } -std::unique_ptr -LLVMProjectIRDB::getParsedIRModuleOrNull(const llvm::Twine &IRFileName, - llvm::LLVMContext &Ctx) noexcept { - llvm::SMDiagnostic Diag; - llvm::SmallString<256> Buf; - std::unique_ptr M = - llvm::parseIRFile(IRFileName.toStringRef(Buf), Diag, Ctx); - bool BrokenDebugInfo = false; - if (M == nullptr) { - Diag.print(nullptr, llvm::errs()); - return nullptr; - } - /* Crash in presence of llvm-3.9.1 module (segfault) */ - if (M == nullptr || llvm::verifyModule(*M, &llvm::errs(), &BrokenDebugInfo)) { - PHASAR_LOG_LEVEL(ERROR, IRFileName << " could not be parsed correctly!"); - return nullptr; - } - if (BrokenDebugInfo) { - PHASAR_LOG_LEVEL(WARNING, "Debug info is broken!"); - } - return M; -} - static llvm::Function * internalGetFunctionDefinition(const llvm::Module &M, llvm::StringRef FunctionName) { diff --git a/lib/PhasarLLVM/HelperAnalyses.cpp b/lib/PhasarLLVM/HelperAnalyses.cpp index e0d13925e..815f9d887 100644 --- a/lib/PhasarLLVM/HelperAnalyses.cpp +++ b/lib/PhasarLLVM/HelperAnalyses.cpp @@ -43,6 +43,20 @@ HelperAnalyses::HelperAnalyses(const char *IRFile, HelperAnalysisConfig Config) : HelperAnalyses(std::string(IRFile), std::move(EntryPoints), std::move(Config)) {} +HelperAnalyses::HelperAnalyses(llvm::Module *IRModule, + std::vector EntryPoints, + HelperAnalysisConfig Config) + : HelperAnalyses(std::string(), std::move(EntryPoints), std::move(Config)) { + this->IRDB = std::make_unique( + IRModule, Config.PreprocessExistingModule); +} +HelperAnalyses::HelperAnalyses(std::unique_ptr IRModule, + std::vector EntryPoints, + HelperAnalysisConfig Config) + : HelperAnalyses(std::string(), std::move(EntryPoints), std::move(Config)) { + this->IRDB = std::make_unique( + std::move(IRModule), Config.PreprocessExistingModule); +} HelperAnalyses::~HelperAnalyses() noexcept = default; From 82a89f605530b23f84659c297e8d0f9b00a1dc22 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:29:02 +0200 Subject: [PATCH 35/59] Pin swift version (#671) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e4c32f0b..ccf529334 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,6 +55,8 @@ jobs: libclang-rt-14-dev - uses: swift-actions/setup-swift@v1 + with: + swift-version: "5.8.1" - name: Building Phasar in ${{ matrix.build }} with ${{ matrix.compiler[0] }} env: BUILD_TYPE: ${{ matrix.build }} From de6d50500f4958fbbafec3daba95f3d4a15ea85d Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:30:28 +0200 Subject: [PATCH 36/59] TaintConfig Serialization (#672) * LLVMTaintConfigYAML class * basic structure * beginning of restructuring * compiles, untested * Constructor init * minor bug fixes * new start w better approach * basic working version * removed unneccesary includes and functions * new TaintConfigData structure * fully refactored, doesn't compile * added func/var structs * compiling version, tests fail * only 3 unittests fail now * fixed a bug with sink values causing a crash * all unittests pass * review fixes * one faulty unittest remaining * all unittests pass + myphasartool revert * pre-commit stuff * review changes + unittest fixed * added static to handle functions * cleanup * minor * Pin swift version * Remove unnecessary forward declaration --------- Co-authored-by: mxHuber --- .../PhasarLLVM/TaintConfig/LLVMTaintConfig.h | 5 +- .../PhasarLLVM/TaintConfig/TaintConfigBase.h | 10 +- .../PhasarLLVM/TaintConfig/TaintConfigData.h | 46 ++++ .../TaintConfig/LLVMTaintConfig.cpp | 197 ++++++++---------- .../TaintConfig/TaintConfigBase.cpp | 184 +++++++++++++--- .../Problems/IDEExtendedTaintAnalysisTest.cpp | 49 ++--- .../TaintConfig/TaintConfigTest.cpp | 27 ++- 7 files changed, 323 insertions(+), 195 deletions(-) create mode 100644 include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h diff --git a/include/phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h b/include/phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h index 04c11650f..31115da09 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h +++ b/include/phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h @@ -19,6 +19,7 @@ namespace psr { class LLVMTaintConfig; class LLVMProjectIRDB; +struct TaintConfigData; template <> struct TaintConfigTraits { using n_t = const llvm::Instruction *; @@ -31,7 +32,7 @@ class LLVMTaintConfig : public TaintConfigBase { public: explicit LLVMTaintConfig(const psr::LLVMProjectIRDB &Code, - const nlohmann::json &Config); + const psr::TaintConfigData &Config); explicit LLVMTaintConfig(const psr::LLVMProjectIRDB &AnnotatedCode); explicit LLVMTaintConfig( TaintDescriptionCallBackTy SourceCB, TaintDescriptionCallBackTy SinkCB, @@ -93,7 +94,7 @@ class LLVMTaintConfig : public TaintConfigBase { // --- utilities void addAllFunctions(const LLVMProjectIRDB &IRDB, - const nlohmann::json &Config); + const TaintConfigData &Config); // --- data members diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h index 94979d2af..422a06a5b 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h @@ -10,6 +10,7 @@ #ifndef PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGBASE_H #define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGBASE_H +#include "phasar/PhasarLLVM/TaintConfig/TaintConfigData.h" #include "phasar/Utils/Nullable.h" #include "llvm/ADT/FunctionExtras.h" @@ -17,8 +18,6 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" -#include "nlohmann/json.hpp" - #include #include #include @@ -26,7 +25,7 @@ namespace psr { -enum class TaintCategory { Source, Sink, Sanitizer, None }; +enum class TaintCategory { None, Source, Sink, Sanitizer }; [[nodiscard]] llvm::StringRef to_string(TaintCategory Cat) noexcept; [[nodiscard]] TaintCategory toTaintCategory(llvm::StringRef Str) noexcept; @@ -159,8 +158,9 @@ template class TaintConfigBase { //===----------------------------------------------------------------------===// // Miscellaneous helper functions -nlohmann::json parseTaintConfig(const llvm::Twine &Path); -std::optional parseTaintConfigOrNull(const llvm::Twine &Path); +[[nodiscard]] TaintConfigData parseTaintConfig(const llvm::Twine &Path); +[[nodiscard]] std::optional +parseTaintConfigOrNull(const llvm::Twine &Path) noexcept; } // namespace psr diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h new file mode 100644 index 000000000..99a3896f8 --- /dev/null +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Maximilian Leo Huber and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGDATA_H +#define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGDATA_H + +#include +#include + +namespace psr { +enum class TaintCategory; + +struct FunctionData { + FunctionData() noexcept = default; + + std::string Name; + TaintCategory ReturnCat{}; + std::vector SourceValues; + std::vector SinkValues; + std::vector SanitizerValues; + bool HasAllSinkParam = false; +}; + +struct VariableData { + VariableData() noexcept = default; + + size_t Line{}; + std::string Name; + std::string Scope; + TaintCategory Cat{}; +}; + +struct TaintConfigData { + std::vector Functions; + std::vector Variables; +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGDATA_H diff --git a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp index 06958f7ed..a448f43f1 100644 --- a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp +++ b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp @@ -15,13 +15,14 @@ #include "phasar/PhasarLLVM/Utils/Annotation.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" -#include "phasar/Utils/NlohmannLogging.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/IntrinsicInst.h" +#include + namespace psr { static llvm::SmallVector @@ -59,9 +60,9 @@ findAllFunctionDefs(const LLVMProjectIRDB &IRDB, llvm::StringRef Name) { } void LLVMTaintConfig::addAllFunctions(const LLVMProjectIRDB &IRDB, - const nlohmann::json &Config) { - for (const auto &FunDesc : Config["functions"]) { - auto Name = FunDesc["name"].get(); + const TaintConfigData &Config) { + for (const auto &FunDesc : Config.Functions) { + const auto &Name = FunDesc.Name; auto FnDefs = findAllFunctionDefs(IRDB, Name); @@ -72,127 +73,105 @@ void LLVMTaintConfig::addAllFunctions(const LLVMProjectIRDB &IRDB, const auto *Fun = FnDefs[0]; - // handle a function's parameters - if (FunDesc.contains("params")) { - auto Params = FunDesc["params"]; - if (Params.contains("source")) { - for (unsigned Idx : Params["source"]) { - if (Idx >= Fun->arg_size()) { - llvm::errs() - << "ERROR: The source-function parameter index is out of " - "bounds: " - << Idx << "\n"; - // Use 'continue' instead of 'break' to get error messages for the - // remaining parameters as well - continue; - } - addTaintCategory(Fun->getArg(Idx), TaintCategory::Source); - } + // handle a function's source parameters + for (const auto &Idx : FunDesc.SourceValues) { + if (Idx >= Fun->arg_size()) { + llvm::errs() << "ERROR: The source-function parameter index is out of " + "bounds: " + << Idx << "\n"; + // Use 'continue' instead of 'break' to get error messages for the + // remaining parameters as well + continue; } - if (Params.contains("sink")) { - for (const auto &Idx : Params["sink"]) { - if (Idx.is_number()) { - if (Idx >= Fun->arg_size()) { - llvm::errs() - << "ERROR: The source-function parameter index is out of " - "bounds: " - << Idx << "\n"; - continue; - } - addTaintCategory(Fun->getArg(Idx), TaintCategory::Sink); - } else if (Idx.is_string()) { - const auto Sinks = Idx.get(); - if (Sinks == "all") { - for (const auto &Arg : Fun->args()) { - addTaintCategory(&Arg, TaintCategory::Sink); - } - } - } - } + + addTaintCategory(Fun->getArg(Idx), TaintCategory::Source); + } + for (const auto &Idx : FunDesc.SinkValues) { + if (Idx >= Fun->arg_size()) { + llvm::errs() << "ERROR: The sink-function parameter index is out of " + "bounds: " + << Idx << "\n"; + continue; } - if (Params.contains("sanitizer")) { - for (unsigned Idx : Params["sanitizer"]) { - if (Idx >= Fun->arg_size()) { - llvm::errs() - << "ERROR: The source-function parameter index is out of " - "bounds: " - << Idx << "\n"; - continue; - } - addTaintCategory(Fun->getArg(Idx), TaintCategory::Sanitizer); - } + + addTaintCategory(Fun->getArg(Idx), TaintCategory::Sink); + } + + if (FunDesc.HasAllSinkParam) { + for (const auto &Arg : Fun->args()) { + addTaintCategory(&Arg, TaintCategory::Sink); } } - // handle a function's return value - if (FunDesc.contains("ret")) { - for (const auto &User : Fun->users()) { - addTaintCategory(User, FunDesc["ret"].get()); + + for (const auto &Idx : FunDesc.SanitizerValues) { + if (Idx >= Fun->arg_size()) { + llvm::errs() + << "ERROR: The sanitizer-function parameter index is out of " + "bounds: " + << Idx << "\n"; + continue; } + addTaintCategory(Fun->getArg(Idx), TaintCategory::Sanitizer); + } + // handle a function's return value + for (const auto &User : Fun->users()) { + addTaintCategory(User, FunDesc.ReturnCat); } } } LLVMTaintConfig::LLVMTaintConfig(const psr::LLVMProjectIRDB &Code, - const nlohmann::json &Config) { + const TaintConfigData &Config) { // handle functions - if (Config.contains("functions")) { - addAllFunctions(Code, Config); - } + addAllFunctions(Code, Config); // handle variables - if (Config.contains("variables")) { - // scope can be a function name or a struct. - std::unordered_map - StructConfigMap; - - // read all struct types from config - for (const auto &VarDesc : Config["variables"]) { - llvm::DebugInfoFinder DIF; - const auto *M = Code.getModule(); - - DIF.processModule(*M); - for (const auto &Ty : DIF.types()) { - if (Ty->getTag() == llvm::dwarf::DW_TAG_structure_type && - Ty->getName().equals(VarDesc["scope"].get())) { - for (const auto &LlvmStructTy : M->getIdentifiedStructTypes()) { - StructConfigMap.insert( - std::pair( - LlvmStructTy, VarDesc)); - } + // scope can be a function name or a struct. + std::unordered_map StructConfigMap; + + // read all struct types from config + size_t Counter = 0; + for (const auto &VarDesc : Config.Variables) { + llvm::DebugInfoFinder DIF; + const auto *M = Code.getModule(); + + DIF.processModule(*M); + for (const auto &Ty : DIF.types()) { + if (Ty->getTag() == llvm::dwarf::DW_TAG_structure_type && + Ty->getName().equals(VarDesc.Scope)) { + for (const auto &LlvmStructTy : M->getIdentifiedStructTypes()) { + StructConfigMap.insert( + std::pair(LlvmStructTy, + VarDesc.Name)); } } - DIF.reset(); } - - // add corresponding Allocas or getElementPtr instructions to the taint - // category - for (const auto &VarDesc : Config["variables"]) { - for (const auto &Fun : Code.getAllFunctions()) { - for (const auto &I : llvm::instructions(Fun)) { - if (const auto *DbgDeclare = - llvm::dyn_cast(&I)) { - const llvm::DILocalVariable *LocalVar = DbgDeclare->getVariable(); - // matching line number with for Allocas - if (LocalVar->getName().equals( - VarDesc["name"].get()) && - LocalVar->getLine() == VarDesc["line"].get()) { - addTaintCategory(DbgDeclare->getAddress(), - VarDesc["cat"].get()); - } - } else if (!StructConfigMap.empty()) { - // Ignorning line numbers for getElementPtr instructions - if (const auto *Gep = llvm::dyn_cast(&I)) { - const auto *StType = llvm::dyn_cast( - Gep->getPointerOperandType()->getPointerElementType()); - if (StType && StructConfigMap.count(StType)) { - const auto VarDesc = StructConfigMap.at(StType); - auto VarName = VarDesc["name"].get(); - // using substr to cover the edge case in which same variable - // name is present as a local variable and also as a struct - // member variable. (Ex. JsonConfig/fun_member_02.cpp) - if (Gep->getName().substr(0, VarName.size()).equals(VarName)) { - addTaintCategory(Gep, VarDesc["cat"].get()); - } + DIF.reset(); + } + // add corresponding Allocas or getElementPtr instructions to the taint + // category + for (const auto &VarDesc : Config.Variables) { + for (const auto &Fun : Code.getAllFunctions()) { + for (const auto &I : llvm::instructions(Fun)) { + if (const auto *DbgDeclare = llvm::dyn_cast(&I)) { + const llvm::DILocalVariable *LocalVar = DbgDeclare->getVariable(); + // matching line number with for Allocas + if (LocalVar->getName().equals(VarDesc.Name) && + LocalVar->getLine() == VarDesc.Line) { + addTaintCategory(DbgDeclare->getAddress(), VarDesc.Cat); + } + } else if (!StructConfigMap.empty()) { + // Ignorning line numbers for getElementPtr instructions + if (const auto *Gep = llvm::dyn_cast(&I)) { + const auto *StType = llvm::dyn_cast( + Gep->getPointerOperandType()->getPointerElementType()); + if (StType && StructConfigMap.count(StType)) { + auto VarName = StructConfigMap.at(StType); + // using substr to cover the edge case in which same variable + // name is present as a local variable and also as a struct + // member variable. (Ex. JsonConfig/fun_member_02.cpp) + if (Gep->getName().substr(0, VarName.size()).equals(VarName)) { + addTaintCategory(Gep, VarDesc.Cat); } } } diff --git a/lib/PhasarLLVM/TaintConfig/TaintConfigBase.cpp b/lib/PhasarLLVM/TaintConfig/TaintConfigBase.cpp index 34e2d2556..d654495d0 100644 --- a/lib/PhasarLLVM/TaintConfig/TaintConfigBase.cpp +++ b/lib/PhasarLLVM/TaintConfig/TaintConfigBase.cpp @@ -1,5 +1,6 @@ #include "phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h" +#include "phasar/PhasarLLVM/TaintConfig/TaintConfigData.h" #include "phasar/Utils/IO.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/NlohmannLogging.h" @@ -11,6 +12,7 @@ #include "nlohmann/json.hpp" #include +#include llvm::StringRef psr::to_string(TaintCategory Cat) noexcept { switch (Cat) { @@ -34,46 +36,160 @@ psr::TaintCategory psr::toTaintCategory(llvm::StringRef Str) noexcept { .Default(TaintCategory::None); } -nlohmann::json psr::parseTaintConfig(const llvm::Twine &Path) { - auto Ret = parseTaintConfigOrNull(Path); - if (!Ret) { - return {}; +static std::optional loadFunc(const nlohmann::json &Func) { + std::optional Data; + Data.emplace(); + bool FunctionNonEmpty = false; + + if (auto NameIt = Func.find("name"); NameIt != Func.end()) { + Data->Name = NameIt->get(); + FunctionNonEmpty = true; + } + + if (auto RetIt = Func.find("ret"); RetIt != Func.end()) { + Data->ReturnCat = psr::toTaintCategory(RetIt->get()); + if (Data->ReturnCat == psr::TaintCategory::None) { + throw std::runtime_error( + "Invalid taint category: '" + RetIt->get() + + "'; Must be one of 'source', 'sink' or 'sanitizer'"); + } + FunctionNonEmpty = true; + } + + auto ParamsIt = Func.find("params"); + if (ParamsIt != Func.end()) { + const auto &Params = *ParamsIt; + if (auto SrcIt = Params.find("source"); SrcIt != Params.end()) { + for (const auto &Curr : *SrcIt) { + Data->SourceValues.push_back(Curr.get()); + FunctionNonEmpty = true; + } + } + + if (auto SinkIt = Params.find("sink"); SinkIt != Params.end()) { + for (const auto &Curr : Func["params"]["sink"]) { + if (Curr.is_number()) { + Data->SinkValues.push_back(Curr.get()); + } else if (Curr == "all") { + Data->HasAllSinkParam = true; + } else { + throw std::runtime_error("[TaintConfigData::TaintConfigData()]: " + "Unknown sink string parameter!"); + } + FunctionNonEmpty = true; + } + } + + if (auto SanIt = Params.find("sanitizer"); SanIt != Params.end()) { + for (const auto &Curr : *SanIt) { + Data->SanitizerValues.push_back(Curr.get()); + FunctionNonEmpty = true; + } + } } - return std::move(*Ret); + + if (!FunctionNonEmpty) { + Data.reset(); + } + + return Data; } -std::optional -psr::parseTaintConfigOrNull(const llvm::Twine &Path) { - std::optional TaintConfig = readJsonFile(Path); - nlohmann::json_schema::json_validator Validator; - try { - static const nlohmann::json TaintConfigSchema = -#include "../config/TaintConfigSchema.json" - ; +static std::optional loadVar(const nlohmann::json &Var) { + std::optional Data; + Data.emplace(); - Validator.set_root_schema(TaintConfigSchema); // insert root-schema - } catch (const std::exception &E) { - PHASAR_LOG_LEVEL(ERROR, - "Validation of schema failed, here is why: " << E.what()); - return std::nullopt; + bool VarNonEmpty = false; + if (auto LineIt = Var.find("line"); LineIt != Var.end()) { + Data->Line = LineIt->get(); + VarNonEmpty = true; + } + + if (auto NameIt = Var.find("name"); NameIt != Var.end()) { + Data->Name = NameIt->get(); + VarNonEmpty = true; } - // a custom error handler - class CustomJsonErrorHandler - : public nlohmann::json_schema::basic_error_handler { - void error(const nlohmann::json::json_pointer &Pointer, - const nlohmann::json &Instance, - const std::string &Message) override { - nlohmann::json_schema::basic_error_handler::error(Pointer, Instance, - Message); - PHASAR_LOG_LEVEL(ERROR, Pointer.to_string() - << "' - '" << Instance << "': " << Message); + if (auto ScopeIt = Var.find("scope"); ScopeIt != Var.end()) { + Data->Scope = ScopeIt->get(); + VarNonEmpty = true; + } + + if (auto CatIt = Var.find("cat"); CatIt != Var.end()) { + Data->Cat = psr::toTaintCategory(CatIt->get()); + if (Data->Cat == psr::TaintCategory::None) { + throw std::runtime_error( + "Invalid taint category: '" + CatIt->get() + + "'; Must be one of 'source', 'sink' or 'sanitizer'"); } - }; - CustomJsonErrorHandler Err; - Validator.validate(*TaintConfig, Err); - if (Err) { - TaintConfig.reset(); + VarNonEmpty = true; + } + + if (!VarNonEmpty) { + Data.reset(); + } + + return Data; +} + +static void loadFunctions(const nlohmann::json &JSON, + std::vector &Into) { + auto It = JSON.find("functions"); + if (It == JSON.end()) { + return; + } + + for (const auto &Func : *It) { + if (auto FuncData = loadFunc(Func)) { + Into.push_back(std::move(*FuncData)); + } + } +} + +static void loadVariables(const nlohmann::json &JSON, + std::vector &Into) { + + auto It = JSON.find("variables"); + if (It == JSON.end()) { + return; + } + + for (const auto &Var : *It) { + if (auto VarData = loadVar(Var)) { + Into.push_back(std::move(*VarData)); + } + } +} + +psr::TaintConfigData psr::parseTaintConfig(const llvm::Twine &Path) { + static const nlohmann::json TaintConfigSchema = +#include "../config/TaintConfigSchema.json" + ; + + std::optional TaintConfig = readJsonFile(Path); + nlohmann::json_schema::json_validator Validator; + + Validator.set_root_schema(TaintConfigSchema); + Validator.validate(*TaintConfig); + + nlohmann::json Config = *TaintConfig; + + TaintConfigData Data{}; + loadFunctions(Config, Data.Functions); + loadVariables(Config, Data.Variables); + + return Data; +} + +std::optional +psr::parseTaintConfigOrNull(const llvm::Twine &Path) noexcept { + try { + return parseTaintConfig(Path); + } catch (std::exception &Exc) { + PHASAR_LOG_LEVEL(ERROR, "parseTaintConfig failed: " << Exc.what()); + return std::nullopt; + } catch (...) { + PHASAR_LOG_LEVEL(ERROR, "parseTaintConfig failed with unknown error"); + return std::nullopt; } - return TaintConfig; } diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp index 8f942e762..806cb58e2 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysisTest.cpp @@ -16,6 +16,7 @@ #include "phasar/PhasarLLVM/Passes/ValueAnnotationPass.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/Utils/DebugOutput.h" #include "phasar/Utils/Utilities.h" @@ -53,18 +54,18 @@ class IDETaintAnalysisTest : public ::testing::Test { IDETaintAnalysisTest() = default; ~IDETaintAnalysisTest() override = default; - void doAnalysis(const llvm::Twine &IRFile, - const map> &GroundTruth, - std::variant Config, - bool DumpResults = false) { + void doAnalysis( + const llvm::Twine &IRFile, const map> &GroundTruth, + std::variant Config, + bool DumpResults = false) { HelperAnalyses HA(IRFile, EntryPoints); auto TC = std::visit(Overloaded{[&](std::monostate) { return LLVMTaintConfig(HA.getProjectIRDB()); }, - [&](json *JS) { - auto Ret = + [&](TaintConfigData *JS) { + LLVMTaintConfig Ret = LLVMTaintConfig(HA.getProjectIRDB(), *JS); if (DumpResults) { llvm::errs() << Ret << "\n"; @@ -120,30 +121,18 @@ TEST_F(IDETaintAnalysisTest, XTaint01_Json) { Gt[7] = {"6"}; - json Config = R"!({ - "name": "XTaintTest", - "version": 1.0, - "functions": [ - { - "file": "xtaint01.cpp", - "name": "main", - "params": { - "source": [ - 0 - ] - } - }, - { - "file": "xtaint01.cpp", - "name": "_Z5printi", - "params": { - "sink": [ - 0 - ] - } - } - ] - })!"_json; + TaintConfigData Config; + + FunctionData FuncDataMain; + FuncDataMain.Name = "main"; + FuncDataMain.SourceValues.push_back(0); + + FunctionData FuncDataPrint; + FuncDataPrint.Name = "_Z5printi"; + FuncDataPrint.SinkValues.push_back(0); + + Config.Functions.push_back(std::move(FuncDataMain)); + Config.Functions.push_back(std::move(FuncDataPrint)); doAnalysis({PathToLLFiles + "xtaint01_json_cpp_dbg.ll"}, Gt, &Config); } diff --git a/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp b/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp index 530c74838..bc722d66e 100644 --- a/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp +++ b/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp @@ -40,7 +40,6 @@ TEST_F(TaintConfigTest, Array_01) { const std::string File = "array_01_c_dbg.ll"; psr::LLVMProjectIRDB IR({PathToAttrTaintConfigTestCode + File}); psr::LLVMTaintConfig Config(IR); - llvm::outs() << Config << '\n'; const llvm::Value *I = IR.getInstruction(5); ASSERT_TRUE(Config.isSource(I)); } @@ -229,12 +228,15 @@ static constexpr auto PathToJsonTaintConfigTestCode = TEST_F(TaintConfigTest, Array_01_Json) { const std::string File = "array_01_c_dbg.ll"; const std::string Config = "array_01_config.json"; + auto JsonConfig = - psr::parseTaintConfig(PathToJsonTaintConfigTestCode + Config); + psr::parseTaintConfig({PathToJsonTaintConfigTestCode.str() + Config}); + psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); + // IR.emitPreprocessedIR(llvm::outs(), false); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; + const llvm::Value *I = IR.getInstruction(3); ASSERT_TRUE(TConfig.isSource(I)); } @@ -247,7 +249,6 @@ TEST_F(TaintConfigTest, Array_02_Json) { psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); // IR.emitPreprocessedIR(llvm::outs(), false); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; const llvm::Value *I = IR.getInstruction(3); ASSERT_TRUE(TConfig.isSource(I)); } @@ -259,7 +260,7 @@ TEST_F(TaintConfigTest, Basic_01_Json) { psr::parseTaintConfig(PathToJsonTaintConfigTestCode + Config); psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; + const auto *Bar = IR.getFunction("bar"); assert(Bar); for (const auto &User : Bar->users()) { @@ -283,7 +284,6 @@ TEST_F(TaintConfigTest, Basic_02_Json) { psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); // IR.emitPreprocessedIR(llvm::outs(), false); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; const llvm::Value *I1 = IR.getInstruction(7); const llvm::Value *I2 = IR.getInstruction(18); ASSERT_TRUE(TConfig.isSource(I1)); @@ -315,8 +315,6 @@ TEST_F(TaintConfigTest, Basic_04_Json) { psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); // IR.emitPreprocessedIR(llvm::outs(), false); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; - llvm::outs().flush(); const llvm::Value *I = IR.getInstruction(2); ASSERT_TRUE(TConfig.isSource(I)); } @@ -328,8 +326,6 @@ TEST_F(TaintConfigTest, DataMember_01_Json) { psr::parseTaintConfig(PathToJsonTaintConfigTestCode + Config); psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; - llvm::outs().flush(); const llvm::Value *I = IR.getInstruction(17); // IR.emitPreprocessedIR(llvm::outs(), false); ASSERT_TRUE(TConfig.isSource(I)); @@ -344,10 +340,10 @@ TEST_F(TaintConfigTest, FunMember_01_Json) { // IR.emitPreprocessedIR(llvm::outs(), false); psr::LLVMTaintConfig TConfig(IR, JsonConfig); llvm::outs() << TConfig << '\n'; - for (const auto &F : IR.getAllFunctions()) { + for (const auto *F : IR.getAllFunctions()) { if (F->getName().contains("foo")) { assert(F); - for (const auto &User : F->users()) { + for (const auto *User : F->users()) { if (llvm::isa(User)) { ASSERT_TRUE(TConfig.isSource(User)); } @@ -362,12 +358,13 @@ TEST_F(TaintConfigTest, FunMember_01_Json) { TEST_F(TaintConfigTest, FunMember_02_Json) { const std::string File = "fun_member_02_cpp_dbg.ll"; const std::string Config = "fun_member_02_config.json"; + auto JsonConfig = psr::parseTaintConfig(PathToJsonTaintConfigTestCode + Config); + psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); // IR.emitPreprocessedIR(llvm::outs(), false); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; const llvm::Value *I1 = IR.getInstruction(18); const llvm::Value *I2 = IR.getInstruction(54); const llvm::Value *I3 = IR.getInstruction(63); @@ -376,6 +373,7 @@ TEST_F(TaintConfigTest, FunMember_02_Json) { ASSERT_TRUE(TConfig.isSource(I2)); ASSERT_TRUE(TConfig.isSource(I3)); ASSERT_TRUE(TConfig.isSource(I4)); + const auto *DestructorX = IR.getFunction("_ZN1XD2Ev"); assert(DestructorX); for (const auto *Arg = DestructorX->arg_begin(); @@ -399,8 +397,7 @@ TEST_F(TaintConfigTest, NameMangling_01_Json) { psr::parseTaintConfig(PathToJsonTaintConfigTestCode + Config); psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File}); psr::LLVMTaintConfig TConfig(IR, JsonConfig); - llvm::outs() << TConfig << '\n'; - llvm::outs().flush(); + for (const auto *F : IR.getAllFunctions()) { std::string FName = getFunctionName(llvm::demangle(F->getName().str())); if (FName == "foo") { From 9eda5e2678bd6c2a799dbd84db8d4a983af76361 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Fri, 27 Oct 2023 14:52:43 +0200 Subject: [PATCH 37/59] Cleanup Build (#673) * Pin swift version * Some build cleanup * Correctly find unittests even if the build-folder is not called "build" * Greater build variety in the CI * Minimize direct modification of CMAKE_CXX_FLAGS + use portable variants of some compilation flags if available + add the ability to turn on -march=native + minor * Add compile options only for C++ build + link LLVM publicly to support BUILD_SHARED_LIBS * Only add asan for CXX builds * Some build cleanup * Correctly find unittests even if the build-folder is not called "build" * Greater build variety in the CI * Minimize direct modification of CMAKE_CXX_FLAGS + use portable variants of some compilation flags if available + add the ability to turn on -march=native + minor * Add compile options only for C++ build + link LLVM publicly to support BUILD_SHARED_LIBS * Only add asan for CXX builds * Move config defines to config.h.in * Fix add_cxx_* macros + link more privately * Make PhasarClang optional * Install phasar-config.h * Out-factor DebugSan in PHASAR_ENABLE_SANITIZERS * Allow for multi-config (not tested) * Make dependencies independent from phasar build flags + enable more warnings * Support for manually setting USE_LLVM_FAT_LIB + remove some obsolete system dependencies * Cleanup system deps * Fix install boost in CI * Modernize LLVM build + minor improvements in bootstrap.sh * Improve add_phasar_library * Fix phasar_llvm lib build * Cleanup inclusion of OpenSSL- and Swift tests * minor * Remove explicit definition of linker language and lib prefix * Update install * Improve install by adding phasar include directories to the targets interfaces * minor * Small fixes for the in-tree build * minor style * minor tweak for in-tree build --- .clang-tidy | 1 + .github/ISSUE_TEMPLATE/bug_report.md | 11 +- .github/workflows/ci.yml | 24 +- BreakingChanges.md | 1 + CMakeLists.txt | 450 ++++++++++-------- Config.cmake.in | 41 +- Dockerfile | 3 +- bootstrap.sh | 44 +- cmake/phasar_macros.cmake | 127 +++-- config.h.in | 14 +- examples/use-phasar-as-library/CMakeLists.txt | 15 +- include/CMakeLists.txt | 1 - include/phasar/CMakeLists.txt | 0 include/phasar/Config/Configuration.h | 3 - include/phasar/ControlFlow/CallGraphBase.h | 2 - .../DataFlow/Mono/Solver/InterMonoSolver.h | 4 +- include/phasar/Utils/Logger.h | 2 + include/phasar/Utils/PAMMMacros.h | 2 + include/phasar/Utils/Utilities.h | 10 +- lib/AnalysisStrategy/CMakeLists.txt | 29 +- lib/CMakeLists.txt | 80 ++-- lib/Config/CMakeLists.txt | 34 +- lib/Config/Configuration.cpp | 10 +- lib/ControlFlow/CMakeLists.txt | 27 +- lib/Controller/CMakeLists.txt | 59 +-- lib/DB/CMakeLists.txt | 39 +- lib/PhasarClang/CMakeLists.txt | 45 +- lib/PhasarLLVM/CMakeLists.txt | 25 +- lib/PhasarLLVM/ControlFlow/CMakeLists.txt | 40 +- .../ControlFlow/Resolver/OTFResolver.cpp | 2 +- lib/PhasarLLVM/DB/CMakeLists.txt | 40 +- .../DataFlow/IfdsIde/CMakeLists.txt | 50 +- .../BranchSwitchInstFlowFunction.cpp | 2 +- .../AbstractMemoryLocationFactory.cpp | 3 +- .../Problems/IDEExtendedTaintAnalysis.cpp | 2 +- lib/PhasarLLVM/DataFlow/Mono/CMakeLists.txt | 40 +- lib/PhasarLLVM/Passes/CMakeLists.txt | 38 +- lib/PhasarLLVM/Pointer/CMakeLists.txt | 52 +- lib/PhasarLLVM/TaintConfig/CMakeLists.txt | 45 +- lib/PhasarLLVM/TypeHierarchy/CMakeLists.txt | 43 +- lib/PhasarLLVM/Utils/CMakeLists.txt | 45 +- lib/PhasarPass/CMakeLists.txt | 60 +-- lib/PhasarPass/PhasarPass.cpp | 2 +- lib/Pointer/CMakeLists.txt | 32 +- lib/Pointer/PointsToInfo.cpp | 8 +- lib/Utils/CMakeLists.txt | 36 +- tools/example-tool/CMakeLists.txt | 9 +- tools/phasar-cli/CMakeLists.txt | 36 +- tools/phasar-cli/phasar-cli.cpp | 2 +- unittests/CMakeLists.txt | 4 +- .../DataFlow/IfdsIde/Problems/CMakeLists.txt | 48 +- .../IDELinearConstantAnalysis_DotTest.cpp | 1 - .../PhasarLLVM/Pointer/LLVMAliasSetTest.cpp | 8 +- unittests/TestUtils/TestConfig.h | 14 +- unittests/Utils/EquivalenceClassMapTest.cpp | 2 +- utils/InstallAptDependencies.sh | 6 +- utils/install-llvm.sh | 4 +- 57 files changed, 744 insertions(+), 1033 deletions(-) delete mode 100644 include/CMakeLists.txt delete mode 100644 include/phasar/CMakeLists.txt diff --git a/.clang-tidy b/.clang-tidy index 063d1090a..5d40d294d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -25,6 +25,7 @@ Checks: '-*, -cppcoreguidelines-non-private-member-variables-in-classes, -cppcoreguidelines-init-variables, -cppcoreguidelines-macro-usage, + -cppcoreguidelines-avoid-do-while, bugprone-*, -bugprone-easily-swappable-parameters, modernize-*, diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a571a74a2..24e0ca0b9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,7 +11,7 @@ assignees: '' Replace the empty checkboxes [ ] below with checked ones [x] accordingly. --> - [ ] I have searched open and closed issues for duplicates - - [ ] I made sure that I am not using an old project version (DO: pull Phasar, update git submodules, rebuild the project and check if the bug is still there) + - [ ] I made sure that I am not using an old project version (DO: pull PhASAR, update git submodules, rebuild the project and check if the bug is still there) ---------------------------------------- @@ -24,9 +24,9 @@ Describe here the issue that you are experiencing. - that reproduce the bug - e.g. cli arguments and flags -**Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour) +**Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behavior) -**Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour) +**Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behavior) ### Context (Environment) @@ -35,7 +35,7 @@ Describe here the issue that you are experiencing. - **phasar:** \[commit-id] - **googletest:** \[commit-id] - **json:** \[commit-id] - - **WALi-OpenNWA:** \[commit-id] + - **json-schema-validator** \[commit-id] @@ -48,11 +48,12 @@ Describe here the issue that you are experiencing. **Build Type:** - [ ] cmake + - [ ] bootstrap.sh - [ ] custom build ### Possible solution -We are happy to discuss possible solutions to this problem, especially if it origniates from a design flaw. +We are happy to discuss possible solutions to this problem, especially if it originates from a design flaw. ### Example files diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccf529334..d109a180f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,11 @@ jobs: matrix: compiler: [ [clang++-14, clang-14] ] build: [ Debug, Release ] + include: + - build: Debug + flags: -DPHASAR_BUILD_DYNLIB=ON -DPHASAR_ENABLE_SANITIZERS=ON + - build: Release + flags: -DPHASAR_ENABLE_DYNAMIC_LOG=OFF continue-on-error: false steps: @@ -23,20 +28,11 @@ jobs: fetch-depth: 0 submodules: recursive - - name: Install Basic Dependencies - shell: bash - run: | - sudo apt-get update - sudo apt-get -y install --no-install-recommends \ - cmake \ - ninja-build \ - libstdc++6 \ - libboost-all-dev - - name: Install Phasar Dependencies shell: bash run: | ./utils/InstallAptDependencies.sh + sudo apt-get -y install --no-install-recommends libboost-graph-dev - name: Install Strategy Dependencies shell: bash @@ -59,7 +55,6 @@ jobs: swift-version: "5.8.1" - name: Building Phasar in ${{ matrix.build }} with ${{ matrix.compiler[0] }} env: - BUILD_TYPE: ${{ matrix.build }} CXX: ${{ matrix.compiler[0] }} CC: ${{ matrix.compiler[1] }} shell: bash @@ -67,9 +62,10 @@ jobs: mkdir build cd build cmake .. \ - -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ - -DCMAKE_CXX_COMPILER=$CXX \ - -DBUILD_SWIFT_TESTS=1 \ + -DCMAKE_BUILD_TYPE=${{ matrix.build }} \ + -DBUILD_SWIFT_TESTS=ON \ + -DPHASAR_DEBUG_LIBDEPS=ON \ + ${{ matrix.flags }} \ -G Ninja cmake --build . diff --git a/BreakingChanges.md b/BreakingChanges.md index 477de93b7..ad40d45f6 100644 --- a/BreakingChanges.md +++ b/BreakingChanges.md @@ -3,6 +3,7 @@ ## Development HEAD - Default build mode is no longer `SHARED` but `STATIC`. To build in shared mode, use the cmake option `BUILD_SHARED_LIBS` which we don't recommend anymore. Consider using `PHASAR_BUILD_DYNLIB` instead to build one big libphasar.so. +- Build type `DebugSan` has been removed in favor of a new CMake option `PHASAR_ENABLE_SANITIZERS` that not only works in `Debug` mode. ## v0323 diff --git a/CMakeLists.txt b/CMakeLists.txt index b9eb75366..68c3607c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,14 @@ cmake_minimum_required (VERSION 3.9) cmake_policy(SET CMP0069 NEW) set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) +# Allow overwriting options of external projects from this CMakeLists file +cmake_policy(SET CMP0077 NEW) +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + +# Allow portable use of CMAKE_VISIBILITY_INLINES_HIDDEN not only for shared libraries +cmake_policy(SET CMP0063 NEW) +set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) + # Check if we build within the llvm source tree if (DEFINED LLVM_MAIN_SRC_DIR) set(PHASAR_IN_TREE 1) @@ -18,7 +26,7 @@ option(PHASAR_EXPERIMENTAL_CXX20 "Build phasar in C++20 mode. This is an experim set(CMAKE_EXPORT_COMPILE_COMMANDS YES) if(PHASAR_EXPERIMENTAL_CXX20) - message(STATUS "Selected experimental C++ build") + message(STATUS "Selected experimental C++20 build") set(CMAKE_CXX_STANDARD 20) else() set(CMAKE_CXX_STANDARD 17) @@ -30,60 +38,95 @@ include(GNUInstallDirs) set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF) -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build mode ('DebugSan' or 'Debug' or 'Release', default is 'Debug')" FORCE) +option(PHASAR_ENABLE_SANITIZERS "Build PhASAR with AddressSanitizer and UBSanitizer (default is OFF)" OFF) + +set(PHASAR_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(PHASAR_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PHASAR_SRC_DIR}/cmake") +include("phasar_macros") + +if (NOT CMAKE_BUILD_TYPE AND NOT GENERATOR_IS_MULTI_CONFIG) + message(STATUS "No CMAKE_BUILD_TYPE specified, setting it to Debug") + set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build mode ('Debug' or 'Release', default is 'Debug')" FORCE) endif () -if(CMAKE_BUILD_TYPE STREQUAL "DebugSan") - message(STATUS "Selected Debug Build with sanitizers") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -fvisibility-inlines-hidden -fstack-protector-strong -ffunction-sections -fdata-sections -pipe -g -fno-omit-frame-pointer -fsanitize=address,undefined") -elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") - message(STATUS "Selected Debug Build") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -fvisibility-inlines-hidden -fstack-protector-strong -ffunction-sections -fdata-sections -pipe -g") +if(GENERATOR_IS_MULTI_CONFIG) + message(STATUS "Selected multi-config Build") + set(CMAKE_CONFIGURATION_TYPES Debug RelWithDebInfo Release CACHE STRING "Configuration types: Debug, RelWithDebInfo and Release" FORCE) else() - message(STATUS "Selected Release Build") + message(STATUS "Selected ${CMAKE_BUILD_TYPE} Build") +endif() - include(CheckIPOSupported) - check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_SUPPORT_ERROR) +set(DEBUG_CONFIGURATIONS DEBUG CACHE INTERNAL "" FORCE) +set(RELEASE_CONFIGURATIONS RELWITHDEBINFO RELEASE CACHE INTERNAL "" FORCE) +# TODO: Once available, we may want to use -fextend-lifetimes on Debug- and RelWithDebInfo builds to improve debugging experience +# https://reviews.llvm.org/D157613 - if(LTO_SUPPORTED) - message(STATUS "IPO/LTO enabled") - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) # LTO - else() - message(STATUS "IPO/LTO not supported: ${LTO_SUPPORT_ERROR}") - endif() +string(APPEND CMAKE_CXX_FLAGS " -MP -fstack-protector-strong -ffunction-sections -fdata-sections -pipe") +string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og -fno-omit-frame-pointer") +string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-omit-frame-pointer") +string(APPEND CMAKE_CXX_FLAGS_RELEASE "") + +option(CMAKE_VISIBILITY_INLINES_HIDDEN "Hide inlined functions from the DSO table (default ON)" ON) +# march=native - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -fvisibility-inlines-hidden -fstack-protector-strong -ffunction-sections -fdata-sections -pipe") +# NOTE: Use gcc -march=native -Q --help=target | grep -- '-march=' | cut -f3 +# to check the architecture detected by match=native +# set(PHASAR_TARGET_ARCH "" CACHE STRING "Optimize the build for the given target architecture, e.g. -march=native. Most useful in Release builds. Disabled by default") +if (DEFINED PHASAR_TARGET_ARCH) + if (NOT CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT GENERATOR_IS_MULTI_CONFIG) + message(WARNING "The PHASAR_TARGET_ARCH flag will be ignored in non-Release build type ${CMAKE_BUILD_TYPE}") + else() + set(PHASAR_TARGET_ARCH_INTERNAL "${PHASAR_TARGET_ARCH}") + endif() +elseif("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + set(PHASAR_TARGET_ARCH_INTERNAL "native") endif() -# Enable testing -enable_testing() +if (NOT "${PHASAR_TARGET_ARCH_INTERNAL}" STREQUAL "") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-march=${PHASAR_TARGET_ARCH_INTERNAL}" MARCH_SUPPORTED) + if (MARCH_SUPPORTED) + message(STATUS "Target architecture '${PHASAR_TARGET_ARCH_INTERNAL}' enabled") + string(APPEND CMAKE_CXX_FLAGS_RELEASE " -march=${PHASAR_TARGET_ARCH_INTERNAL}") + else() + message(WARNING "Target architecture '${PHASAR_TARGET_ARCH_INTERNAL}' not supported. Fallback to generic build") + endif() +endif() -# 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!") -# endif() +# Sanitizers +if (PHASAR_ENABLE_SANITIZERS) + message(STATUS "Selected ${CMAKE_BUILD_TYPE} Build with Sanitizers") -set(PHASAR_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PHASAR_SRC_DIR}/cmake") + if(MSVC) + set(ASAN_FLAG "/fsanitize=address") + else() + set(ASAN_FLAG "-fsanitize=address,undefined") + endif() -file(STRINGS ${PHASAR_SRC_DIR}/include/phasar/Config/Version.h VERSION_NUMBER_FILE) -string(REPLACE " " ";" VERSION_NUMBER_FILE ${VERSION_NUMBER_FILE}) -list(GET VERSION_NUMBER_FILE 2 VERSION_NUMBER_PHASAR) + string(APPEND CMAKE_CXX_FLAGS " ${ASAN_FLAG}") +endif() -include("phasar_macros") +# LTO +if (GENERATOR_IS_MULTI_CONFIG OR CMAKE_BUILD_TYPE STREQUAL "Release") + include(CheckIPOSupported) + check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_SUPPORT_ERROR) -option(PHASAR_BUILD_UNITTESTS "Build all tests (default is ON)" ON) + if(LTO_SUPPORTED) + message(STATUS "IPO/LTO enabled in Release mode") + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) # LTO + else() + message(STATUS "IPO/LTO not supported: ${LTO_SUPPORT_ERROR}") + endif() +endif() -option(BUILD_SWIFT_TESTS "Builds the Swift tests (Swift compiler has to be installed manually beforehand!)" OFF) -if (BUILD_SWIFT_TESTS) - set(CMAKE_Swift_FLAGS_RELEASE "-g") - set(CMAKE_Swift_FLAGS_RELWITHDEBINFO "-g") - enable_language(Swift) -endif(BUILD_SWIFT_TESTS) +# Enable testing +enable_testing() + +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) @@ -102,25 +145,21 @@ if(PHASAR_BUILD_DYNLIB AND BUILD_SHARED_LIBS) message(FATAL_ERROR "PHASAR_BUILD_DYNLIB is incompatible with BUILD_SHARED_LIBS") endif() -option(PHASAR_ENABLE_WARNINGS "Enable warnings" ON) -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) - option(PHASAR_ENABLE_PIC "Build Position-Independed Code" ON) if (PHASAR_ENABLE_PIC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") + set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif (PHASAR_ENABLE_PIC) +# 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) - add_compile_definitions(PAMM_CORE) + set(PAMM_CORE ON) message(STATUS "PAMM metric severity level: Core") elseif(PHASAR_ENABLE_PAMM STREQUAL "Full" AND NOT PHASAR_BUILD_UNITTESTS) - add_compile_definitions(PAMM_FULL) + set(PAMM_FULL ON) message(STATUS "PAMM metric severity level: Full") elseif(PHASAR_BUILD_UNITTESTS AND (PHASAR_ENABLE_PAMM STREQUAL "Core" OR PHASAR_ENABLE_PAMM STREQUAL "Full")) message(WARNING "PAMM metric severity level: Off (due to unittests)") @@ -128,22 +167,17 @@ else() message(STATUS "PAMM metric severity level: Off") endif() +# Logger 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) message(STATUS "Dynamic log enabled") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDYNAMIC_LOG") + set(DYNAMIC_LOG ON) else() message(STATUS "Dynamic log disabled") endif() -configure_file(config.h.in config.h @ONLY) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -include_directories( - ${PHASAR_SRC_DIR}/include -) - +# RPATH if (NOT PHASAR_IN_TREE) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) @@ -155,12 +189,14 @@ if (NOT PHASAR_IN_TREE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() +# Filesystem if (LLVM_ENABLE_LIBCXX) set(PHASAR_STD_FILESYSTEM c++fs) else() set(PHASAR_STD_FILESYSTEM stdc++fs) endif() +# Config set(PHASAR_CUSTOM_CONFIG_INSTALL_DIR "" CACHE STRING "If set, customizes the directory, where configuration files for PhASAR are installed (default is /usr/local/.phasar-config)") if ("${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}" STREQUAL "") set(PHASAR_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/.phasar-config/") @@ -168,28 +204,21 @@ else() set(PHASAR_CONFIG_INSTALL_DIR "${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}") endif() -add_compile_definitions(PHASAR_CONFIG_DIR="${PHASAR_CONFIG_INSTALL_DIR}") -add_compile_definitions(PHASAR_DIR="${PHASAR_SRC_DIR}") - - ### Adding external libraries + # Threads find_package(Threads) # Boost -find_package(Boost 1.65.1 COMPONENTS graph ${BOOST_THREAD} REQUIRED) -#find_package(Boost 1.72.0 COMPONENTS graph ${BOOST_THREAD} REQUIRED) -include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) +find_package(Boost 1.65.1 COMPONENTS graph REQUIRED) # Disable clang-tidy for the external projects set(CMAKE_CXX_CLANG_TIDY "") # Nlohmann JSON - set(JSON_BuildTests OFF) set(JSON_Install ON) add_subdirectory(external/json) -include_directories(SYSTEM external/json/include/) # We need to work around the behavior of nlohmann_json_schema_validator and nlohmann_json here # The validator needs the json part, but if you include it, the library of nlohmann_json_schema_validator @@ -209,88 +238,90 @@ endif() # Json Schema Validator set(JSON_VALIDATOR_INSTALL ON) add_subdirectory(external/json-schema-validator) -include_directories(SYSTEM external/json-schema-validator/src/) # Googletest if (NOT PHASAR_IN_TREE) + set(BUILD_GMOCK OFF) + set(INSTALL_GTEST OFF) add_subdirectory(external/googletest EXCLUDE_FROM_ALL) - include_directories(SYSTEM external/googletest/googletest/include) - include_directories(SYSTEM external/googletest/googlemock/include) + set(GTEST_INCLUDE_DIR "external/googletest/googletest/include") else() # Set llvm distributed includes for gtest header - include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include) - include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock/include) + set(GTEST_INCLUDE_DIR "${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include") endif() # SQL find_path(SQLITE3_INCLUDE_DIR NAMES sqlite3.h) find_library(SQLITE3_LIBRARY NAMES sqlite3) -include_directories(SYSTEM ${SQLITE3_INCLUDE_DIR}) + +option(USE_LLVM_FAT_LIB "Link against libLLVM.so instead of the individual LLVM libraries if possible (default is OFF; always on if BUILD_SHARED_LIBS is ON)" OFF) # LLVM if (NOT PHASAR_IN_TREE) # Only search for LLVM if we build out of tree find_package(LLVM 14 REQUIRED CONFIG) - include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) - link_directories(${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS}) -endif() - -add_definitions(${LLVM_DEFINITIONS}) -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) + + if(USE_LLVM_FAT_LIB AND ${LLVM_LIBRARY} STREQUAL "LLVM_LIBRARY-NOTFOUND") + message(WARNING "Did not find requested libLLVM.so. Link against individual modules instead") + set(USE_LLVM_FAT_LIB OFF) + elseif(BUILD_SHARED_LIBS AND 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) endif() endif() +if(NOT LLVM_ENABLE_RTTI AND NOT PHASAR_IN_TREE) + message(FATAL_ERROR "PhASAR requires a LLVM version that is built with RTTI") +endif() + # Clang -# 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) +option(BUILD_PHASAR_CLANG "Build the phasar_clang library (default is ON)" ON) + +if(BUILD_PHASAR_CLANG) + # 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 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 + clangTooling + clangFrontendTool + clangFrontend + clangDriver + clangSerialization + clangCodeGen + clangParse + clangSema + clangStaticAnalyzerFrontend + clangStaticAnalyzerCheckers + clangStaticAnalyzerCore + clangAnalysis + clangARCMigrate + clangRewrite + clangRewriteFrontend + clangEdit + clangAST + clangASTMatchers + clangLex + clangBasic + LLVMFrontendOpenMP) endif() -endif() -# As fallback, look for the small clang libraries -if(PHASAR_IN_TREE OR NEED_LIBCLANG_COMPONENT_LIBS) - set(CLANG_LIBRARY - clangTooling - clangFrontendTool - clangFrontend - clangDriver - clangSerialization - clangCodeGen - clangParse - clangSema - clangStaticAnalyzerFrontend - clangStaticAnalyzerCheckers - clangStaticAnalyzerCore - clangAnalysis - clangARCMigrate - clangRewrite - clangRewriteFrontend - clangEdit - clangAST - clangASTMatchers - clangLex - clangBasic - LLVMFrontendOpenMP) -endif() -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) - # Phasar needs clang headers, specificaly some that are generated by clangs table-gen - include_directories(SYSTEM - ${CLANG_INCLUDE_DIR} - ${PHASAR_SRC_DIR}/../clang/include - ${PROJECT_BINARY_DIR}/tools/clang/include - ) -endif() + if (PHASAR_IN_TREE) + # Phasar needs clang headers, specificaly some that are generated by clangs table-gen + include_directories(SYSTEM + ${CLANG_INCLUDE_DIR} + ${PHASAR_SRC_DIR}/../clang/include + ${PROJECT_BINARY_DIR}/tools/clang/include + ) + endif() +endif(BUILD_PHASAR_CLANG) # Set up clang-tidy to run during PhASAR's compilation to indicate code smells if (PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD) @@ -302,44 +333,56 @@ if (PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD) ) endif () -# Add PhASAR's subdirectories -add_subdirectory(include) -add_subdirectory(lib) +# Library Dependency Dirs +if(NOT PHASAR_IN_TREE) + include_directories(${LLVM_INCLUDE_DIRS}) + link_directories(${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS}) + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) + add_definitions(${LLVM_DEFINITIONS_LIST}) + if (BUILD_PHASAR_CLANG) + link_directories(${CLANG_LIB_PATH}) + endif() +endif() -set(LLVM_LINK_COMPONENTS - coverage - coroutines - demangle - libdriver - lto - support - analysis - bitwriter - core - ipo - irreader - instcombine - instrumentation - linker - objcarcopts - scalaropts - transformutils - codegen - vectorize -) +# Installed config +configure_file(config.h.in include/phasar/Config/phasar-config.h @ONLY) -llvm_map_components_to_libnames(llvm_libs - ${LLVM_LINK_COMPONENTS} -) +# Warnings +option(PHASAR_ENABLE_WARNINGS "Enable warnings" ON) +if (PHASAR_ENABLE_WARNINGS) + if (MSVC) + string(APPEND CMAKE_CXX_FLAGS " /W4") + else() + string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wno-unused-parameter") + endif() +endif (PHASAR_ENABLE_WARNINGS) + +# Some preprocessor symbols that need to be available in phasar sources, but should not be installed +add_cxx_compile_definitions(PHASAR_SRC_DIR="${CMAKE_SOURCE_DIR}") +add_cxx_compile_definitions(PHASAR_BUILD_DIR="${CMAKE_BINARY_DIR}") + +# Add PhASAR's subdirectories +add_subdirectory(lib) # phasar-based binaries add_subdirectory(tools) +# Swift tests +option(BUILD_SWIFT_TESTS "Builds the Swift tests (Swift compiler has to be installed manually beforehand!)" OFF) +if (BUILD_SWIFT_TESTS) + set(CMAKE_Swift_FLAGS_RELEASE "-g") + set(CMAKE_Swift_FLAGS_RELWITHDEBINFO "-g") + enable_language(Swift) +endif(BUILD_SWIFT_TESTS) + # Add Phasar unittests and build all IR test code if (PHASAR_BUILD_UNITTESTS) message("Phasar unittests") add_subdirectory(unittests) - set(PHASAR_BUILD_IR ON) + if(NOT PHASAR_BUILD_IR) + message(WARNING "Set PHASAR_BUILD_IR=ON, because PHASAR_BUILD_UNITTESTS is ON") + set(PHASAR_BUILD_IR ON) + endif() endif() # Build all IR test code @@ -348,7 +391,8 @@ if (PHASAR_BUILD_IR) add_subdirectory(test) endif() -set(INCLUDE_INSTALL_DIR include/ CACHE PATH "Install dir of headers") +set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}" CACHE PATH "Install dir of headers") +set(LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}" CACHE PATH "Install dir of libraries") # Install targets of phasar-cli, other executables, and libraries are to be # found in the individual subdirectories of tools/ @@ -361,6 +405,14 @@ install(DIRECTORY include/ PATTERN "*.h" ) +# Install the config file +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/phasar/Config/ + DESTINATION include/phasar/Config + FILES_MATCHING + PATTERN "*.def" + PATTERN "*.h" +) + # Install the header only json container install(DIRECTORY external/json/single_include/ DESTINATION include @@ -397,21 +449,21 @@ configure_package_config_file( Config.cmake.in phasarConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/phasar - PATH_VARS INCLUDE_INSTALL_DIR - ) + PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_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( FILES "${CMAKE_CURRENT_BINARY_DIR}/phasarConfig.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 @@ -433,62 +485,44 @@ 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(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_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_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) - 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) - message("Doxygen build started") - add_custom_target(doc_doxygen ALL - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen" - VERBATIM - ) - else(DOXYGEN_FOUND) - message(FATAL_ERROR "Doxygen need to be installed to generate the doxygen documentation.") - endif() + find_package(Doxygen REQUIRED) + + 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) + + add_custom_target(doc_doxygen ALL + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM + ) endif() diff --git a/Config.cmake.in b/Config.cmake.in index 78e7bb723..98d5c07c7 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -2,13 +2,19 @@ set(PHASAR_VERSION 1.0.0) @PACKAGE_INIT@ set_and_check(PHASAR_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(PHASAR_LIBRARY_DIR "@PACKAGE_LIBRARY_INSTALL_DIR@") include (CMakeFindDependencyMacro) find_dependency(nlohmann_json) find_dependency(nlohmann_json_schema_validator) -find_package(Boost 1.65.1 COMPONENTS program_options graph REQUIRED) -# TODO: The order seems to be important. Fix this! +find_package(Boost 1.65.1 COMPONENTS graph REQUIRED) +find_package(LLVM 14 REQUIRED CONFIG) + +set(PHASAR_USE_LLVM_FAT_LIB @USE_LLVM_FAT_LIB@) +set(PHASAR_BUILD_DYNLIB @PHASAR_BUILD_DYNLIB@) + +# TODO: The order seems to be important in the include'ing loop below. Fix this! set(PHASAR_COMPONENTS utils @@ -32,27 +38,32 @@ set(PHASAR_COMPONENTS controller ) +list(REMOVE_DUPLICATES phasar_FIND_COMPONENTS) + +foreach(component ${phasar_FIND_COMPONENTS}) + if(NOT ${component} IN_LIST PHASAR_COMPONENTS) + set(phasar_FOUND false) + set(phasar_NOT_FOUND_MESSAGE "Unsupported component: ${component}. valid components are: ${PHASAR_COMPONENTS}") + endif() +endforeach() + foreach(component ${PHASAR_COMPONENTS}) include("${CMAKE_CURRENT_LIST_DIR}/phasar_${component}-targets.cmake") - list(APPEND PHASAR_NEEDED_LIBS phasar::phasar_${component}) endforeach() +include("${CMAKE_CURRENT_LIST_DIR}/phasar-targets.cmake") -list(REMOVE_DUPLICATES PHASAR_NEEDED_LIBS) +if (NOT phasar_FIND_COMPONENTS) + list(APPEND PHASAR_NEEDED_LIBS phasar::phasar) + set(phasar_FIND_COMPONENTS ${PHASAR_NEEDED_LIBS}) +endif() -find_package(LLVM 14 REQUIRED CONFIG) -include_directories(${LLVM_INCLUDE_DIRS}) -link_directories(${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS}) -find_library(LLVM_LIBRARY NAMES LLVM HINTS ${LLVM_LIBRARY_DIRS}) +foreach(component ${phasar_FIND_COMPONENTS}) + list(APPEND PHASAR_NEEDED_LIBS phasar::phasar_${component}) +endforeach() function(phasar_config executable) - if(NOT ${LLVM_LIBRARY} STREQUAL "LLVM_LIBRARY-NOTFOUND") - llvm_config(${executable} USE_SHARED ${PHASAR_LLVM_DEPS}) - else() - llvm_config(${executable} ${PHASAR_LLVM_DEPS}) - endif() - target_link_libraries(${executable} PUBLIC - ${PHASAR_NEEDED_LIBS} + ${PHASAR_NEEDED_LIBS} ) endfunction() diff --git a/Dockerfile b/Dockerfile index f91375c66..f5893f5a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get -y install --no-install-recommends \ cmake \ ninja-build \ libstdc++6 \ - libboost-all-dev + libboost-graph-dev COPY ./utils/InstallAptDependencies.sh /usr/src/phasar/utils/ RUN ./utils/InstallAptDependencies.sh @@ -53,6 +53,7 @@ RUN git submodule update RUN mkdir -p build && cd build && \ cmake .. \ -DCMAKE_BUILD_TYPE=Release \ + -DPHASAR_TARGET_ARCH="" \ -DCMAKE_CXX_COMPILER=$CXX \ -G Ninja && \ cmake --build . diff --git a/bootstrap.sh b/bootstrap.sh index 2b5bfe397..9e615a1b3 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -9,12 +9,26 @@ readonly PHASAR_INSTALL_DIR="/usr/local/phasar" readonly LLVM_INSTALL_DIR="/usr/local/llvm-14" NUM_THREADS=$(nproc) -LLVM_RELEASE=llvmorg-14.0.0 +LLVM_RELEASE=llvmorg-14.0.6 DO_UNIT_TEST=true DO_INSTALL=false BUILD_TYPE=Release +function usage { + echo "USAGE: ./bootstrap.sh [options]" + echo "" + echo "OPTIONS:" + echo -e "\t--jobs\t\t-j\t\t- Number of parallel jobs used for compilation (default is nproc -- $(nproc))" + echo -e "\t--unittest\t-u\t\t- Build and run PhASARs unit-tests (default is true)" + echo -e "\t--install\t\t\t- Install PhASAR system-wide after building (default is false)" + echo -e "\t--help\t\t-h\t\t- Display this help message" + echo -e "\t-DBOOST_DIR=\t\t- The directory where boost should be installed (optional)" + echo -e "\t-DBOOST_VERSION=\t- The desired boost version to install (optional)" + echo -e "\t-DCMAKE_BUILD_TYPE=\t- The build mode for building PhASAR. One of {Debug, RelWithDebInfo, Release} (default is Release)" + echo -e "\t-DPHASAR_INSTALL_DIR=\t- The folder where to install PhASAR if --install is specified (default is /usr/local/phasar)" +} + # Parsing command-line-parameters # See "https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash" as a reference @@ -59,6 +73,19 @@ case $key in DO_INSTALL=true shift # past argument ;; + -DPHASAR_INSTALL_DIR) + PHASAR_INSTALL_DIR="$2" + shift # past argument + shift # past value + ;; + -DPHASAR_INSTALL_DIR=*) + PHASAR_INSTALL_DIR="${key#*=}" + shift # past argument=value + ;; + -h|--help) + usage + exit 0 + ;; *) # unknown option POSITIONAL+=("$1") # save it in an array for later shift # past argument @@ -71,14 +98,11 @@ set -- "${POSITIONAL[@]}" # restore positional parameters echo "installing phasar dependencies..." if [ -x "$(command -v pacman)" ]; then - yes | sudo pacman -Syu --needed which zlib sqlite3 ncurses make python3 doxygen libxml2 swig gcc z3 libedit graphviz python-sphinx openmp curl python-pip ninja - ./utils/installBuildEAR.sh + yes | sudo pacman -Syu --needed which zlib sqlite3 python3 doxygen gcc python-pip ninja cmake else ./utils/InstallAptDependencies.sh fi -pip3 install cmake - if [ ! -z "${DESIRED_BOOST_DIR}" ]; then BOOST_PARAMS="-DBOOST_ROOT=${DESIRED_BOOST_DIR}" else @@ -91,10 +115,10 @@ else yes | sudo pacman -Syu --needed boost-libs boost else if [ -z "$DESIRED_BOOST_VERSION" ] ;then - sudo apt install libboost-all-dev -y + sudo apt-get install libboost-graph-dev -y else # DESIRED_BOOST_VERSION in form d.d, i.e. 1.65 (this is the latest version I found in the apt repo) - sudo apt install "libboost${DESIRED_BOOST_VERSION}-all-dev" -y + sudo apt-get install "libboost${DESIRED_BOOST_VERSION}-graph-dev" -y fi #verify installation BOOST_VERSION=$(echo -e '#include \nBOOST_LIB_VERSION' | gcc -s -x c++ -E - 2>/dev/null| grep "^[^#;]" | tr -d '\"') @@ -110,9 +134,7 @@ else if [ -x "$(command -v apt)" ]; then DESIRED_BOOST_VERSION=${BOOST_VERSION//_/.} # install missing packages if necessary - boostlibnames=("libboost-system" "libboost-filesystem" - "libboost-graph" "libboost-program-options" - "libboost-thread") + boostlibnames=("libboost-graph") additional_boost_libs=() for boost_lib in ${boostlibnames[@]}; do dpkg -s "$boost_lib${DESIRED_BOOST_VERSION}" >/dev/null 2>&1 || @@ -123,7 +145,7 @@ else done if [ ${#additional_boost_libs[@]} -gt 0 ] ;then echo "Installing additional ${#additional_boost_libs[@]} boost packages: ${additional_boost_libs[*]}" - sudo apt install "${additional_boost_libs[@]}" -y || true + sudo apt-get install "${additional_boost_libs[@]}" -y || true fi fi fi diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index db0096471..4e7b2a901 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -1,3 +1,18 @@ + +function(phasar_link_llvm executable) + # llvm_config links LLVM as PRIVATE. We need to link PUBLIC + if (USE_LLVM_FAT_LIB) + target_link_libraries(${executable} PUBLIC LLVM) + else() + llvm_map_components_to_libnames(LLVM_LIBRARIES ${ARGN}) + target_link_libraries(${executable} PUBLIC ${LLVM_LIBRARIES}) + endif() +endfunction() + +macro(add_cxx_compile_definitions) + add_compile_definitions("$<$:${ARGN}>") +endmacro() + function(add_phasar_unittest test_name) message("Set-up unittest: ${test_name}") get_filename_component(test ${test_name} NAME_WE) @@ -6,22 +21,12 @@ function(add_phasar_unittest test_name) ) add_dependencies(PhasarUnitTests ${test}) - if(USE_LLVM_FAT_LIB) - llvm_config(${test} USE_SHARED ${LLVM_LINK_COMPONENTS}) - else() - llvm_config(${test} ${LLVM_LINK_COMPONENTS}) - endif() + phasar_link_llvm(${test} ${LLVM_LINK_COMPONENTS}) target_link_libraries(${test} - LINK_PUBLIC - phasar - nlohmann_json_schema_validator - ${SQLITE3_LIBRARY} - ${Boost_LIBRARIES} - ${CMAKE_DL_LIBS} - ${CMAKE_THREAD_LIBS_INIT} - curl - gtest + PRIVATE + phasar + gtest ) add_test(NAME "${test}" @@ -147,25 +152,31 @@ macro(add_phasar_executable name) ) endmacro(add_phasar_executable) -macro(add_phasar_library name) - set(srcs ${ARGN}) +function(add_phasar_library name) + set(PHASAR_LIB_OPTIONS SHARED STATIC MODULE INTERFACE) + set(PHASAR_LIB_MULTIVAL LLVM_LINK_COMPONENTS LINKS LINK_PUBLIC LINK_PRIVATE FILES) + cmake_parse_arguments(PHASAR_LIB "${PHASAR_LIB_OPTIONS}" "" "${PHASAR_LIB_MULTIVAL}" ${ARGN}) + set(srcs ${PHASAR_LIB_UNPARSED_ARGUMENTS}) + list(APPEND srcs ${PHASAR_LIB_FILES}) if(MSVC_IDE OR XCODE) file(GLOB_RECURSE headers *.h *.td *.def) - set(srcs ${srcs} ${headers}) + list(APPEND srcs ${headers}) string(REGEX MATCHALL "/[^/]" split_path ${CMAKE_CURRENT_SOURCE_DIR}) list(GET split_path -1 dir) file(GLOB_RECURSE headers ../../include/phasar${dir}/*.h) - set(srcs ${srcs} ${headers}) + list(APPEND srcs ${headers}) endif(MSVC_IDE OR XCODE) - if(MODULE) + if(PHASAR_LIB_MODULE) set(libkind MODULE) - elseif(SHARED_LIBRARY) + elseif(PHASAR_LIB_INTERFACE) + set(libkind INTERFACE) + elseif(PHASAR_LIB_SHARED OR BUILD_SHARED_LIBS) set(libkind SHARED) else() - set(libkind) + set(libkind STATIC) endif() add_library(${name} ${libkind} ${srcs}) @@ -175,29 +186,28 @@ macro(add_phasar_library name) add_dependencies(${name} ${LLVM_COMMON_DEPENDS}) endif(LLVM_COMMON_DEPENDS) - if(LLVM_USED_LIBS) - foreach(lib ${LLVM_USED_LIBS}) - target_link_libraries(${name} ${lib}) - endforeach(lib) - endif(LLVM_USED_LIBS) - - if(PHASAR_LINK_LIBS) - foreach(lib ${PHASAR_LINK_LIBS}) - if(PHASAR_DEBUG_LIBDEPS) - target_link_libraries(${name} LINK_PRIVATE ${lib}) - else() - target_link_libraries(${name} LINK_PUBLIC ${lib}) - endif(PHASAR_DEBUG_LIBDEPS) - endforeach(lib) - endif(PHASAR_LINK_LIBS) - - if(LLVM_LINK_COMPONENTS) - if(USE_LLVM_FAT_LIB) - llvm_config(${name} USE_SHARED ${LLVM_LINK_COMPONENTS}) - else() - llvm_config(${name} ${LLVM_LINK_COMPONENTS}) - endif() - endif(LLVM_LINK_COMPONENTS) + if(PHASAR_DEBUG_LIBDEPS) + target_link_libraries(${name} PRIVATE ${PHASAR_LIB_LINKS}) + else() + target_link_libraries(${name} PUBLIC ${PHASAR_LIB_LINKS}) + endif() + + target_link_libraries(${name} PUBLIC ${PHASAR_LIB_LINK_PUBLIC}) + target_link_libraries(${name} PRIVATE ${PHASAR_LIB_LINK_PRIVATE}) + + phasar_link_llvm(${name} ${PHASAR_LIB_LLVM_LINK_COMPONENTS}) + + target_include_directories(${name} + PUBLIC + $ # The regular include folder + $ # The location of phasar-config.h + ) + + # Set the target property such that installed PhASAR knows where to find its includes (must be relative paths in this case in contrast to non-installed PhASAR!) + set_property(TARGET ${name} APPEND + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $ + ) if(MSVC) get_target_property(cflag ${name} COMPILE_FLAGS) @@ -211,7 +221,7 @@ macro(add_phasar_library name) endif(MSVC) # cut off prefix phasar_ for convenient component names - string(REGEX REPLACE phasar_ "" name component_name) + string(REGEX REPLACE phasar_ "" component_name ${name}) if(PHASAR_IN_TREE) install(TARGETS ${name} @@ -238,32 +248,7 @@ macro(add_phasar_library name) endif() set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS ${name}) -endmacro(add_phasar_library) - -macro(add_phasar_loadable_module name) - set(srcs ${ARGN}) - - # klduge: pass different values for MODULE with multiple targets in same dir - # this allows building shared-lib and module in same dir - # there must be a cleaner way to achieve this.... - if(MODULE) - else() - set(GLOBAL_NOT_MODULE TRUE) - endif() - - set(MODULE TRUE) - add_phasar_library(${name} ${srcs}) - - if(GLOBAL_NOT_MODULE) - unset(MODULE) - endif() - - if(APPLE) - # Darwin-specific linker flags for loadable modules. - set_target_properties(${name} PROPERTIES - LINK_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress") - endif() -endmacro(add_phasar_loadable_module) +endfunction(add_phasar_library) macro(subdirlist result curdir) file(GLOB children RELATIVE ${curdir} ${curdir}/*) diff --git a/config.h.in b/config.h.in index ac0e9c09a..d5df1dd0f 100644 --- a/config.h.in +++ b/config.h.in @@ -1,7 +1,11 @@ -#ifndef __CONFIG_H__ -#define __CONFIG_H__ +#ifndef PHASAR_CONFIG_CONFIG_H +#define PHASAR_CONFIG_CONFIG_H -#define PHASAR_SRC_DIR "@CMAKE_SOURCE_DIR@" -#define PHASAR_BUILD_DIR "@CMAKE_BINARY_DIR@" +#define PHASAR_CONFIG_DIR "@PHASAR_CONFIG_INSTALL_DIR@" -#endif /* __CONFIG_H__ */ +#cmakedefine PAMM_CORE +#cmakedefine PAMM_FULL + +#cmakedefine DYNAMIC_LOG + +#endif /* PHASAR_CONFIG_CONFIG_H */ diff --git a/examples/use-phasar-as-library/CMakeLists.txt b/examples/use-phasar-as-library/CMakeLists.txt index bba4e8e6d..de0f50fd1 100644 --- a/examples/use-phasar-as-library/CMakeLists.txt +++ b/examples/use-phasar-as-library/CMakeLists.txt @@ -7,17 +7,24 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +find_package(phasar COMPONENTS llvm_ifdside REQUIRED) + +# Or without specifying components +# find_package(phasar REQUIRED) # Build a small test tool to show how phasar may be used add_executable(myphasartool myphasartool.cpp ) -find_package(phasar COMPONENTS ifdside REQUIRED) -include_directories(${PHASAR_INCLUDE_DIR}) -link_directories(${PHASAR_LIBRARY_DIR}) +# Old way using phasar_config: +# phasar_config(myphasartool) + +# New way using target_link_libraries: +target_link_libraries(myphasartool phasar::phasar_llvm_ifdside) -phasar_config(myphasartool) +# If find_package did not specify components: +# target_link_libraries(myphasartool phasar::phasar) install(TARGETS myphasartool RUNTIME DESTINATION bin diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt deleted file mode 100644 index 0e8996497..000000000 --- a/include/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(phasar) diff --git a/include/phasar/CMakeLists.txt b/include/phasar/CMakeLists.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/include/phasar/Config/Configuration.h b/include/phasar/Config/Configuration.h index 24db00a2d..86528c338 100644 --- a/include/phasar/Config/Configuration.h +++ b/include/phasar/Config/Configuration.h @@ -28,9 +28,6 @@ #include #include -#define XSTR(S) STR(S) -#define STR(S) #S - namespace psr { class PhasarConfig { diff --git a/include/phasar/ControlFlow/CallGraphBase.h b/include/phasar/ControlFlow/CallGraphBase.h index e2b1e01e5..2f2371618 100644 --- a/include/phasar/ControlFlow/CallGraphBase.h +++ b/include/phasar/ControlFlow/CallGraphBase.h @@ -13,8 +13,6 @@ #include "phasar/Utils/ByRef.h" #include "phasar/Utils/TypeTraits.h" -#include "nlohmann/json.hpp" - namespace psr { template struct CGTraits { // using n_t diff --git a/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h index 518d80c7d..4e05c9279 100644 --- a/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h +++ b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h @@ -92,7 +92,7 @@ template class InterMonoSolver { void addCalleesToWorklist(std::pair Edge) { auto Src = Edge.first; - auto Dst = Edge.second; + // auto Dst = Edge.second; // Add inter- and intra-edges of callee(s) for (auto Callee : ICF->getCalleesOfCallAt(Src)) { if (AddedFunctions.find(Callee) != AddedFunctions.end()) { @@ -362,7 +362,7 @@ template class InterMonoSolver { std::pair Edge = Worklist.front(); Worklist.pop_front(); auto Src = Edge.first; - auto Dst = Edge.second; + // auto Dst = Edge.second; if (ICF->isCallSite(Src)) { addCalleesToWorklist(Edge); } diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index 7ffdfdc2d..b35b3f806 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -10,6 +10,8 @@ #ifndef PHASAR_UTILS_LOGGER_H #define PHASAR_UTILS_LOGGER_H +#include "phasar/Config/phasar-config.h" + #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" // LLVM_UNLIKELY diff --git a/include/phasar/Utils/PAMMMacros.h b/include/phasar/Utils/PAMMMacros.h index f41ef4a0e..cc74e6631 100644 --- a/include/phasar/Utils/PAMMMacros.h +++ b/include/phasar/Utils/PAMMMacros.h @@ -17,6 +17,8 @@ #ifndef PHASAR_UTILS_PAMMMACROS_H_ #define PHASAR_UTILS_PAMMMACROS_H_ +#include "phasar/Config/phasar-config.h" + namespace psr { /// Defines the different level of severity of PAMM's performance evaluation enum class PAMM_SEVERITY_LEVEL { Off = 0, Core, Full }; // NOLINT diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 762735bfe..5bc01ecd2 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -270,19 +270,21 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, } template -LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const T &Value) {} +LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const T & /*Value*/) {} template -LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const std::optional &Value) { +LLVM_ATTRIBUTE_ALWAYS_INLINE void +assertNotNull([[maybe_unused]] const std::optional &Value) { assert(Value.has_value()); } template -LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const T *Value) { +LLVM_ATTRIBUTE_ALWAYS_INLINE void +assertNotNull([[maybe_unused]] const T *Value) { assert(Value != nullptr); } -template void assertAllNotNull(const T &Range) { +template void assertAllNotNull([[maybe_unused]] const T &Range) { assertNotNull(Range); for (const auto &Elem : Range) { assertNotNull(Elem); diff --git a/lib/AnalysisStrategy/CMakeLists.txt b/lib/AnalysisStrategy/CMakeLists.txt index 3b205207d..5bb3d4446 100644 --- a/lib/AnalysisStrategy/CMakeLists.txt +++ b/lib/AnalysisStrategy/CMakeLists.txt @@ -1,28 +1,7 @@ file(GLOB_RECURSE ANALYSIS_STRATEGY_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_db - phasar_controlflow -) - -set(LLVM_LINK_COMPONENTS - Support -) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_analysis_strategy - SHARED - ${ANALYSIS_STRATEGY_SRC} - ) -else() - add_phasar_library(phasar_analysis_strategy - STATIC - ${ANALYSIS_STRATEGY_SRC} - ) -endif() - -set_target_properties(phasar_analysis_strategy - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" +add_phasar_library(phasar_analysis_strategy + ${ANALYSIS_STRATEGY_SRC} + LINKS phasar_db phasar_controlflow + LLVM_LINK_COMPONENTS Support ) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 2045abbfe..cbcfbaa01 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,58 +1,56 @@ add_subdirectory(AnalysisStrategy) add_subdirectory(PhasarLLVM) add_subdirectory(PhasarPass) -add_subdirectory(PhasarClang) add_subdirectory(DB) add_subdirectory(Config) add_subdirectory(Utils) add_subdirectory(Controller) add_subdirectory(Pointer) add_subdirectory(ControlFlow) - -set(PHASAR_LINK_LIBS - phasar_utils - phasar_passes - phasar_config - phasar_db - phasar_pointer - phasar_controlflow - - phasar_llvm_utils - phasar_llvm_db - phasar_llvm_pointer - phasar_llvm_typehierarchy - phasar_llvm_controlflow - - phasar_taintconfig - phasar_mono - phasar_llvm - phasar_llvm_ifdside - phasar_analysis_strategy - phasar_controller - ${Boost_LIBRARIES} -) - -set(LLVM_LINK_COMPONENTS - Core - Support - BitWriter - Analysis - Passes - Demangle -) +if(BUILD_PHASAR_CLANG) + add_subdirectory(PhasarClang) +endif() # The fat lib relies on transitive dependencies... set(PHASAR_DEBUG_LIBDEPS_SAVE ${PHASAR_DEBUG_LIBDEPS}) set(PHASAR_DEBUG_LIBDEPS OFF) -if(BUILD_SHARED_LIBS OR PHASAR_BUILD_DYNLIB) - add_phasar_library(phasar SHARED - LibPhasar.cpp - ) -else() - add_phasar_library(phasar STATIC - LibPhasar.cpp - ) +if(PHASAR_BUILD_DYNLIB) + set(PHASAR_DYNLIB_KIND SHARED) endif() +add_phasar_library(phasar ${PHASAR_DYNLIB_KIND} + FILES + LibPhasar.cpp + LINKS + phasar_utils + phasar_passes + phasar_config + phasar_db + phasar_pointer + phasar_controlflow + + phasar_llvm_utils + phasar_llvm_db + phasar_llvm_pointer + phasar_llvm_typehierarchy + phasar_llvm_controlflow + + phasar_taintconfig + phasar_mono + phasar_llvm + phasar_llvm_ifdside + phasar_analysis_strategy + phasar_controller + LINK_PRIVATE + ${Boost_LIBRARIES} + LLVM_LINK_COMPONENTS + Core + Support + BitWriter + Analysis + Passes + Demangle +) + set(PHASAR_DEBUG_LIBDEPS ${PHASAR_DEBUG_LIBDEPS_SAVE}) diff --git a/lib/Config/CMakeLists.txt b/lib/Config/CMakeLists.txt index 10ae4447d..455fa8fbf 100644 --- a/lib/Config/CMakeLists.txt +++ b/lib/Config/CMakeLists.txt @@ -1,32 +1,8 @@ file(GLOB_RECURSE CONFIG_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_utils -) - -set(LLVM_LINK_COMPONENTS - Support -) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_config - SHARED - ${CONFIG_SRC} - ) -else() - add_phasar_library(phasar_config - STATIC - ${CONFIG_SRC} - ) -endif() - -target_link_libraries(phasar_config - LINK_PUBLIC - ${Boost_LIBRARIES} -) - -set_target_properties(phasar_config - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" +add_phasar_library(phasar_config + ${CONFIG_SRC} + LINKS phasar_utils + LINK_PRIVATE ${Boost_LIBRARIES} + LLVM_LINK_COMPONENTS Support ) diff --git a/lib/Config/Configuration.cpp b/lib/Config/Configuration.cpp index 5ad3665c1..8e9708f94 100644 --- a/lib/Config/Configuration.cpp +++ b/lib/Config/Configuration.cpp @@ -16,6 +16,7 @@ #include "phasar/Config/Configuration.h" +#include "phasar/Config/phasar-config.h" #include "phasar/Utils/ErrorHandling.h" #include "phasar/Utils/IO.h" #include "phasar/Utils/Logger.h" @@ -32,6 +33,9 @@ #include #include +#define XSTR(S) STR(S) +#define STR(S) #S + using namespace psr; namespace psr { @@ -43,10 +47,12 @@ llvm::StringRef PhasarConfig::GlobalConfigurationDirectory() noexcept { return PHASAR_CONFIG_DIR; } -llvm::StringRef PhasarConfig::PhasarDirectory() noexcept { return PHASAR_DIR; } +llvm::StringRef PhasarConfig::PhasarDirectory() noexcept { + return PHASAR_SRC_DIR; +} llvm::StringRef PhasarConfig::DefaultSourceSinkFunctionsPath() noexcept { - return PHASAR_DIR "/config/phasar-source-sink-function.json"; + return PHASAR_SRC_DIR "/config/phasar-source-sink-function.json"; } PhasarConfig::PhasarConfig() { diff --git a/lib/ControlFlow/CMakeLists.txt b/lib/ControlFlow/CMakeLists.txt index b757c3d62..39084cd11 100644 --- a/lib/ControlFlow/CMakeLists.txt +++ b/lib/ControlFlow/CMakeLists.txt @@ -1,26 +1,7 @@ file(GLOB_RECURSE CONTROLFLOW_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS -) - -set(LLVM_LINK_COMPONENTS - Support -) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_controlflow - SHARED - ${CONTROLFLOW_SRC} - ) -else() - add_phasar_library(phasar_controlflow - STATIC - ${CONTROLFLOW_SRC} - ) -endif() - -set_target_properties(phasar_controlflow - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" +add_phasar_library(phasar_controlflow + ${CONTROLFLOW_SRC} + LLVM_LINK_COMPONENTS Support + LINK_PRIVATE nlohmann_json::nlohmann_json ) diff --git a/lib/Controller/CMakeLists.txt b/lib/Controller/CMakeLists.txt index 8b3df9478..dba171b58 100644 --- a/lib/Controller/CMakeLists.txt +++ b/lib/Controller/CMakeLists.txt @@ -1,45 +1,26 @@ file(GLOB_RECURSE CONTROLLER_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_llvm_ifdside - phasar_mono - phasar_llvm_db - phasar_llvm_pointer - phasar_llvm_typehierarchy - phasar_llvm_controlflow - phasar_llvm_utils - phasar_utils - phasar_analysis_strategy - phasar_taintconfig -) - -set(LLVM_LINK_COMPONENTS - Core - Support - Demangle -) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_controller - SHARED +add_phasar_library(phasar_controller + FILES ${CONTROLLER_SRC} - ) -else() - add_phasar_library(phasar_controller - STATIC - ${CONTROLLER_SRC} - ) -endif() -target_link_libraries(phasar_controller - LINK_PUBLIC - curl - ${CMAKE_THREAD_LIBS_INIT} - ${PHASAR_STD_FILESYSTEM} -) + LINKS + phasar_llvm_ifdside + phasar_mono + phasar_llvm_db + phasar_llvm_pointer + phasar_llvm_typehierarchy + phasar_llvm_controlflow + phasar_llvm_utils + phasar_utils + phasar_analysis_strategy + phasar_taintconfig + + LLVM_LINK_COMPONENTS + Core + Support + Demangle -set_target_properties(phasar_controller - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LINK_PRIVATE + ${PHASAR_STD_FILESYSTEM} ) diff --git a/lib/DB/CMakeLists.txt b/lib/DB/CMakeLists.txt index 4579879ce..d5dbf67e1 100644 --- a/lib/DB/CMakeLists.txt +++ b/lib/DB/CMakeLists.txt @@ -1,37 +1,12 @@ file(GLOB_RECURSE DB_SRC *.h *.cpp) -include_directories( - ${SQLITE3_INCLUDE_DIR} +add_phasar_library(phasar_db + ${DB_SRC} + LINKS phasar_passes phasar_utils + LLVM_LINK_COMPONENTS Support + LINK_PRIVATE ${SQLITE3_LIBRARY} ) -set(PHASAR_LINK_LIBS - phasar_passes - phasar_utils -) - -set(LLVM_LINK_COMPONENTS - Support -) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_db - SHARED - ${DB_SRC} - ) -else() - add_phasar_library(phasar_db - STATIC - ${DB_SRC} - ) -endif() - -target_link_libraries(phasar_db - LINK_PUBLIC - ${SQLITE3_LIBRARY} -) - -set_target_properties(phasar_db - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" +target_include_directories(phasar_db + PRIVATE ${SQLITE3_INCLUDE_DIR} ) diff --git a/lib/PhasarClang/CMakeLists.txt b/lib/PhasarClang/CMakeLists.txt index cd6955610..961953ae2 100644 --- a/lib/PhasarClang/CMakeLists.txt +++ b/lib/PhasarClang/CMakeLists.txt @@ -1,37 +1,28 @@ file(GLOB_RECURSE PHASARCLANG_SRC *.h *.cpp) -include_directories(${CLANG_INCLUDE_DIRS}) -set(PHASAR_LINK_LIBS - phasar_utils - phasar_taintconfig -) -set(LLVM_LINK_COMPONENTS - Support - Core - Option -) +add_phasar_library(phasar_clang + ${PHASARCLANG_SRC} + LINKS + phasar_utils + phasar_taintconfig -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_clang - SHARED - ${PHASARCLANG_SRC} - ) -else() - add_phasar_library(phasar_clang - STATIC - ${PHASARCLANG_SRC} - ) -endif() + LLVM_LINK_COMPONENTS + Support + Core + Option -target_link_libraries(phasar_clang LINK_PUBLIC - ${CLANG_LIBRARY} + ${CLANG_LIBRARY} ) -set_target_properties(phasar_clang - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" +target_include_directories(phasar_clang + PUBLIC ${CLANG_INCLUDE_DIRS} ) + +if(PHASAR_IN_TREE) + # Some phasar-clang headers depend on generated files e.g files included from clang/AST/ASTFwd.h + # Make sure, phasar-clang is built *after* these files have been generated + add_dependencies(phasar_clang intrinsics_gen) +endif() diff --git a/lib/PhasarLLVM/CMakeLists.txt b/lib/PhasarLLVM/CMakeLists.txt index 7d446b251..be4adc5e0 100644 --- a/lib/PhasarLLVM/CMakeLists.txt +++ b/lib/PhasarLLVM/CMakeLists.txt @@ -9,26 +9,17 @@ add_subdirectory(Utils) file(GLOB PHASAR_LLVM_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS +add_phasar_library(phasar_llvm + ${PHASAR_LLVM_SRC} + + LINKS + phasar_utils phasar_llvm_pointer phasar_llvm_db phasar_llvm_controlflow phasar_llvm_typehierarchy -) -set(LLVM_LINK_COMPONENTS - Core - Support + LLVM_LINK_COMPONENTS + Core + Support ) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_llvm - SHARED - ${PHASAR_LLVM_SRC} - ) -else() - add_phasar_library(phasar_llvm - STATIC - ${PHASAR_LLVM_SRC} - ) -endif() diff --git a/lib/PhasarLLVM/ControlFlow/CMakeLists.txt b/lib/PhasarLLVM/ControlFlow/CMakeLists.txt index 3f93e7e90..162f9a6cf 100644 --- a/lib/PhasarLLVM/ControlFlow/CMakeLists.txt +++ b/lib/PhasarLLVM/ControlFlow/CMakeLists.txt @@ -1,33 +1,17 @@ file(GLOB_RECURSE CONTROLFLOW_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_llvm_pointer - phasar_llvm_typehierarchy - phasar_db - phasar_utils - phasar_controlflow -) - -set(LLVM_LINK_COMPONENTS - Core - Support - Demangle -) +add_phasar_library(phasar_llvm_controlflow + ${CONTROLFLOW_SRC} -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_llvm_controlflow - SHARED - ${CONTROLFLOW_SRC} - ) -else() - add_phasar_library(phasar_llvm_controlflow - STATIC - ${CONTROLFLOW_SRC} - ) -endif() + LINKS + phasar_llvm_pointer + phasar_llvm_typehierarchy + phasar_db + phasar_utils + phasar_controlflow -set_target_properties(phasar_llvm_controlflow - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LLVM_LINK_COMPONENTS + Core + Support + Demangle ) diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp index b1e99e85d..8fd7621bf 100644 --- a/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp +++ b/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp @@ -94,7 +94,7 @@ auto OTFResolver::resolveVirtualCall(const llvm::CallBase *CallSite) PHASAR_LOG_LEVEL(DEBUG, "Virtual function table entry is: " << VtableIndex); - const llvm::Value *Receiver = CallSite->getArgOperand(0); + // const llvm::Value *Receiver = CallSite->getArgOperand(0); if (CallSite->getCalledOperand() && CallSite->getCalledOperand()->getType()->isPointerTy()) { diff --git a/lib/PhasarLLVM/DB/CMakeLists.txt b/lib/PhasarLLVM/DB/CMakeLists.txt index cda931d3f..5c89b3aa6 100644 --- a/lib/PhasarLLVM/DB/CMakeLists.txt +++ b/lib/PhasarLLVM/DB/CMakeLists.txt @@ -1,31 +1,15 @@ file(GLOB_RECURSE PSR_LLVM_DB_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_db - phasar_utils - phasar_llvm_utils -) - -set(LLVM_LINK_COMPONENTS - Core - Support - IRReader -) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_llvm_db - SHARED - ${PSR_LLVM_DB_SRC} - ) -else() - add_phasar_library(phasar_llvm_db - STATIC - ${PSR_LLVM_DB_SRC} - ) -endif() - -set_target_properties(phasar_llvm_db - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" +add_phasar_library(phasar_llvm_db + ${PSR_LLVM_DB_SRC} + + LINKS + phasar_db + phasar_utils + phasar_llvm_utils + + LLVM_LINK_COMPONENTS + Core + Support + IRReader ) diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt index 7ab2b533a..9411bc739 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/CMakeLists.txt @@ -1,38 +1,24 @@ file(GLOB_RECURSE IFDSIDE_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_config - phasar_utils - phasar_llvm_pointer - phasar_llvm - phasar_llvm_typehierarchy - phasar_llvm_controlflow - phasar_llvm_utils - phasar_db - phasar_taintconfig - ${Boost_LIBRARIES} -) +add_phasar_library(phasar_llvm_ifdside + ${IFDSIDE_SRC} -set(LLVM_LINK_COMPONENTS - Core - Support - Demangle -) + LINKS + phasar_config + phasar_utils + phasar_llvm_pointer + phasar_llvm + phasar_llvm_typehierarchy + phasar_llvm_controlflow + phasar_llvm_utils + phasar_db + phasar_taintconfig -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_llvm_ifdside - SHARED - ${IFDSIDE_SRC} - ) -else() - add_phasar_library(phasar_llvm_ifdside - STATIC - ${IFDSIDE_SRC} - ) -endif() + LLVM_LINK_COMPONENTS + Core + Support + Demangle -set_target_properties(phasar_llvm_ifdside - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LINK_PRIVATE + ${Boost_LIBRARIES} ) diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.cpp index fa57a4022..0a2f03623 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.cpp @@ -36,7 +36,7 @@ BranchSwitchInstFlowFunction::computeTargetsExt(ExtendedValue &Fact) { if (IsConditionTainted) { const auto *const StartBasicBlock = CurrentInst->getParent(); - const auto StartBasicBlockLabel = StartBasicBlock->getName(); + // const auto StartBasicBlockLabel = StartBasicBlock->getName(); LOG_DEBUG("Searching end of block label for: " << StartBasicBlockLabel); diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp index d3a11d09c..ef6999038 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp @@ -354,8 +354,9 @@ AbstractMemoryLocationFactoryBase::withOffsetsImpl( AML->offsets().end()); OffsCpy.back() += Offs.front(); +#ifdef XTAINT_DIAGNOSTICS bool IsOverApproximating = false; - +#endif if (NwLifetime < Offs.size() - 1) { Offs = Offs.slice(0, NwLifetime + 1); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp index 02c08a309..d3dd8fd76 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @@ -695,7 +695,7 @@ auto IDEExtendedTaintAnalysis::getSummaryEdgeFunction(n_t Curr, d_t CurrNode, d_t SuccNode) -> EdgeFunctionType { - const auto *Call = llvm::cast(Curr); + // const auto *Call = llvm::cast(Curr); if (isZeroValue(CurrNode) && !isZeroValue(SuccNode)) { return GenEdgeFunction{nullptr}; diff --git a/lib/PhasarLLVM/DataFlow/Mono/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/Mono/CMakeLists.txt index 9c11f2066..7c7d00bf9 100644 --- a/lib/PhasarLLVM/DataFlow/Mono/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/Mono/CMakeLists.txt @@ -1,33 +1,17 @@ file(GLOB_RECURSE MONO_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_config - phasar_utils - phasar_llvm_utils - phasar_llvm_controlflow - phasar_db - phasar_taintconfig -) - -set(LLVM_LINK_COMPONENTS - Core - Support -) +add_phasar_library(phasar_mono + ${MONO_SRC} -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_mono - SHARED - ${MONO_SRC} - ) -else() - add_phasar_library(phasar_mono - STATIC - ${MONO_SRC} - ) -endif() + LINKS + phasar_config + phasar_utils + phasar_llvm_utils + phasar_llvm_controlflow + phasar_db + phasar_taintconfig -set_target_properties(phasar_mono - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LLVM_LINK_COMPONENTS + Core + Support ) diff --git a/lib/PhasarLLVM/Passes/CMakeLists.txt b/lib/PhasarLLVM/Passes/CMakeLists.txt index f40831353..10c71117e 100644 --- a/lib/PhasarLLVM/Passes/CMakeLists.txt +++ b/lib/PhasarLLVM/Passes/CMakeLists.txt @@ -1,34 +1,14 @@ file(GLOB_RECURSE PASSES_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_utils -) - -set(LLVM_LINK_COMPONENTS - Core - Support - Analysis - Demangle -) +add_phasar_library(phasar_passes + ${PASSES_SRC} -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_passes - SHARED - ${PASSES_SRC} - ) -else() - add_phasar_library(phasar_passes - STATIC - ${PASSES_SRC} - ) -endif() - -target_link_libraries(phasar_passes - LINK_PUBLIC -) + LINKS + phasar_utils -set_target_properties(phasar_passes - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LLVM_LINK_COMPONENTS + Core + Support + Analysis + Demangle ) diff --git a/lib/PhasarLLVM/Pointer/CMakeLists.txt b/lib/PhasarLLVM/Pointer/CMakeLists.txt index b01e8274d..c189f6153 100644 --- a/lib/PhasarLLVM/Pointer/CMakeLists.txt +++ b/lib/PhasarLLVM/Pointer/CMakeLists.txt @@ -1,42 +1,22 @@ file(GLOB_RECURSE POINTER_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_utils - phasar_db - phasar_pointer - phasar_llvm_utils - phasar_llvm_db -) - -set(LLVM_LINK_COMPONENTS - Core - Support - Analysis - Passes - Demangle -) +add_phasar_library(phasar_llvm_pointer + ${POINTER_SRC} -# Handle the library files -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_llvm_pointer - SHARED - ${POINTER_SRC} - ) -else() - add_phasar_library(phasar_llvm_pointer - STATIC - ${POINTER_SRC} - ) -endif() + LINKS + phasar_utils + phasar_db + phasar_pointer + phasar_llvm_utils + phasar_llvm_db -find_package(Boost COMPONENTS graph REQUIRED) -target_link_libraries(phasar_llvm_pointer - LINK_PUBLIC - ${Boost_LIBRARIES} -) + LLVM_LINK_COMPONENTS + Core + Support + Analysis + Passes + Demangle -set_target_properties(phasar_llvm_pointer - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LINK_PRIVATE + ${Boost_LIBRARIES} ) diff --git a/lib/PhasarLLVM/TaintConfig/CMakeLists.txt b/lib/PhasarLLVM/TaintConfig/CMakeLists.txt index 81d9ad6a8..1a801938f 100644 --- a/lib/PhasarLLVM/TaintConfig/CMakeLists.txt +++ b/lib/PhasarLLVM/TaintConfig/CMakeLists.txt @@ -1,38 +1,19 @@ file(GLOB_RECURSE TAINTCONFIG_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_utils - phasar_db - phasar_llvm_db - phasar_llvm_utils - phasar_controlflow - phasar_llvm_controlflow -) - -set(LLVM_LINK_COMPONENTS - Core - Support -) +add_phasar_library(phasar_taintconfig + ${TAINTCONFIG_SRC} -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_taintconfig - SHARED - ${TAINTCONFIG_SRC} - ) -else() - add_phasar_library(phasar_taintconfig - STATIC - ${TAINTCONFIG_SRC} - ) -endif() + LINKS + phasar_utils + phasar_db + phasar_llvm_db + phasar_llvm_utils + phasar_controlflow + phasar_llvm_controlflow -target_link_libraries(phasar_taintconfig - LINK_PUBLIC - nlohmann_json_schema_validator -) + nlohmann_json_schema_validator -set_target_properties(phasar_taintconfig - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LLVM_LINK_COMPONENTS + Core + Support ) diff --git a/lib/PhasarLLVM/TypeHierarchy/CMakeLists.txt b/lib/PhasarLLVM/TypeHierarchy/CMakeLists.txt index 1094db186..3c3d86078 100644 --- a/lib/PhasarLLVM/TypeHierarchy/CMakeLists.txt +++ b/lib/PhasarLLVM/TypeHierarchy/CMakeLists.txt @@ -1,37 +1,18 @@ file(GLOB_RECURSE TYPEHIERARCHY_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_utils -) - -set(LLVM_LINK_COMPONENTS - Core - Demangle - Support - Analysis -) - # Handle the library files -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_llvm_typehierarchy - SHARED - ${TYPEHIERARCHY_SRC} - ) -else() - add_phasar_library(phasar_llvm_typehierarchy - STATIC - ${TYPEHIERARCHY_SRC} - ) -endif() +add_phasar_library(phasar_llvm_typehierarchy + ${TYPEHIERARCHY_SRC} -find_package(Boost COMPONENTS graph REQUIRED) -target_link_libraries(phasar_llvm_typehierarchy - LINK_PUBLIC - ${Boost_LIBRARIES} -) + LINKS + phasar_utils + + LLVM_LINK_COMPONENTS + Core + Demangle + Support + Analysis -set_target_properties(phasar_llvm_typehierarchy - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LINK_PRIVATE + ${Boost_LIBRARIES} ) diff --git a/lib/PhasarLLVM/Utils/CMakeLists.txt b/lib/PhasarLLVM/Utils/CMakeLists.txt index 6c05a4112..b88ee9d75 100644 --- a/lib/PhasarLLVM/Utils/CMakeLists.txt +++ b/lib/PhasarLLVM/Utils/CMakeLists.txt @@ -1,36 +1,15 @@ file(GLOB_RECURSE UTILS_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_config - phasar_utils -) - -set(LLVM_LINK_COMPONENTS - Core - Support - BitWriter - Demangle -) - -# Handle the library files -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_llvm_utils - SHARED - ${UTILS_SRC} - ) -else() - add_phasar_library(phasar_llvm_utils - STATIC - ${UTILS_SRC} - ) -endif() - -target_link_libraries(phasar_llvm_utils - LINK_PUBLIC -) - -set_target_properties(phasar_llvm_utils - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" +add_phasar_library(phasar_llvm_utils + ${UTILS_SRC} + + LINKS + phasar_config + phasar_utils + + LLVM_LINK_COMPONENTS + Core + Support + BitWriter + Demangle ) diff --git a/lib/PhasarPass/CMakeLists.txt b/lib/PhasarPass/CMakeLists.txt index cec9dc7b5..dd4dff3cb 100644 --- a/lib/PhasarPass/CMakeLists.txt +++ b/lib/PhasarPass/CMakeLists.txt @@ -1,48 +1,28 @@ file(GLOB_RECURSE PHASARPASS_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_config - phasar_llvm_controlflow - phasar_llvm_db - phasar_llvm_ifdside - phasar_mono - phasar_passes - phasar_llvm_utils - phasar_llvm_pointer - phasar_llvm_typehierarchy - phasar_utils -) +# We specifically link internal phasar libs into phasar_pass so on that the +# llvm user side only has to specify one library. -set(LLVM_LINK_COMPONENTS - Core - Support -) +add_phasar_library(phasar_pass + ${PHASARPASS_SRC} -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_pass - SHARED - ${PHASARPASS_SRC} - ) -else() - add_phasar_library(phasar_pass - STATIC - ${PHASARPASS_SRC} - ) -endif() + LINKS + phasar_config + phasar_llvm_controlflow + phasar_llvm_db + phasar_llvm_ifdside + phasar_mono + phasar_passes + phasar_llvm_utils + phasar_llvm_pointer + phasar_llvm_typehierarchy + phasar_utils -# We specifically link internal phasar libs into phasar_pass so on that the -# llvm user side only has to specify one library. + LLVM_LINK_COMPONENTS + Core + Support -find_package(Boost COMPONENTS graph REQUIRED) -target_link_libraries(phasar_pass LINK_PUBLIC - ${CMAKE_THREAD_LIBS_INIT} - ${PHASAR_LINK_LIBS} - ${Boost_LIBRARIES} -) - -set_target_properties(phasar_pass - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} ) diff --git a/lib/PhasarPass/PhasarPass.cpp b/lib/PhasarPass/PhasarPass.cpp index dc90da2f9..d16a1fb78 100644 --- a/lib/PhasarPass/PhasarPass.cpp +++ b/lib/PhasarPass/PhasarPass.cpp @@ -64,7 +64,7 @@ bool PhasarPass::runOnModule(llvm::Module &M) { CallGraphAnalysisType CGTy = toCallGraphAnalysisType(CallGraphAnalysis); LLVMTypeHierarchy H(DB); LLVMAliasSet PT(&DB); - LLVMBasedCFG CFG; + // LLVMBasedCFG CFG; LLVMBasedICFG I(&DB, CGTy, EntryPoints, &H, &PT); if (DataFlowAnalysis == "ifds-solvertest") { IFDSSolverTest IFDSTest(&DB, EntryPoints); diff --git a/lib/Pointer/CMakeLists.txt b/lib/Pointer/CMakeLists.txt index 791168961..5c2f8d43e 100644 --- a/lib/Pointer/CMakeLists.txt +++ b/lib/Pointer/CMakeLists.txt @@ -1,29 +1,13 @@ file(GLOB_RECURSE POINTER_SRC *.h *.cpp) -set(PHASAR_LINK_LIBS - phasar_utils - phasar_db -) - -set(LLVM_LINK_COMPONENTS - Support -) - # Handle the library files -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_pointer - SHARED - ${POINTER_SRC} - ) -else() - add_phasar_library(phasar_pointer - STATIC - ${POINTER_SRC} - ) -endif() +add_phasar_library(phasar_pointer + ${POINTER_SRC} + + LINKS + phasar_utils + phasar_db -set_target_properties(phasar_pointer - PROPERTIES - LINKER_LANGUAGE CXX - PREFIX "lib" + LLVM_LINK_COMPONENTS + Support ) diff --git a/lib/Pointer/PointsToInfo.cpp b/lib/Pointer/PointsToInfo.cpp index 3f7678e0b..b690be3c0 100644 --- a/lib/Pointer/PointsToInfo.cpp +++ b/lib/Pointer/PointsToInfo.cpp @@ -137,12 +137,14 @@ class DummyFieldSensitivePointsToAnalysis [[maybe_unused]] void testTypeErasure() { DummyFieldInsensitivePointsToAnalysis PTA1; - PointsToInfoRef> + [[maybe_unused]] PointsToInfoRef< + PointsToTraits> TEPTA1 = &PTA1; DummyFieldSensitivePointsToAnalysis PTA2; - PointsToInfoRef> TEPTA2 = - &PTA2; + [[maybe_unused]] PointsToInfoRef< + PointsToTraits> + TEPTA2 = &PTA2; PointsToInfo> TEPTA3( std::in_place_type); diff --git a/lib/Utils/CMakeLists.txt b/lib/Utils/CMakeLists.txt index e8d429fc8..c10569663 100644 --- a/lib/Utils/CMakeLists.txt +++ b/lib/Utils/CMakeLists.txt @@ -6,35 +6,19 @@ if(PHASAR_ENABLE_PAMM STREQUAL "Off" AND NOT PHASAR_BUILD_UNITTESTS) list(REMOVE_ITEM UTILS_SRC ${pamm_src}) endif() -set(PHASAR_LINK_LIBS -) - -set(LLVM_LINK_COMPONENTS - Core - Support - BitWriter - Demangle -) - -if(BUILD_SHARED_LIBS) - add_phasar_library(phasar_utils - SHARED - ${UTILS_SRC} - ) -else() - add_phasar_library(phasar_utils - STATIC - ${UTILS_SRC} - ) -endif() +add_phasar_library(phasar_utils + ${UTILS_SRC} -target_include_directories(phasar_utils PUBLIC ${LLVM_INCLUDE_DIRS}) + LLVM_LINK_COMPONENTS + Core + Support + BitWriter + Demangle -target_link_libraries(phasar_utils + LINK_PRIVATE + ${PHASAR_STD_FILESYSTEM} LINK_PUBLIC - ${CMAKE_DL_LIBS} - ${Boost_LIBRARIES} - ${PHASAR_STD_FILESYSTEM} + nlohmann_json::nlohmann_json ) set_target_properties(phasar_utils diff --git a/tools/example-tool/CMakeLists.txt b/tools/example-tool/CMakeLists.txt index aab2a9a7d..e4d397e70 100644 --- a/tools/example-tool/CMakeLists.txt +++ b/tools/example-tool/CMakeLists.txt @@ -12,14 +12,11 @@ else() endif() target_link_libraries(myphasartool - LINK_PUBLIC - phasar - LINK_PRIVATE - ${PHASAR_STD_FILESYSTEM} + PRIVATE + phasar + ${PHASAR_STD_FILESYSTEM} ) install(TARGETS myphasartool RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib ) diff --git a/tools/phasar-cli/CMakeLists.txt b/tools/phasar-cli/CMakeLists.txt index f696adea4..a20a7d6a8 100644 --- a/tools/phasar-cli/CMakeLists.txt +++ b/tools/phasar-cli/CMakeLists.txt @@ -23,26 +23,22 @@ endif() # Warning! There is a another listing of libraries inside cmake/phasar_macros.cmake. # If this list is altered the other one should be altered accordingly. target_link_libraries(phasar-cli - LINK_PUBLIC - phasar_config - phasar_controller - phasar_llvm_controlflow - phasar_llvm_utils - phasar_analysis_strategy - phasar_llvm_ifdside - phasar_utils - phasar_mono - phasar_llvm_db - phasar_passes - phasar_llvm_pointer - phasar_llvm - phasar_llvm_typehierarchy - ${SQLITE3_LIBRARY} - ${Boost_LIBRARIES} - ${CMAKE_DL_LIBS} - ${CMAKE_THREAD_LIBS_INIT} - LINK_PRIVATE - ${PHASAR_STD_FILESYSTEM} + PRIVATE + phasar_config + phasar_controller + phasar_llvm_controlflow + phasar_llvm_utils + phasar_analysis_strategy + phasar_llvm_ifdside + phasar_utils + phasar_mono + phasar_llvm_db + phasar_passes + phasar_llvm_pointer + phasar_llvm + phasar_llvm_typehierarchy + + ${PHASAR_STD_FILESYSTEM} ) if (NOT PHASAR_IN_TREE) diff --git a/tools/phasar-cli/phasar-cli.cpp b/tools/phasar-cli/phasar-cli.cpp index ef221b8cd..c9c20f629 100644 --- a/tools/phasar-cli/phasar-cli.cpp +++ b/tools/phasar-cli/phasar-cli.cpp @@ -366,7 +366,7 @@ int main(int Argc, const char **Argv) { validateParamAnalysisConfig(); validatePTAJsonFile(); - auto &PConfig = PhasarConfig::getPhasarConfig(); + [[maybe_unused]] auto &PConfig = PhasarConfig::getPhasarConfig(); // setup the emitter options to display the computed analysis results auto EmitterOptions = AnalysisControllerEmitterOptions::None; diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index b30f77c73..931faf8a9 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -23,6 +23,8 @@ endfunction() include_directories(TestUtils) add_subdirectory(DB) -add_subdirectory(PhasarClang) add_subdirectory(PhasarLLVM) add_subdirectory(Utils) +if(BUILD_PHASAR_CLANG) + add_subdirectory(PhasarClang) +endif() diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/CMakeLists.txt index 23d61519b..708ce3bcb 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/CMakeLists.txt @@ -1,33 +1,4 @@ -if(PHASAR_BUILD_OPENSSL_TS_UNITTESTS) - set(IfdsIdeProblemSources - IFDSConstAnalysisTest.cpp - IFDSTaintAnalysisTest.cpp - IDEInstInteractionAnalysisTest.cpp - IDELinearConstantAnalysisTest.cpp - IDELinearConstantAnalysis_DotTest.cpp - IDETSAnalysisFileIOTest.cpp - IDETSAnalysisOpenSSLEVPKDFTest.cpp - IDETSAnalysisOpenSSLSecureHeapTest.cpp - IDETSAnalysisOpenSSLSecureMemoryTest.cpp - IFDSUninitializedVariablesTest.cpp - IDEExtendedTaintAnalysisTest.cpp - IDEGeneralizedLCATest.cpp - ) -elseif(BUILD_SWIFT_TESTS) - set(IfdsIdeProblemSources - IFDSConstAnalysisTest.cpp - IFDSTaintAnalysisTest.cpp - IDEInstInteractionAnalysisTest.cpp - IDELinearConstantAnalysisTest.cpp - IDELinearConstantAnalysis_DotTest.cpp - IFDSUninitializedVariablesTest.cpp - IDEGeneralizedLCATest.cpp - IDEExtendedTaintAnalysisTest.cpp - IDETSAnalysisFileIOTest.cpp - IDELinearConstantAnalysisSwiftTest.cpp - ) - else() - set(IfdsIdeProblemSources +set(IfdsIdeProblemSources IFDSConstAnalysisTest.cpp IFDSTaintAnalysisTest.cpp IDEInstInteractionAnalysisTest.cpp @@ -37,8 +8,21 @@ elseif(BUILD_SWIFT_TESTS) IDEGeneralizedLCATest.cpp IDEExtendedTaintAnalysisTest.cpp IDETSAnalysisFileIOTest.cpp - ) -endif(PHASAR_BUILD_OPENSSL_TS_UNITTESTS) +) + +if(PHASAR_BUILD_OPENSSL_TS_UNITTESTS) + list(APPEND IfdsIdeProblemSources + IDETSAnalysisOpenSSLEVPKDFTest.cpp + IDETSAnalysisOpenSSLSecureHeapTest.cpp + IDETSAnalysisOpenSSLSecureMemoryTest.cpp + ) +endif() + +if(BUILD_SWIFT_TESTS) + list(APPEND IfdsIdeProblemSources + IDELinearConstantAnalysisSwiftTest.cpp + ) +endif() test_require_config_file("DOTGraphConfig.json") diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp index 61a7912d4..8f14daced 100644 --- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp +++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp @@ -9,7 +9,6 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "TestConfig.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" #include diff --git a/unittests/PhasarLLVM/Pointer/LLVMAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/LLVMAliasSetTest.cpp index 3cac284a2..b6144d68b 100644 --- a/unittests/PhasarLLVM/Pointer/LLVMAliasSetTest.cpp +++ b/unittests/PhasarLLVM/Pointer/LLVMAliasSetTest.cpp @@ -21,7 +21,7 @@ TEST(LLVMAliasSet, Intra_01) { const auto *Main = IRDB.getFunctionDefinition("main"); for (const auto &BB : *Main) { for (const auto &I : BB) { - auto S = PTS.getAliasSet(&I); // NOLINT + std::ignore = PTS.getAliasSet(&I); // NOLINT } } PTS.print(llvm::outs()); @@ -37,7 +37,7 @@ TEST(LLVMAliasSet, Inter_01) { const auto *Main = IRDB.getFunctionDefinition("main"); for (const auto &BB : *Main) { for (const auto &I : BB) { - auto S = PTS.getAliasSet(&I); // NOLINT + std::ignore = PTS.getAliasSet(&I); // NOLINT } } PTS.print(llvm::outs()); @@ -53,11 +53,11 @@ TEST(LLVMAliasSet, Global_01) { LLVMBasedICFG ICF(&IRDB, CallGraphAnalysisType::OTF, {"main"}, &TH, &PTS); const auto *Main = IRDB.getFunctionDefinition("main"); for (const auto &G : Main->getParent()->globals()) { - auto S = PTS.getAliasSet(&G); // NOLINT + std::ignore = PTS.getAliasSet(&G); // NOLINT } for (const auto &BB : *Main) { for (const auto &I : BB) { - auto S = PTS.getAliasSet(&I); // NOLINT + std::ignore = PTS.getAliasSet(&I); // NOLINT } } PTS.print(llvm::outs()); diff --git a/unittests/TestUtils/TestConfig.h b/unittests/TestUtils/TestConfig.h index a58bc45ae..e162b619b 100644 --- a/unittests/TestUtils/TestConfig.h +++ b/unittests/TestUtils/TestConfig.h @@ -1,7 +1,9 @@ #ifndef UNITTEST_TESTUTILS_TESTCONFIG_H_ #define UNITTEST_TESTUTILS_TESTCONFIG_H_ -#include "phasar/Config/Configuration.h" +#include "phasar/Config/phasar-config.h" + +#include "llvm/ADT/StringRef.h" #include "gtest/gtest.h" @@ -10,19 +12,19 @@ namespace psr::unittest { static constexpr llvm::StringLiteral PathToLLTestFiles = - PHASAR_DIR "/build/test/llvm_test_code/"; + PHASAR_BUILD_DIR "/test/llvm_test_code/"; static constexpr llvm::StringLiteral PathToTxtTestFiles = - PHASAR_DIR "/build/test/text_test_code/"; + PHASAR_BUILD_DIR "/test/text_test_code/"; static constexpr llvm::StringLiteral PathToJSONTestFiles = - PHASAR_DIR "/test/json_test_code/"; + PHASAR_SRC_DIR "/test/json_test_code/"; #define PHASAR_BUILD_SWIFT_SUBFOLDER(SUB) \ - llvm::StringLiteral(PHASAR_DIR "/build/test/llvm_swift_test_code/" SUB) + llvm::StringLiteral(PHASAR_BUILD_DIR "/test/llvm_swift_test_code/" SUB) #define PHASAR_BUILD_SUBFOLDER(SUB) \ - llvm::StringLiteral(PHASAR_DIR "/build/test/llvm_test_code/" SUB) + llvm::StringLiteral(PHASAR_BUILD_DIR "/test/llvm_test_code/" SUB) // Remove wrapped tests in case GTEST_SKIP is not available. This is needed as // LLVM currently ships with an older version of gtest (<1.10.0) that does not diff --git a/unittests/Utils/EquivalenceClassMapTest.cpp b/unittests/Utils/EquivalenceClassMapTest.cpp index c712615ad..04c641324 100644 --- a/unittests/Utils/EquivalenceClassMapTest.cpp +++ b/unittests/Utils/EquivalenceClassMapTest.cpp @@ -59,7 +59,7 @@ TEST(EquivalenceClassMap, insertKeyRef) { int Key = 42; const MapTy::key_type &KeyRef = Key; - M.insert(42, "foo"); + M.insert(KeyRef, "foo"); EXPECT_EQ(M.findValue(42), "foo"); } diff --git a/utils/InstallAptDependencies.sh b/utils/InstallAptDependencies.sh index 496c879f4..37bc530c6 100755 --- a/utils/InstallAptDependencies.sh +++ b/utils/InstallAptDependencies.sh @@ -1,6 +1,6 @@ #!/bin/bash set -e -sudo apt update -sudo apt install git -y -sudo apt install zlib1g-dev sqlite3 libsqlite3-dev bear python3 doxygen graphviz python3-pip libxml2 libxml2-dev libncurses5-dev libncursesw5-dev swig build-essential g++ libz3-dev libedit-dev python3-sphinx libomp-dev libcurl4-openssl-dev ninja-build -y +sudo apt-get update +sudo apt-get install git -y +sudo apt-get install zlib1g-dev sqlite3 libsqlite3-dev python3 doxygen python3-pip g++ ninja-build cmake -y diff --git a/utils/install-llvm.sh b/utils/install-llvm.sh index 943b3c211..aff717a8b 100755 --- a/utils/install-llvm.sh +++ b/utils/install-llvm.sh @@ -15,7 +15,7 @@ readonly dest_dir="${3}" readonly llvm_release="${4}" if [ "$#" -ne 4 ] || ! [[ "$num_cores" =~ ${re_number} ]] || ! [ -d "${build_dir}" ] || ! [[ "${llvm_release}" =~ ${re_llvm_release} ]]; then - echo "usage: <# cores> " >&2 + echo "usage: <# cores> " >&2 exit 1 fi @@ -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' -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_RUNTIMES='libcxx;libcxxabi;libunwind' -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;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 ../llvm cmake --build . echo "Installing LLVM to ${dest_dir}" From 02e832d6ad9c00a25d5f26b57eea2b46bd8a5533 Mon Sep 17 00:00:00 2001 From: Mingjie Shen Date: Tue, 7 Nov 2023 12:52:24 -0500 Subject: [PATCH 38/59] Fix unexpected subshell execution in bootstrap.sh (#678) For `(list)` in bash, `list` is executed in a subshell environment. Variable assignments do not remain in effect after the command completes. Fix by using `{ list; }`, where `list` is executed in the current shell environment. --- bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index 9e615a1b3..2caf67eea 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -108,7 +108,7 @@ if [ ! -z "${DESIRED_BOOST_DIR}" ]; then else # New way of installing boost: # Check whether we have the required boost packages installed - (BOOST_VERSION=$(echo -e '#include \nBOOST_LIB_VERSION' | gcc -s -x c++ -E - 2>/dev/null| grep "^[^#;]" | tr -d '\"')) || true + { BOOST_VERSION=$(echo -e '#include \nBOOST_LIB_VERSION' | gcc -s -x c++ -E - 2>/dev/null| grep "^[^#;]" | tr -d '\"'); } || true if [ -z "$BOOST_VERSION" ] ;then if [ -x "$(command -v pacman)" ]; then From 5ddab3f2ebfb7b289657937928ba45eb95cbf9fe Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Wed, 15 Nov 2023 09:13:23 +0100 Subject: [PATCH 39/59] CallBase Called Function getName Null Check (#680) * Null checking getCalledFunction() when calling getName() * minor * pre-commit --------- Co-authored-by: SanthoshMohan --- .../IfdsIde/Problems/IDESecureHeapPropagation.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp index a06853787..225b701fa 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp @@ -87,9 +87,10 @@ IDESecureHeapPropagation::getCallToRetFlowFunction( // Change to CallSite everywhere const auto *CS = llvm::cast(CallSite); - auto FName = CS->getCalledFunction()->getName(); - if (FName == InitializerFn) { - return generateFromZero(SecureHeapFact::INITIALIZED); + if (const auto *Callee = CS->getCalledFunction()) { + if (Callee->getName() == InitializerFn) { + return generateFromZero(SecureHeapFact::INITIALIZED); + } } return identityFlow(); } @@ -147,7 +148,7 @@ IDESecureHeapPropagation::getCallToRetEdgeFunction( return SHPGenEdgeFn{l_t::INITIALIZED}; } const auto *CS = llvm::cast(CallSite); - if (CallNode != ZeroValue && + if (CallNode != ZeroValue && CS->getCalledFunction() && CS->getCalledFunction()->getName() == ShutdownFn) { // std::cerr << "Kill at " << llvmIRToShortString(callSite) << std::endl; return SHPGenEdgeFn{l_t::BOT}; From 659cb8d2598bf87458fd92ada4641ce687a19ab2 Mon Sep 17 00:00:00 2001 From: Martin Mory Date: Fri, 17 Nov 2023 18:39:11 +0100 Subject: [PATCH 40/59] Fix global handling in type state analysis (#651) * fix global handling in type state analysis * Fix error due to update from dev * fix killing of globals: only kill if no declaration-only func is called --------- Co-authored-by: Martin Mory Co-authored-by: Fabian Schiebel --- .../DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp index 3f20b5d97..8b2dfdcf9 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp @@ -182,6 +182,7 @@ auto IDETypeStateAnalysisBase::getCallToRetFlowFunction( n_t CallSite, n_t /*RetSite*/, llvm::ArrayRef Callees) -> FlowFunctionPtrType { const auto *CS = llvm::cast(CallSite); + bool DeclarationOnlyCalleeFound = false; for (const auto *Callee : Callees) { std::string DemangledFname = llvm::demangle(Callee->getName().str()); // Generate the return value of factory functions from zero value @@ -189,6 +190,8 @@ auto IDETypeStateAnalysisBase::getCallToRetFlowFunction( return this->generateFromZero(CS); } + DeclarationOnlyCalleeFound |= Callee->isDeclaration(); + /// XXX: Revisit this: // Handle all functions that are not modeld with special semantics. @@ -209,6 +212,10 @@ auto IDETypeStateAnalysisBase::getCallToRetFlowFunction( } } } + if (!DeclarationOnlyCalleeFound) { + return killFlowIf( + [](d_t Source) { return llvm::isa(Source); }); + } return identityFlow(); } From ae8c1610e7b395ad0985c995e1277b5d8dee93d7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:07:53 +0100 Subject: [PATCH 41/59] Use the ASAN API to better communicate to the sanitizer, what memory regions should actually be valid (#670) Co-authored-by: Martin Mory --- .../AbstractMemoryLocationFactory.h | 3 ++- include/phasar/Utils/StableVector.h | 18 +++++++++++++++++- .../AbstractMemoryLocationFactory.cpp | 18 +++++++++++++++--- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h index 6b6066989..a492bdd6a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h @@ -41,7 +41,7 @@ class AbstractMemoryLocationFactoryBase { Block *Next = nullptr; static Block *create(Block *Next, size_t NumPointerEntries); - static void destroy(Block *Blck); + static void destroy(Block *Blck, size_t NumPointerEntries); private: Block(Block *Next); @@ -49,6 +49,7 @@ class AbstractMemoryLocationFactoryBase { Block *Root = nullptr; void **Pos = nullptr, **End = nullptr; + size_t InitialCapacity{}; Allocator() noexcept = default; Allocator(size_t InitialCapacity); diff --git a/include/phasar/Utils/StableVector.h b/include/phasar/Utils/StableVector.h index 168972d19..68102efd3 100644 --- a/include/phasar/Utils/StableVector.h +++ b/include/phasar/Utils/StableVector.h @@ -11,6 +11,7 @@ #define PHASAR_UTILS_STABLEVECTOR_H_ #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -197,6 +198,8 @@ class StableVector { Start = Blck; End = Blck + Cap; Pos = Blck + (Other.Pos - Other.Start); + + __asan_poison_memory_region(Pos, (End - Pos) * sizeof(T)); } void swap(StableVector &Other) noexcept { @@ -244,6 +247,7 @@ class StableVector { std::destroy(Start, Pos); for (size_t I = BlockIdx; I < Blocks.size(); ++I) { + __asan_unpoison_memory_region(Blocks[I], Cap * sizeof(T)); std::allocator_traits::deallocate(Alloc, Blocks[I], Cap); Cap = TotalSize; @@ -263,6 +267,7 @@ class StableVector { } auto Ret = Pos; + __asan_unpoison_memory_region(Ret, sizeof(T)); std::allocator_traits::construct( Alloc, Ret, std::forward(Args)...); ++Pos; @@ -343,6 +348,8 @@ class StableVector { assert(!empty() && "Do not call pop_back() on an empty StableVector!"); std::destroy_at(--Pos); + __asan_poison_memory_region(Pos, sizeof(T)); + --Size; if (Pos != Start) { return; @@ -374,11 +381,13 @@ class StableVector { for (size_t I = 0; I < BlockIdx; ++I) { std::destroy_n(Blocks[I], Cap); + __asan_poison_memory_region(Blocks[I], Cap * sizeof(T)); Cap = TotalSize; TotalSize += Cap; } std::destroy(Start, Pos); + __asan_poison_memory_region(Start, (Pos - Start) * sizeof(T)); BlockIdx = 0; Size = 0; if (!Blocks.empty()) { @@ -399,10 +408,12 @@ class StableVector { Pos -= N; Size -= N; std::destroy_n(Pos, N); + __asan_poison_memory_region(Pos, N * sizeof(T)); return; } std::destroy(Start, Pos); + __asan_poison_memory_region(Start, (Pos - Start) * sizeof(T)); Size -= NumElementsInCurrBlock; N -= NumElementsInCurrBlock; @@ -429,6 +440,7 @@ class StableVector { if (Size == 0) { assert(BlockIdx == 0); + __asan_unpoison_memory_region(Blocks[0], InitialCapacity * sizeof(T)); std::allocator_traits::deallocate(Alloc, Blocks[0], InitialCapacity); } @@ -437,6 +449,7 @@ class StableVector { for (size_t I = BlockIdx + 1, BlocksEnd = Blocks.size(); I < BlocksEnd; ++I) { + __asan_unpoison_memory_region(Blocks[I], Cap * sizeof(T)); std::allocator_traits::deallocate(Alloc, Blocks[I], Cap); Cap <<= 1; } @@ -491,7 +504,9 @@ class StableVector { template [[nodiscard]] T &growAndEmplace(ArgTys &&...Args) { auto makeBlock = [this](size_t N) { - return std::allocator_traits::allocate(Alloc, N); + auto *Ret = std::allocator_traits::allocate(Alloc, N); + __asan_poison_memory_region(std::next(Ret), (N - 1) * sizeof(T)); + return Ret; }; if (Blocks.empty()) { @@ -501,6 +516,7 @@ class StableVector { assert(llvm::isPowerOf2_64(Size)); BlockIdx++; End = Blocks[BlockIdx] + Size; + __asan_unpoison_memory_region(Blocks[BlockIdx], sizeof(T)); } else { assert(llvm::isPowerOf2_64(Size)); BlockIdx++; diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp index ef6999038..6baa82949 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.cpp @@ -39,10 +39,17 @@ auto AbstractMemoryLocationFactoryBase::Allocator::Block::create( alignof(AbstractMemoryLocationImpl)}) size_t[1 + NumPointerEntries]); new (Ret) Block(Next); + + __asan_poison_memory_region(Ret->getTrailingObjects(), + NumPointerEntries * sizeof(void *)); + return Ret; } -void AbstractMemoryLocationFactoryBase::Allocator::Block::destroy(Block *Blck) { +void AbstractMemoryLocationFactoryBase::Allocator::Block::destroy( + Block *Blck, [[maybe_unused]] size_t NumPointerEntries) { + __asan_unpoison_memory_region(Blck->getTrailingObjects(), + NumPointerEntries * sizeof(void *)); ::operator delete[](Blck, std::align_val_t{alignof(AbstractMemoryLocationImpl)}); } @@ -61,10 +68,13 @@ AbstractMemoryLocationFactoryBase::Allocator::Allocator( } AbstractMemoryLocationFactoryBase::Allocator::~Allocator() { - auto *Blck = Root; + auto *Rt = Root; + auto *Blck = Rt; while (Blck) { auto *Nxt = Blck->Next; - Block::destroy(Blck); + Block::destroy(Blck, Blck == Rt + ? (MinNumPointersPerAML + 3) * InitialCapacity + : NumPointersPerBlock); Blck = Nxt; } Root = nullptr; @@ -110,6 +120,8 @@ AbstractMemoryLocationFactoryBase::Allocator::create( Pos += NumPointersRequired; + __asan_unpoison_memory_region(Ret, NumPointersRequired * sizeof(void *)); + new (Ret) AbstractMemoryLocationImpl(Baseptr, Offsets, Lifetime); return Ret; From 4c04ed3ce05a13606082282c4baa354c675b8480 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sat, 25 Nov 2023 11:57:07 +0100 Subject: [PATCH 42/59] Fix Build (#684) * Add split-dwarf to improve linker resource consumption in incremental build * More target-oriented cmake + verify that llvm small libs exist when not using the fat lib * Single export set + rename install components * minor fix * Auto-detect whether we should link against the fat LLVM lib * Fix in-tree build * fix llvm small library search * make output of non-found small llvm libs pretty --------- Co-authored-by: Martin Mory --- CMakeLists.txt | 99 ++++++++++++++++--- Config.cmake.in | 43 ++++---- cmake/phasar_macros.cmake | 48 ++++----- examples/use-phasar-as-library/CMakeLists.txt | 4 +- 4 files changed, 130 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68c3607c5..a32ac2bc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,27 @@ string(APPEND CMAKE_CXX_FLAGS_RELEASE "") option(CMAKE_VISIBILITY_INLINES_HIDDEN "Hide inlined functions from the DSO table (default ON)" ON) +include(CheckCXXCompilerFlag) + +# Handle memory issues with linking +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + string(APPEND CMAKE_CXX_FLAGS_DEBUG " -gsplit-dwarf") + string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -gsplit-dwarf") + set(LINKER_FLAGS_SAVE ${CMAKE_EXE_LINKER_FLAGS}) + + # See LLVM_USE_SPLIT_DWARF in LLVM + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gdb-index") + cmake_policy(PUSH) + cmake_policy(SET CMP0056 NEW) + check_cxx_compiler_flag("" GDB_INDEX_SUPPORTED) + cmake_policy(POP) + set(CMAKE_EXE_LINKER_FLAGS ${LINKER_FLAGS_SAVE}) + + if(GDB_INDEX_SUPPORTED) + link_libraries(debug "-Wl,--gdb-index") + endif() +endif() + # march=native # NOTE: Use gcc -march=native -Q --help=target | grep -- '-march=' | cut -f3 @@ -87,7 +108,6 @@ elseif("${CMAKE_BUILD_TYPE}" STREQUAL "Release") endif() if (NOT "${PHASAR_TARGET_ARCH_INTERNAL}" STREQUAL "") - include(CheckCXXCompilerFlag) check_cxx_compiler_flag("-march=${PHASAR_TARGET_ARCH_INTERNAL}" MARCH_SUPPORTED) if (MARCH_SUPPORTED) message(STATUS "Target architecture '${PHASAR_TARGET_ARCH_INTERNAL}' enabled") @@ -204,6 +224,17 @@ else() set(PHASAR_CONFIG_INSTALL_DIR "${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}") endif() + +# Headers + +add_library(phasar_interface INTERFACE) +target_include_directories(phasar_interface + INTERFACE + $ # The regular include folder + $ # The location of phasar-config.h + $ # The installed include folder +) + ### Adding external libraries # Threads @@ -260,7 +291,6 @@ option(USE_LLVM_FAT_LIB "Link against libLLVM.so instead of the individual LLVM if (NOT PHASAR_IN_TREE) # Only search for LLVM if we build out of tree find_package(LLVM 14 REQUIRED CONFIG) - find_library(LLVM_LIBRARY NAMES LLVM PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH) if(USE_LLVM_FAT_LIB AND ${LLVM_LIBRARY} STREQUAL "LLVM_LIBRARY-NOTFOUND") @@ -270,7 +300,38 @@ if (NOT PHASAR_IN_TREE) message(STATUS "Found consolidated shared LLVM lib ${LLVM_LIBRARY} that will be linked against.") set(USE_LLVM_FAT_LIB ON) endif() -endif() + + if (NOT USE_LLVM_FAT_LIB) + message(STATUS "Link against individual LLVM modules") + set(LLVM_REQUIRED_LIBRARIES + Core + Support + BitWriter + Analysis + Passes + Demangle + Analysis + IRReader + Linker + ) + foreach(lib ${LLVM_REQUIRED_LIBRARIES}) + find_library(LLVM_SMALL_LIB${lib} NAMES LLVM${lib} PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH) + if(LLVM_SMALL_LIB${lib} MATCHES "NOTFOUND$") + list(APPEND LLVM_SMALL_LIB_NOTFOUND "LLVM${lib}") + endif() + endforeach() + + if(DEFINED LLVM_SMALL_LIB_NOTFOUND) + if(${LLVM_LIBRARY} STREQUAL "LLVM_LIBRARY-NOTFOUND") + message(FATAL_ERROR "Did not find a complete version of LLVM: Did not find the fat lib libLLVM.so, but also did not find the individual modules ${LLVM_SMALL_LIB_NOTFOUND}.") + else() + set(USE_LLVM_FAT_LIB ON) + list(JOIN LLVM_SMALL_LIB_NOTFOUND ", " LLVM_SMALL_LIB_NOTFOUND_PRETTY) + message(WARNING "Did not find the LLVM modules ${LLVM_SMALL_LIB_NOTFOUND_PRETTY}. Fallback to link against ${LLVM_LIBRARY}. To silence this warning, set -DUSE_LLVM_FAT_LIB=ON in the cmake invocation.") + endif() + endif(DEFINED LLVM_SMALL_LIB_NOTFOUND) + endif(NOT USE_LLVM_FAT_LIB) +endif(NOT PHASAR_IN_TREE) if(NOT LLVM_ENABLE_RTTI AND NOT PHASAR_IN_TREE) message(FATAL_ERROR "PhASAR requires a LLVM version that is built with RTTI") @@ -315,7 +376,7 @@ if(BUILD_PHASAR_CLANG) if (PHASAR_IN_TREE) # Phasar needs clang headers, specificaly some that are generated by clangs table-gen - include_directories(SYSTEM + include_directories( ${CLANG_INCLUDE_DIR} ${PHASAR_SRC_DIR}/../clang/include ${PROJECT_BINARY_DIR}/tools/clang/include @@ -335,13 +396,8 @@ endif () # Library Dependency Dirs if(NOT PHASAR_IN_TREE) - include_directories(${LLVM_INCLUDE_DIRS}) - link_directories(${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS}) separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) add_definitions(${LLVM_DEFINITIONS_LIST}) - if (BUILD_PHASAR_CLANG) - link_directories(${CLANG_LIB_PATH}) - endif() endif() # Installed config @@ -413,17 +469,30 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/phasar/Config/ PATTERN "*.h" ) -# Install the header only json container +if(NOT PHASAR_IN_TREE) + install(TARGETS phasar_interface + EXPORT PhasarExports + ) + + # Install the export-set containing all the phasar targets + install(EXPORT PhasarExports + FILE PhasarExports.cmake + NAMESPACE phasar:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/phasar" + ) +else() + install(TARGETS phasar_interface + EXPORT LLVMExports + ) + set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS phasar_interface) +endif() + +# Install the header only json container ### TODO Fix this! install(DIRECTORY external/json/single_include/ DESTINATION include FILES_MATCHING PATTERN "*.hpp" ) -# Install the gtest header files (TODO this installation dependency should be eliminated) -install(DIRECTORY external/googletest/googletest/include/gtest/ - DESTINATION include/gtest -) - # Install Phasar utils helper scripts install(DIRECTORY utils/ DESTINATION bin diff --git a/Config.cmake.in b/Config.cmake.in index 98d5c07c7..5828af35e 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -14,8 +14,6 @@ find_package(LLVM 14 REQUIRED CONFIG) set(PHASAR_USE_LLVM_FAT_LIB @USE_LLVM_FAT_LIB@) set(PHASAR_BUILD_DYNLIB @PHASAR_BUILD_DYNLIB@) -# TODO: The order seems to be important in the include'ing loop below. Fix this! - set(PHASAR_COMPONENTS utils passes @@ -40,30 +38,35 @@ set(PHASAR_COMPONENTS list(REMOVE_DUPLICATES phasar_FIND_COMPONENTS) +set(PHASAR_NEEDED_LIBS) + +include("${CMAKE_CURRENT_LIST_DIR}/PhasarExports.cmake") + foreach(component ${phasar_FIND_COMPONENTS}) if(NOT ${component} IN_LIST PHASAR_COMPONENTS) set(phasar_FOUND false) - set(phasar_NOT_FOUND_MESSAGE "Unsupported component: ${component}. valid components are: ${PHASAR_COMPONENTS}") + set(phasar_NOT_FOUND_MESSAGE "Unsupported component: ${component}. Valid components are: ${PHASAR_COMPONENTS}") endif() -endforeach() -foreach(component ${PHASAR_COMPONENTS}) - include("${CMAKE_CURRENT_LIST_DIR}/phasar_${component}-targets.cmake") + list(APPEND PHASAR_NEEDED_LIBS phasar::${component}) endforeach() -include("${CMAKE_CURRENT_LIST_DIR}/phasar-targets.cmake") -if (NOT phasar_FIND_COMPONENTS) - list(APPEND PHASAR_NEEDED_LIBS phasar::phasar) - set(phasar_FIND_COMPONENTS ${PHASAR_NEEDED_LIBS}) -endif() +if (phasar_FOUND) + foreach(component ${phasar_FIND_COMPONENTS}) + # For backwards compatibility -- will be removed with next release + add_library(phasar::phasar_${component} ALIAS phasar::${component}) + endforeach() -foreach(component ${phasar_FIND_COMPONENTS}) - list(APPEND PHASAR_NEEDED_LIBS phasar::phasar_${component}) -endforeach() + if (NOT phasar_FIND_COMPONENTS) + list(APPEND PHASAR_NEEDED_LIBS phasar::phasar) + # Default target + add_library(phasar ALIAS phasar::phasar) + endif() -function(phasar_config executable) - target_link_libraries(${executable} - PUBLIC - ${PHASAR_NEEDED_LIBS} - ) -endfunction() + function(phasar_config executable) + target_link_libraries(${executable} + PUBLIC + ${PHASAR_NEEDED_LIBS} + ) + endfunction() +endif() diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index 4e7b2a901..2c9decf9a 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -179,8 +179,14 @@ function(add_phasar_library name) set(libkind STATIC) endif() + # cut off prefix phasar_ for convenient component names + string(REGEX REPLACE phasar_ "" component_name ${name}) + add_library(${name} ${libkind} ${srcs}) - add_library(phasar::${name} ALIAS ${name}) + add_library(phasar::${component_name} ALIAS ${name}) + set_target_properties(${name} PROPERTIES + EXPORT_NAME ${component_name} + ) if(LLVM_COMMON_DEPENDS) add_dependencies(${name} ${LLVM_COMMON_DEPENDS}) @@ -192,22 +198,20 @@ function(add_phasar_library name) target_link_libraries(${name} PUBLIC ${PHASAR_LIB_LINKS}) endif() - target_link_libraries(${name} PUBLIC ${PHASAR_LIB_LINK_PUBLIC}) + target_link_libraries(${name} PUBLIC phasar_interface ${PHASAR_LIB_LINK_PUBLIC}) target_link_libraries(${name} PRIVATE ${PHASAR_LIB_LINK_PRIVATE}) phasar_link_llvm(${name} ${PHASAR_LIB_LLVM_LINK_COMPONENTS}) - target_include_directories(${name} - PUBLIC - $ # The regular include folder - $ # The location of phasar-config.h - ) - - # Set the target property such that installed PhASAR knows where to find its includes (must be relative paths in this case in contrast to non-installed PhASAR!) - set_property(TARGET ${name} APPEND - PROPERTY INTERFACE_INCLUDE_DIRECTORIES - $ - ) + # Library Dependency Dirs + if(NOT PHASAR_IN_TREE) + target_include_directories(${name} PUBLIC + ${LLVM_INCLUDE_DIRS} + ) + target_link_directories(${name} PUBLIC + ${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS} + ) + endif() if(MSVC) get_target_property(cflag ${name} COMPILE_FLAGS) @@ -220,31 +224,19 @@ function(add_phasar_library name) set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag}) endif(MSVC) - # cut off prefix phasar_ for convenient component names - string(REGEX REPLACE phasar_ "" component_name ${name}) - if(PHASAR_IN_TREE) install(TARGETS ${name} EXPORT LLVMExports LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}) + ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} + ) else() install(TARGETS ${name} - EXPORT ${name}-targets - COMPONENT ${component_name} - - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + EXPORT PhasarExports # NOTE: Library, archive and runtime destination are automatically set by # GNUInstallDirs which is included in the top-level CMakeLists.txt ) - install(EXPORT ${name}-targets - FILE ${name}-targets.cmake - NAMESPACE phasar:: - DESTINATION lib/cmake/phasar - COMPONENT ${component_name} - ) endif() set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS ${name}) diff --git a/examples/use-phasar-as-library/CMakeLists.txt b/examples/use-phasar-as-library/CMakeLists.txt index de0f50fd1..a7bfaa8d9 100644 --- a/examples/use-phasar-as-library/CMakeLists.txt +++ b/examples/use-phasar-as-library/CMakeLists.txt @@ -21,10 +21,12 @@ add_executable(myphasartool # phasar_config(myphasartool) # New way using target_link_libraries: -target_link_libraries(myphasartool phasar::phasar_llvm_ifdside) +target_link_libraries(myphasartool phasar::llvm_ifdside) # If find_package did not specify components: # target_link_libraries(myphasartool phasar::phasar) +# alternatively using the default target: +# target_link_libraries(myphasartool phasar) install(TARGETS myphasartool RUNTIME DESTINATION bin From 3aca4324601764ad3c6c80e23f9231631d8a227d Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sat, 25 Nov 2023 12:11:13 +0100 Subject: [PATCH 43/59] Improve Logger Performance (#683) * Make use of LoggerFilterLevel to conditionally disable message formatting * Move more from the Logger header to the implementation file * Refactor StdStream + some cleanup * Re-enable PIC by default to support ASLR --- .../DataFlow/IfdsIde/Solver/IDESolver.h | 175 ++++++++------- include/phasar/Utils/Logger.h | 139 ++++++------ include/phasar/Utils/TypeTraits.h | 22 +- lib/Utils/Logger.cpp | 210 ++++++++++-------- 4 files changed, 288 insertions(+), 258 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index ac730de2a..cfe82bacf 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -286,15 +286,16 @@ class IDESolver const auto &ReturnSiteNs = ICF->getReturnSitesOfCallAt(n); const auto &Callees = ICF->getCalleesOfCallAt(n); - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL(DEBUG, "Possible callees:"); for (auto Callee - : Callees) { - PHASAR_LOG_LEVEL(DEBUG, " " << Callee->getName()); - } PHASAR_LOG_LEVEL(DEBUG, "Possible return sites:"); - for (auto ret - : ReturnSiteNs) { - PHASAR_LOG_LEVEL(DEBUG, " " << NToString(ret)); - }); + IF_LOG_LEVEL_ENABLED(DEBUG, { + PHASAR_LOG_LEVEL(DEBUG, "Possible callees:"); + for (auto Callee : Callees) { + PHASAR_LOG_LEVEL(DEBUG, " " << Callee->getName()); + } + PHASAR_LOG_LEVEL(DEBUG, "Possible return sites:"); + for (auto ret : ReturnSiteNs) { + PHASAR_LOG_LEVEL(DEBUG, " " << NToString(ret)); + } + }); // for each possible callee for (f_t SCalledProcN : Callees) { // still line 14 @@ -315,11 +316,11 @@ class IDESolver CachedFlowEdgeFunctions.getSummaryEdgeFunction(n, d2, ReturnSiteN, d3); INC_COUNTER("SpecialSummary-EF Queries", 1, Full); - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL( - DEBUG, "Queried Summary Edge Function: " << SumEdgFnE); - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << SumEdgFnE << " * " << f - << '\n')); + + PHASAR_LOG_LEVEL(DEBUG, + "Queried Summary Edge Function: " << SumEdgFnE); + PHASAR_LOG_LEVEL(DEBUG, + "Compose: " << SumEdgFnE << " * " << f << '\n'); WorkList.emplace_back(PathEdge(d1, ReturnSiteN, std::move(d3)), f.composeWith(SumEdgFnE)); } @@ -562,7 +563,7 @@ class IDESolver } void setVal(n_t NHashN, d_t NHashD, l_t L) { - IF_LOG_ENABLED({ + IF_LOG_LEVEL_ENABLED(DEBUG, { PHASAR_LOG_LEVEL(DEBUG, "Function : " << ICF->getFunctionOf(NHashN)->getName()); PHASAR_LOG_LEVEL(DEBUG, "Inst. : " << NToString(NHashN)); @@ -580,13 +581,14 @@ class IDESolver } EdgeFunction jumpFunction(const PathEdge Edge) { - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL(DEBUG, "JumpFunctions Forward-Lookup:"); - PHASAR_LOG_LEVEL(DEBUG, - " Source D: " << DToString(Edge.factAtSource())); - PHASAR_LOG_LEVEL(DEBUG, " Target N: " << NToString(Edge.getTarget())); - PHASAR_LOG_LEVEL(DEBUG, - " Target D: " << DToString(Edge.factAtTarget()))); + IF_LOG_LEVEL_ENABLED(DEBUG, { + PHASAR_LOG_LEVEL(DEBUG, "JumpFunctions Forward-Lookup:"); + PHASAR_LOG_LEVEL(DEBUG, + " Source D: " << DToString(Edge.factAtSource())); + PHASAR_LOG_LEVEL(DEBUG, " Target N: " << NToString(Edge.getTarget())); + PHASAR_LOG_LEVEL(DEBUG, + " Target D: " << DToString(Edge.factAtTarget())); + }); auto FwdLookupRes = JumpFn->forwardLookup(Edge.factAtSource(), Edge.getTarget()); @@ -617,21 +619,22 @@ class IDESolver void pathEdgeProcessingTask(PathEdge Edge) { PAMM_GET_INSTANCE; INC_COUNTER("JumpFn Construction", 1, Full); - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL( - DEBUG, - "-------------------------------------------- " - << PathEdgeCount - << ". Path Edge --------------------------------------------"); - PHASAR_LOG_LEVEL(DEBUG, ' '); - PHASAR_LOG_LEVEL(DEBUG, "Process " << PathEdgeCount << ". path edge:"); - PHASAR_LOG_LEVEL(DEBUG, "< D source: " << DToString(Edge.factAtSource()) - << " ;"); - PHASAR_LOG_LEVEL(DEBUG, - " N target: " << NToString(Edge.getTarget()) << " ;"); - PHASAR_LOG_LEVEL(DEBUG, " D target: " << DToString(Edge.factAtTarget()) - << " >"); - PHASAR_LOG_LEVEL(DEBUG, ' ')); + IF_LOG_LEVEL_ENABLED(DEBUG, { + PHASAR_LOG_LEVEL( + DEBUG, + "-------------------------------------------- " + << PathEdgeCount + << ". Path Edge --------------------------------------------"); + PHASAR_LOG_LEVEL(DEBUG, ' '); + PHASAR_LOG_LEVEL(DEBUG, "Process " << PathEdgeCount << ". path edge:"); + PHASAR_LOG_LEVEL(DEBUG, "< D source: " << DToString(Edge.factAtSource()) + << " ;"); + PHASAR_LOG_LEVEL(DEBUG, + " N target: " << NToString(Edge.getTarget()) << " ;"); + PHASAR_LOG_LEVEL(DEBUG, " D target: " << DToString(Edge.factAtTarget()) + << " >"); + PHASAR_LOG_LEVEL(DEBUG, ' '); + }); if (!ICF->isCallSite(Edge.getTarget())) { if (ICF->isExitInst(Edge.getTarget())) { @@ -1063,28 +1066,31 @@ class IDESolver EdgeFunction fPrime = JumpFnE.joinWith(f); bool NewFunction = fPrime != JumpFnE; - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL( - DEBUG, "Join: " << JumpFnE << " & " << f - << (JumpFnE == f ? " (EF's are equal)" : " ")); - PHASAR_LOG_LEVEL(DEBUG, - " = " << fPrime + IF_LOG_LEVEL_ENABLED(DEBUG, { + PHASAR_LOG_LEVEL(DEBUG, + "Join: " << JumpFnE << " & " << f + << (JumpFnE == f ? " (EF's are equal)" : " ")); + PHASAR_LOG_LEVEL(DEBUG, " = " + << fPrime << (NewFunction ? " (new jump func)" : " ")); - PHASAR_LOG_LEVEL(DEBUG, ' ')); + PHASAR_LOG_LEVEL(DEBUG, ' '); + }); if (NewFunction) { JumpFn->addFunction(SourceVal, Target, TargetVal, fPrime); PathEdge Edge(SourceVal, Target, TargetVal); PathEdgeCount++; pathEdgeProcessingTask(std::move(Edge)); - IF_LOG_ENABLED(if (!IDEProblem.isZeroValue(TargetVal)) { - PHASAR_LOG_LEVEL(DEBUG, "EDGE: getFunction()->getName() - << ", D: " << DToString(SourceVal) - << '>'); - PHASAR_LOG_LEVEL(DEBUG, " ---> '); - PHASAR_LOG_LEVEL(DEBUG, ' '); + IF_LOG_LEVEL_ENABLED(DEBUG, { + if (!IDEProblem.isZeroValue(TargetVal)) { + PHASAR_LOG_LEVEL( + DEBUG, "EDGE: getFunction()->getName() + << ", D: " << DToString(SourceVal) << '>'); + PHASAR_LOG_LEVEL(DEBUG, " ---> '); + PHASAR_LOG_LEVEL(DEBUG, ' '); + } }); } else { PHASAR_LOG_LEVEL(DEBUG, "PROPAGATE: No new function!"); @@ -1118,41 +1124,43 @@ class IDESolver } void printIncomingTab() const { - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL(DEBUG, "Start of incomingtab entry"); - for (const auto &Cell - : IncomingTab.cellSet()) { - PHASAR_LOG_LEVEL(DEBUG, "sP: " << NToString(Cell.getRowKey())); - PHASAR_LOG_LEVEL(DEBUG, "d3: " << DToString(Cell.getColumnKey())); - for (const auto &Entry : Cell.getValue()) { - PHASAR_LOG_LEVEL(DEBUG, " n: " << NToString(Entry.first)); - for (const auto &Fact : Entry.second) { - PHASAR_LOG_LEVEL(DEBUG, " d2: " << DToString(Fact)); - } + IF_LOG_LEVEL_ENABLED(DEBUG, { + PHASAR_LOG_LEVEL(DEBUG, "Start of incomingtab entry"); + for (const auto &Cell : IncomingTab.cellSet()) { + PHASAR_LOG_LEVEL(DEBUG, "sP: " << NToString(Cell.getRowKey())); + PHASAR_LOG_LEVEL(DEBUG, "d3: " << DToString(Cell.getColumnKey())); + for (const auto &Entry : Cell.getValue()) { + PHASAR_LOG_LEVEL(DEBUG, " n: " << NToString(Entry.first)); + for (const auto &Fact : Entry.second) { + PHASAR_LOG_LEVEL(DEBUG, " d2: " << DToString(Fact)); } - PHASAR_LOG_LEVEL(DEBUG, "---------------"); - } PHASAR_LOG_LEVEL(DEBUG, "End of incomingtab entry");) + } + PHASAR_LOG_LEVEL(DEBUG, "---------------"); + } + PHASAR_LOG_LEVEL(DEBUG, "End of incomingtab entry"); + }) } void printEndSummaryTab() const { - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL(DEBUG, "Start of endsummarytab entry"); - - EndsummaryTab.foreachCell( - [](const auto &Row, const auto &Col, const auto &Val) { - PHASAR_LOG_LEVEL(DEBUG, "sP: " << NToString(Row)); - PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(Col)); - - Val.foreachCell([](const auto &InnerRow, const auto &InnerCol, - const auto &InnerVal) { - PHASAR_LOG_LEVEL(DEBUG, " eP: " << NToString(InnerRow)); - PHASAR_LOG_LEVEL(DEBUG, " d2: " << DToString(InnerCol)); - PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerVal); - }); - PHASAR_LOG_LEVEL(DEBUG, "---------------"); + IF_LOG_LEVEL_ENABLED(DEBUG, { + PHASAR_LOG_LEVEL(DEBUG, "Start of endsummarytab entry"); + + EndsummaryTab.foreachCell( + [](const auto &Row, const auto &Col, const auto &Val) { + PHASAR_LOG_LEVEL(DEBUG, "sP: " << NToString(Row)); + PHASAR_LOG_LEVEL(DEBUG, "d1: " << DToString(Col)); + + Val.foreachCell([](const auto &InnerRow, const auto &InnerCol, + const auto &InnerVal) { + PHASAR_LOG_LEVEL(DEBUG, " eP: " << NToString(InnerRow)); + PHASAR_LOG_LEVEL(DEBUG, " d2: " << DToString(InnerCol)); + PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerVal); }); + PHASAR_LOG_LEVEL(DEBUG, "---------------"); + }); - PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry");) + PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry"); + }) } void printComputedPathEdges() { @@ -1259,7 +1267,7 @@ class IDESolver if (ICF->isCallSite(Edge.first)) { ValidInCallerContext[Edge.second].insert(D2s.begin(), D2s.end()); } - IF_LOG_ENABLED([this](const auto &D2s) { + IF_LOG_LEVEL_ENABLED(DEBUG, [this](const auto &D2s) { for (auto D2 : D2s) { PHASAR_LOG_LEVEL(DEBUG, "d2: " << DToString(D2)); } @@ -1671,6 +1679,8 @@ class IDESolver void finalizeInternal() { PAMM_GET_INSTANCE; STOP_TIMER("DFA Phase I", Full); + PHASAR_LOG_LEVEL(INFO, "[info]: IDE Phase I completed"); + if (SolverConfig.computeValues()) { START_TIMER("DFA Phase II", Full); // Computing the final values for the edge functions @@ -1679,6 +1689,7 @@ class IDESolver computeValues(); STOP_TIMER("DFA Phase II", Full); } + PHASAR_LOG_LEVEL(INFO, "Problem solved"); if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::Core) { computeAndPrintStatistics(); diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index b35b3f806..6b3ea5e18 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -12,17 +12,12 @@ #include "phasar/Config/phasar-config.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" // LLVM_UNLIKELY -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include #include #include -#include -#include namespace psr { @@ -32,33 +27,40 @@ enum SeverityLevel { INVALID }; -SeverityLevel parseSeverityLevel(llvm::StringRef Str); +[[nodiscard]] SeverityLevel parseSeverityLevel(llvm::StringRef Str) noexcept; +[[nodiscard]] llvm::StringRef to_string(SeverityLevel Level) noexcept; class Logger final { public: /** * Set the filter level. */ - static void setLoggerFilterLevel(SeverityLevel Level); + static void setLoggerFilterLevel(SeverityLevel Level) noexcept; - static SeverityLevel getLoggerFilterLevel(); - - static bool isLoggingEnabled(); + static SeverityLevel getLoggerFilterLevel() noexcept { + return LogFilterLevel; + } - static void enable() { LoggingEnabled = true; }; + static bool isLoggingEnabled() noexcept { return LoggingEnabled; } - static void disable() { LoggingEnabled = false; }; + static void enable() noexcept { LoggingEnabled = true; }; + static void disable() noexcept { LoggingEnabled = false; }; static llvm::raw_ostream & getLogStream(std::optional Level, const std::optional &Category); - static bool logCategory(llvm::StringRef Category, - std::optional Level); + static llvm::raw_ostream & + getLogStreamWithLinePrefix(std::optional Level, + const std::optional &Category); + + [[nodiscard]] static bool + logCategory(llvm::StringRef Category, + std::optional Level) noexcept; static void addLinePrefix(llvm::raw_ostream &, std::optional Level, - const std::optional &Category); + const std::optional &Category); static void initializeStdoutLogger( std::optional Level = std::nullopt, @@ -75,32 +77,15 @@ class Logger final { bool Append = false); private: - enum class StdStream : uint8_t { STDOUT = 0, STDERR }; static inline bool LoggingEnabled = false; - static inline llvm::StringMap, - std::variant>> - CategoriesToStreamVariant; - static inline std::map, - std::variant> - LevelsToStreamVariant; - static inline SeverityLevel LogFilterLevel = DEBUG; - static std::string toString(SeverityLevel Level); - static inline llvm::StringMap LogfileStreams; - // static inline auto StartTime = std::chrono::steady_clock::now(); - [[nodiscard]] static llvm::raw_ostream & - getLogStream(std::optional Level, - const std::map, - std::variant> - &PassedLevelsToStreamVariant); - [[nodiscard]] static llvm::raw_ostream &getLogStreamFromStreamVariant( - const std::variant &StreamVariant); + static inline SeverityLevel LogFilterLevel = CRITICAL; }; #ifdef DYNAMIC_LOG // For performance reason, we want to disable any // formatting computation that would go straight into -// logs if logs are deactivated This macro does just +// logs if logs are deactivated. This macro does just // that #define IF_LOG_ENABLED_BOOL(condition, computation) \ if (LLVM_UNLIKELY(condition)) { \ @@ -108,66 +93,66 @@ class Logger final { } #define IS_LOG_ENABLED ::psr::Logger::isLoggingEnabled() - #define IF_LOG_ENABLED(computation) \ IF_LOG_ENABLED_BOOL(::psr::Logger::isLoggingEnabled(), computation) +#define IS_LOG_LEVEL_ENABLED(level) \ + (::psr::Logger::isLoggingEnabled() && \ + (::psr::SeverityLevel::level) >= ::psr::Logger::getLoggerFilterLevel()) +#define IF_LOG_LEVEL_ENABLED(level, computation) \ + IF_LOG_ENABLED_BOOL(IS_LOG_LEVEL_ENABLED(level), computation) + #define PHASAR_LOG_LEVEL(level, message) \ - IF_LOG_ENABLED_BOOL( \ - ::psr::Logger::isLoggingEnabled() && \ - (::psr::SeverityLevel::level) >= \ - ::psr::Logger::getLoggerFilterLevel(), \ - do { \ - auto &Stream = ::psr::Logger::getLogStream( \ - ::psr::SeverityLevel::level, std::nullopt); \ - ::psr::Logger::addLinePrefix(Stream, ::psr::SeverityLevel::level, \ - std::nullopt); \ - /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - Stream << message << '\n'; \ - } while (false);) + do { \ + IF_LOG_ENABLED_BOOL(IS_LOG_LEVEL_ENABLED(level), { \ + auto &Stream = ::psr::Logger::getLogStreamWithLinePrefix( \ + ::psr::SeverityLevel::level, std::nullopt); \ + /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ + Stream << message << '\n'; \ + }) \ + } while (false) #define PHASAR_LOG(message) PHASAR_LOG_LEVEL(DEBUG, message) #define PHASAR_LOG_LEVEL_CAT(level, cat, message) \ - IF_LOG_ENABLED_BOOL( \ - ::psr::Logger::isLoggingEnabled() && \ - (::psr::SeverityLevel::level) >= \ - ::psr::Logger::getLoggerFilterLevel() && \ - ::psr::Logger::logCategory(cat, ::psr::SeverityLevel::level), \ - do { \ - auto &Stream = \ - ::psr::Logger::getLogStream(::psr::SeverityLevel::level, cat); \ - ::psr::Logger::addLinePrefix(Stream, ::psr::SeverityLevel::level, \ - cat); \ - /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - Stream << message << '\n'; \ - } while (false);) + do { \ + IF_LOG_ENABLED_BOOL( \ + IS_LOG_LEVEL_ENABLED(level) && \ + ::psr::Logger::logCategory(cat, ::psr::SeverityLevel::level), \ + { \ + auto &Stream = ::psr::Logger::getLogStreamWithLinePrefix( \ + ::psr::SeverityLevel::level, cat); \ + /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ + Stream << message << '\n'; \ + }) \ + } while (false) #define PHASAR_LOG_CAT(cat, message) \ - IF_LOG_ENABLED_BOOL( \ - ::psr::Logger::isLoggingEnabled() && \ - ::psr::Logger::logCategory(cat, std::nullopt), \ - do { \ - auto &Stream = ::psr::Logger::getLogStream(std::nullopt, cat); \ - ::psr::Logger::addLinePrefix(Stream, std::nullopt, cat); \ - /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ - Stream << message << '\n'; \ - } while (false);) + do { \ + IF_LOG_ENABLED_BOOL(::psr::Logger::isLoggingEnabled() && \ + ::psr::Logger::logCategory(cat, std::nullopt), \ + { \ + auto &Stream = \ + ::psr::Logger::getLogStreamWithLinePrefix( \ + std::nullopt, cat); \ + /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \ + Stream << message << '\n'; \ + }) \ + } while (false) #else +#define IS_LOG_ENABLED false #define IF_LOG_ENABLED_BOOL(condition, computation) \ {} #define IF_LOG_ENABLED(computation) \ {} -#define PHASAR_LOG(computation) \ +#define IS_LOG_LEVEL_ENABLED(level) false +#define IF_LOG_LEVEL_ENABLED(level, computation) \ {} -#define PHASAR_LOG_CAT(cat, message) \ - {} -#define PHASAR_LOG_LEVEL_CAT(level, cat, message) \ - {} -#define PHASAR_LOG_LEVEL(level, message) \ - {} -#define IS_LOG_ENABLED false +#define PHASAR_LOG(computation) (void)0 +#define PHASAR_LOG_CAT(cat, message) (void)0 +#define PHASAR_LOG_LEVEL_CAT(level, cat, message) (void)0 +#define PHASAR_LOG_LEVEL(level, message) (void)0 #endif /** diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 77bcfa36a..d3022d72c 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -21,6 +21,12 @@ namespace psr { +#if __cplusplus < 202002L +template struct type_identity { using type = T; }; +#else +template using type_identity = std::type_identity; +#endif + // NOLINTBEGIN(readability-identifier-naming) namespace detail { @@ -147,6 +153,13 @@ struct AreEqualityComparable() == std::declval())> : std::true_type {}; +template struct variant_idx; +template +struct variant_idx, T> + : std::integral_constant< + size_t, + std::variant...>(type_identity{}).index()> {}; + } // namespace detail template @@ -217,14 +230,11 @@ template static inline constexpr bool AreEqualityComparable = detail::AreEqualityComparable::value; -#if __cplusplus < 202002L -template struct type_identity { using type = T; }; -#else -template using type_identity = std::type_identity; -#endif - template using type_identity_t = typename type_identity::type; +template +static constexpr size_t variant_idx = detail::variant_idx::value; + struct TrueFn { template [[nodiscard]] bool operator()(const Args &.../*unused*/) const noexcept { diff --git a/lib/Utils/Logger.cpp b/lib/Utils/Logger.cpp index 85b88f290..35cd18a29 100644 --- a/lib/Utils/Logger.cpp +++ b/lib/Utils/Logger.cpp @@ -16,19 +16,24 @@ #include "phasar/Utils/Logger.h" +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileSystem.h" -namespace psr { +#include +#include -SeverityLevel parseSeverityLevel(llvm::StringRef Str) { +auto psr::parseSeverityLevel(llvm::StringRef Str) noexcept -> SeverityLevel { return llvm::StringSwitch(Str) #define SEVERITY_LEVEL(NAME, TYPE) .Case(NAME, SeverityLevel::TYPE) #include "phasar/Utils/SeverityLevel.def" .Default(SeverityLevel::INVALID); } -std::string Logger::toString(SeverityLevel Level) { +llvm::StringRef psr::to_string(SeverityLevel Level) noexcept { switch (Level) { default: #define SEVERITY_LEVEL(NAME, TYPE) \ @@ -39,63 +44,116 @@ std::string Logger::toString(SeverityLevel Level) { } } -void Logger::setLoggerFilterLevel(SeverityLevel Level) { - LogFilterLevel = Level; +namespace psr { +namespace logger { + +struct StdOut {}; +struct StdErr {}; +using StreamVariantTy = std::variant; + +static llvm::StringMap, StreamVariantTy>> + CategoriesToStreamVariant; +static std::map, StreamVariantTy> + LevelsToStreamVariant; + +static llvm::StringMap LogfileStreams; +// static inline auto StartTime = std::chrono::steady_clock::now(); + +// --- + +[[nodiscard]] static llvm::raw_ostream & +getLogStreamFromStreamVariant(const StreamVariantTy &StreamVariant) { + switch (StreamVariant.index()) { + case variant_idx: + return llvm::outs(); + case variant_idx: + return llvm::errs(); + case variant_idx: { + const auto &Filename = std::get(StreamVariant); + auto It = LogfileStreams.find(Filename); + assert(It != LogfileStreams.end()); + return It->second; + } + } + llvm_unreachable("All stream variants should be handled in the switch above"); +} + +[[nodiscard]] static llvm::raw_ostream & +getLogStream(std::optional Level, + const std::map, StreamVariantTy> + &PassedLevelsToStreamVariant) { + if (Level.has_value()) { + for (const auto &[LevelThreshold, StreamVar] : + llvm::reverse(PassedLevelsToStreamVariant)) { + if (LevelThreshold <= *Level) { + return getLogStreamFromStreamVariant(StreamVar); + } + } + // fallthrough + } + + auto StreamVariantIt = PassedLevelsToStreamVariant.find(std::nullopt); + if (StreamVariantIt != PassedLevelsToStreamVariant.end()) { + return getLogStreamFromStreamVariant(StreamVariantIt->second); + } + return llvm::nulls(); } -SeverityLevel Logger::getLoggerFilterLevel() { return LogFilterLevel; } +template +void initializeLoggerImpl(std::optional Level, + const std::optional &Category, + StdStreamTy Stream) { + using namespace logger; + if (Category.has_value()) { + CategoriesToStreamVariant[*Category].insert_or_assign(Level, + std::move(Stream)); + } else { + LevelsToStreamVariant.insert_or_assign(Level, std::move(Stream)); + } +} -bool Logger::isLoggingEnabled() { return LoggingEnabled; } +} // namespace logger + +void Logger::setLoggerFilterLevel(SeverityLevel Level) noexcept { + assert(Level >= SeverityLevel::DEBUG && Level < SeverityLevel::INVALID); + LogFilterLevel = Level; +} void Logger::initializeStdoutLogger( std::optional Level, const std::optional &Category) { LoggingEnabled = true; - if (Category.has_value()) { - CategoriesToStreamVariant[Category.value()][Level] = StdStream::STDOUT; - } else { - LevelsToStreamVariant[Level] = StdStream::STDOUT; - } + logger::initializeLoggerImpl(Level, Category, logger::StdOut{}); + LogFilterLevel = std::min(LogFilterLevel, Level.value_or(CRITICAL)); } void Logger::initializeStderrLogger( std::optional Level, const std::optional &Category) { LoggingEnabled = true; - if (Category.has_value()) { - CategoriesToStreamVariant[Category.value()][Level] = StdStream::STDERR; - } else { - LevelsToStreamVariant[Level] = StdStream::STDERR; - } + logger::initializeLoggerImpl(Level, Category, logger::StdErr{}); + LogFilterLevel = std::min(LogFilterLevel, Level.value_or(CRITICAL)); } -[[nodiscard]] bool Logger::initializeFileLogger( - llvm::StringRef Filename, std::optional Level, - const std::optional &Category, bool Append) { +bool Logger::initializeFileLogger(llvm::StringRef Filename, + std::optional Level, + const std::optional &Category, + bool Append) { + using logger::LogfileStreams; + LoggingEnabled = true; - if (Category.has_value()) { - CategoriesToStreamVariant[Category.value()][Level] = Filename.str(); - } else { - LevelsToStreamVariant[Level] = Filename.str(); + logger::initializeLoggerImpl(Level, Category, Filename.str()); + LogFilterLevel = std::min(LogFilterLevel, Level.value_or(CRITICAL)); + + auto Flags = llvm::sys::fs::OpenFlags::OF_ChildInherit; + if (Append) { + Flags |= llvm::sys::fs::OpenFlags::OF_Append; } std::error_code EC; - auto [It, Inserted] = [&] { - if (Append) { - return LogfileStreams.try_emplace( - Filename, Filename, EC, - llvm::sys::fs::OpenFlags::OF_Append | - llvm::sys::fs::OpenFlags::OF_ChildInherit); - } - - return LogfileStreams.try_emplace( - Filename, Filename, EC, llvm::sys::fs::OpenFlags::OF_ChildInherit); - }(); - - if (!Inserted) { - return true; - } + LogfileStreams.try_emplace(Filename, Filename, EC, Flags); + // EC can only be true, if a new filestream was inserted if (EC) { LogfileStreams.erase(Filename); llvm::errs() << "Failed to open logfile: " << Filename << '\n'; @@ -108,99 +166,67 @@ void Logger::initializeStderrLogger( llvm::raw_ostream & Logger::getLogStream(std::optional Level, const std::optional &Category) { + using namespace logger; if (Category.has_value()) { - auto CategoryLookupIt = CategoriesToStreamVariant.find(Category.value()); + auto CategoryLookupIt = CategoriesToStreamVariant.find(*Category); if (CategoryLookupIt == CategoriesToStreamVariant.end()) { return llvm::nulls(); } - return getLogStream(Level, CategoryLookupIt->second); + return logger::getLogStream(Level, CategoryLookupIt->second); } - return getLogStream(Level, LevelsToStreamVariant); + return logger::getLogStream(Level, LevelsToStreamVariant); } -llvm::raw_ostream & -Logger::getLogStream(std::optional Level, - const std::map, - std::variant> - &PassedLevelsToStreamVariant) { - if (Level.has_value()) { - std::optional ClosestLevel = std::nullopt; - for (const auto &[LevelThreshold, _] : PassedLevelsToStreamVariant) { - if (LevelThreshold <= Level.value()) { - if (!ClosestLevel || ClosestLevel.value() < LevelThreshold) { - ClosestLevel = LevelThreshold; - } - } - } - auto StreamVariantIt = PassedLevelsToStreamVariant.find(ClosestLevel); - if (StreamVariantIt != PassedLevelsToStreamVariant.end()) { - return getLogStreamFromStreamVariant(StreamVariantIt->second); - } - return llvm::nulls(); - } - auto StreamVariantIt = PassedLevelsToStreamVariant.find(Level); - if (StreamVariantIt != PassedLevelsToStreamVariant.end()) { - return getLogStreamFromStreamVariant(StreamVariantIt->second); - } - return llvm::nulls(); -} - -llvm::raw_ostream &Logger::getLogStreamFromStreamVariant( - const std::variant &StreamVariant) { - if (std::holds_alternative(StreamVariant)) { - auto StdStreamKind = std::get(StreamVariant); - if (StdStreamKind == StdStream::STDOUT) { - return llvm::outs(); - } - if (StdStreamKind == StdStream::STDERR) { - return llvm::errs(); - } - return llvm::nulls(); - } - auto It = LogfileStreams.find(std::get(StreamVariant)); - assert(It != LogfileStreams.end()); - return It->second; +llvm::raw_ostream &Logger::getLogStreamWithLinePrefix( + std::optional Level, + const std::optional &Category) { + auto &OS = getLogStream(Level, Category); + addLinePrefix(OS, Level, Category); + return OS; } bool Logger::logCategory(llvm::StringRef Category, - std::optional Level) { + std::optional Level) noexcept { + using namespace logger; auto CategoryLookupIt = CategoriesToStreamVariant.find(Category); if (CategoryLookupIt == CategoriesToStreamVariant.end()) { return false; } if (Level.has_value()) { for (const auto &[LevelThreshold, Stream] : CategoryLookupIt->second) { - if (LevelThreshold <= Level.value()) { + if (LevelThreshold <= *Level) { return true; } } return false; } - return CategoryLookupIt->second.count(Level) > 0; + return CategoryLookupIt->second.count(Level); } void Logger::addLinePrefix(llvm::raw_ostream &OS, std::optional Level, - const std::optional &Category) { + const std::optional &Category) { // const auto NowTime = std::chrono::steady_clock::now(); // const auto MillisecondsDuration = // chrono::duration_cast(NowTime - // StartTime).count(); // OS << MillisecondsDuration; if (Level.has_value()) { - OS << '[' << toString(Level.value()) << ']'; + OS << '[' << to_string(*Level) << ']'; } // else { // OS << ' '; // } if (Category.has_value()) { - OS << '[' << Category.value() << ']'; + OS << '[' << *Category << ']'; } // else { // OS << ' '; // } OS << ' '; } -void initializeLogger(bool UseLogger, const std::string &LogFile) { +} // namespace psr + +void psr::initializeLogger(bool UseLogger, const std::string &LogFile) { if (!UseLogger) { Logger::disable(); return; @@ -212,5 +238,3 @@ void initializeLogger(bool UseLogger, const std::string &LogFile) { Logger::initializeFileLogger(LogFile, Logger::getLoggerFilterLevel()); } } - -} // namespace psr From fc14480e86e9da43a6061c99436bc1b19ec75d8d Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sat, 25 Nov 2023 12:24:35 +0100 Subject: [PATCH 44/59] Make killAllFlows() kill flows (#682) --- include/phasar/DataFlow/IfdsIde/FlowFunctions.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index 7ff1769d7..24a511eca 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -107,14 +107,14 @@ class ZeroedFlowFunction : public FlowFunction { public: ZeroedFlowFunction(FlowFunctionPtrType FF, D ZV) - : Delegate(std::move(FF)), ZeroValue(ZV) {} + : Delegate(std::move(FF)), ZeroValue(std::move(ZV)) {} container_type computeTargets(D Source) override { if (Source == ZeroValue) { container_type Result = Delegate->computeTargets(Source); Result.insert(ZeroValue); return Result; } - return Delegate->computeTargets(Source); + return Delegate->computeTargets(std::move(Source)); } private: @@ -423,9 +423,7 @@ template class FlowFunctionTemplates { /// static auto killAllFlows() { struct KillAllFF final : public FlowFunction { - Container computeTargets(d_t Source) override { - return {std::move(Source)}; - } + Container computeTargets(d_t /*Source*/) override { return Container(); } }; static auto TheKillAllFlow = std::make_shared(); From 1e9f3b725b6c11c1a66002ef5d7af553434b006b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Sat, 25 Nov 2023 12:39:02 +0100 Subject: [PATCH 45/59] Analysis Printer (#677) * Analysis Printer (#17) * Initial Commit * AnalysisPrinter Second commit * Initial Commit * Integrate Printer with client Analysis and test * Addressing Review comments * Integrate AnalysisPrinter with all analyses and template class modified * vector emplace_back instead of push_back * Testcase for AnalysisPrinter * GroundTruth derived class initial commit * AnalysisPrinter Test complete and Test * fixing myphasartool file * Test pre-commit fix * Adding Test cases and fixing PR failure * 1.template params to N,D,L 2.remove AnalysisType param from AnalysisResults 3.rearranging class variables * 1.template params to N,D,L 2.remove AnalysisType param from AnalysisResults 3.rearranging class variables * Null AnalysisPrinter singleton * Adding AnalysisPrinter to IDETabulation Problem * making free (N,D,L)ToString functions * disable copy and move for analysis-printer * Default NullAnalysisPrinter and explicit print methods * removing SetAnalysisPrinter from client analyses and modified Testcase for AnalysisPrinter * Adding superclass for AnalysisPrinter * Addressing review comments and fixing PR build failure * fix: minors * fix: minor (clang-tidy) * fix: review feedback * misc: minor refactoring --------- Co-authored-by: SanthoshMohan Co-authored-by: Sriteja Kummita * fix: review feedback --------- Co-authored-by: SanthoshMohan Co-authored-by: Sriteja Kummita --- .../DataFlow/IfdsIde/IDETabulationProblem.h | 14 +- .../Utils/ExtendedValue.h | 2 + .../IfdsIde/Problems/IDETypeStateAnalysis.h | 51 ++----- .../PhasarLLVM/Utils/AnalysisPrinterBase.h | 44 ++++++ .../PhasarLLVM/Utils/DefaultAnalysisPrinter.h | 47 +++++++ .../PhasarLLVM/Utils/NullAnalysisPrinter.h | 25 ++++ .../Problems/IDEExtendedTaintAnalysis.cpp | 12 +- .../Problems/IDEInstInteractionAnalysis.cpp | 2 + .../Problems/IFDSFieldSensTaintAnalysis.cpp | 3 +- .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 33 ++--- .../OpenSSLSecureMemoryDescription.cpp | 3 +- unittests/Utils/AnalysisPrinterTest.cpp | 128 ++++++++++++++++++ unittests/Utils/CMakeLists.txt | 1 + 13 files changed, 295 insertions(+), 70 deletions(-) create mode 100644 include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h create mode 100644 include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h create mode 100644 include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h create mode 100644 unittests/Utils/AnalysisPrinterTest.cpp diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index ab20dc3f6..35bd80ae5 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -19,6 +19,7 @@ #include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h" #include "phasar/DataFlow/IfdsIde/InitialSeeds.h" #include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h" #include "phasar/Utils/JoinLattice.h" #include "phasar/Utils/Printer.h" #include "phasar/Utils/Soundness.h" @@ -78,10 +79,19 @@ class IDETabulationProblem : public FlowFunctions, std::optional ZeroValue) noexcept(std::is_nothrow_move_constructible_v) : IRDB(IRDB), EntryPoints(std::move(EntryPoints)), - ZeroValue(std::move(ZeroValue)) { + ZeroValue(std::move(ZeroValue)), + Printer(NullAnalysisPrinter::getInstance()) { assert(IRDB != nullptr); } + void setAnalysisPrinter(AnalysisPrinterBase *P) { + if (P) { + Printer = P; + } else { + Printer = NullAnalysisPrinter::getInstance(); + } + } + ~IDETabulationProblem() override = default; /// Checks if the given data-flow fact is the special tautological lambda (or @@ -167,6 +177,8 @@ class IDETabulationProblem : public FlowFunctions, IFDSIDESolverConfig SolverConfig{}; [[maybe_unused]] Soundness SF = Soundness::Soundy; + + AnalysisPrinterBase *Printer; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h index 10253527c..01ff03246 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h @@ -5,6 +5,8 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_EXTENDEDVALUE_H #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_EXTENDEDVALUE_H +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + #include #include #include diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 9335838f9..19bdd525a 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -519,38 +519,21 @@ class IDETypeStateAnalysis void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override { LLVMBasedCFG CFG; - OS << "\n======= TYPE STATE RESULTS =======\n"; for (const auto &F : this->IRDB->getAllFunctions()) { - OS << '\n' << F->getName() << '\n'; for (const auto &BB : *F) { for (const auto &I : BB) { auto Results = SR.resultsAt(&I, true); + if (CFG.isExitInst(&I)) { - OS << "\nAt exit stmt: " << NToString(&I) << '\n'; for (auto Res : Results) { if (const auto *Alloca = llvm::dyn_cast(Res.first)) { if (Res.second == TSD->error()) { - OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " - << DToString(Res.first) << '\n'; - for (const auto *Pred : CFG.getPredsOf(&I)) { - OS << "\nPredecessor: " << NToString(Pred) << '\n'; - auto PredResults = SR.resultsAt(Pred, true); - for (auto Res : PredResults) { - if (Res.first == Alloca) { - OS << "Pred State: " << LToString(Res.second) << '\n'; - } - } - } - OS << "============================\n"; - } else { - OS << "\nAlloca : " << DToString(Res.first) - << "\nState : " << LToString(Res.second) << '\n'; + Warning> + Warn(&I, Res.first, TSD->error()); + // ERROR STATE DETECTED + this->Printer->onResult(Warn); } - } else { - OS << "\nInst: " << NToString(&I) << '\n' - << "Fact: " << DToString(Res.first) << '\n' - << "State: " << LToString(Res.second) << '\n'; } } } else { @@ -558,31 +541,19 @@ class IDETypeStateAnalysis if (const auto *Alloca = llvm::dyn_cast(Res.first)) { if (Res.second == TSD->error()) { - OS << "\n=== ERROR STATE DETECTED ===\nAlloca: " - << DToString(Res.first) << '\n' - << "\nAt IR Inst: " << NToString(&I) << '\n'; - for (const auto *Pred : CFG.getPredsOf(&I)) { - OS << "\nPredecessor: " << NToString(Pred) << '\n'; - auto PredResults = SR.resultsAt(Pred, true); - for (auto Res : PredResults) { - if (Res.first == Alloca) { - OS << "Pred State: " << LToString(Res.second) << '\n'; - } - } - } - OS << "============================\n"; + Warning> + Warn(&I, Res.first, TSD->error()); + // ERROR STATE DETECTED + this->Printer->onResult(Warn); } - } else { - OS << "\nInst: " << NToString(&I) << '\n' - << "Fact: " << DToString(Res.first) << '\n' - << "State: " << LToString(Res.second) << '\n'; } } } } } - OS << "\n--------------------------------------------\n"; } + + this->Printer->onFinalize(OS); } private: diff --git a/include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h b/include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h new file mode 100644 index 000000000..9190ead07 --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h @@ -0,0 +1,44 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H +#define PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H + +#include "llvm/Support/raw_ostream.h" + +namespace psr { + +template struct Warning { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using l_t = typename AnalysisDomainTy::l_t; + + n_t Instr; + d_t Fact; + l_t LatticeElement; + + // Constructor + Warning(n_t Inst, d_t DfFact, l_t Lattice) + : Instr(std::move(Inst)), Fact(std::move(DfFact)), + LatticeElement(std::move(Lattice)) {} +}; + +template struct DataflowAnalysisResults { + std::vector> War; +}; + +template class AnalysisPrinterBase { +public: + virtual void onResult(Warning /*War*/) = 0; + virtual void onInitialize() = 0; + virtual void onFinalize(llvm::raw_ostream & /*OS*/) const = 0; + + AnalysisPrinterBase() = default; + virtual ~AnalysisPrinterBase() = default; + AnalysisPrinterBase(const AnalysisPrinterBase &) = delete; + AnalysisPrinterBase &operator=(const AnalysisPrinterBase &) = delete; + + AnalysisPrinterBase(AnalysisPrinterBase &&) = delete; + AnalysisPrinterBase &operator=(AnalysisPrinterBase &&) = delete; +}; + +} // namespace psr + +#endif diff --git a/include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h b/include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h new file mode 100644 index 000000000..7cbdf476b --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h @@ -0,0 +1,47 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H +#define PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H + +#include "phasar/Domain/BinaryDomain.h" +#include "phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/Printer.h" + +#include +#include +#include + +namespace psr { + +template +class DefaultAnalysisPrinter : public AnalysisPrinterBase { + using l_t = typename AnalysisDomainTy::l_t; + +public: + ~DefaultAnalysisPrinter() override = default; + DefaultAnalysisPrinter() = default; + + void onResult(Warning War) override { + AnalysisResults.War.emplace_back(std::move(War)); + } + + void onInitialize() override{}; + void onFinalize(llvm::raw_ostream &OS = llvm::outs()) const override { + for (const auto &Iter : AnalysisResults.War) { + + OS << "\nAt IR statement: " << NToString(Iter.Instr) << "\n"; + + OS << "\tFact: " << DToString(Iter.Fact) << "\n"; + + if constexpr (std::is_same_v) { + OS << "Value: " << LToString(Iter.LatticeElement) << "\n"; + } + } + } + +private: + DataflowAnalysisResults AnalysisResults{}; +}; + +} // namespace psr + +#endif diff --git a/include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h b/include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h new file mode 100644 index 000000000..900767755 --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h @@ -0,0 +1,25 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_NULLANALYSISPRINTER_H +#define PHASAR_PHASARLLVM_UTILS_NULLANALYSISPRINTER_H + +#include "phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h" + +namespace psr { + +template +class NullAnalysisPrinter final : public AnalysisPrinterBase { +public: + static NullAnalysisPrinter *getInstance() { + static auto Instance = NullAnalysisPrinter(); + return &Instance; + } + + void onInitialize() override{}; + void onResult(Warning /*War*/) override{}; + void onFinalize(llvm::raw_ostream & /*OS*/) const override{}; + +private: + NullAnalysisPrinter() = default; +}; + +} // namespace psr +#endif diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp index d3dd8fd76..6759ed4b9 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @@ -227,6 +227,9 @@ void IDEExtendedTaintAnalysis::reportLeakIfNecessary( const llvm::Value *LeakCandidate) { if (isSink(SinkCandidate, Inst)) { Leaks[Inst].insert(LeakCandidate); + Warning Warn( + Inst, makeFlowFact(LeakCandidate), Top{}); + Printer->onResult(Warn); } } @@ -744,19 +747,20 @@ auto IDEExtendedTaintAnalysis::getSummaryEdgeFunction(n_t Curr, d_t CurrNode, void IDEExtendedTaintAnalysis::emitTextReport( const SolverResults &SR, llvm::raw_ostream &OS) { - OS << "===== IDEExtendedTaintAnalysis-Results =====\n"; if (!PostProcessed) { doPostProcessing(SR); } for (auto &[Inst, LeakSet] : Leaks) { - OS << "At " << NToString(Inst) << '\n'; for (const auto &Leak : LeakSet) { - OS << "\t" << llvmIRToShortString(Leak) << "\n"; + Warning Warn(Inst, makeFlowFact(Leak), + Top{}); + Printer->onResult(Warn); } } - OS << '\n'; + + Printer->onFinalize(OS); } // Helpers: diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.cpp index 2877e3086..d65e8ea9c 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.cpp @@ -9,6 +9,8 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Value.h" diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp index 8b1eb7341..53d6099e7 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.cpp @@ -28,14 +28,13 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/Support/raw_ostream.h" #include #include #include #include -#include - namespace psr { IFDSFieldSensTaintAnalysis::IFDSFieldSensTaintAnalysis( diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index c7b2b6f72..a6ee4458b 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -16,6 +16,7 @@ #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h" #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" @@ -408,7 +409,11 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, this, CallSite](d_t Source) -> container_type { if (Leak.count(Source)) { - Leaks[CallSite].insert(Source); + if (Leaks[CallSite].insert(Source).second) { + Warning Warn(CallSite, Source, + topElement()); + Printer->onResult(Warn); + } } if (Kill.count(Source)) { @@ -433,7 +438,11 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, } if (Leak.count(Source)) { - Leaks[CallSite].insert(Source); + if (Leaks[CallSite].insert(Source).second) { + Warning Warn(CallSite, Source, + topElement()); + Printer->onResult(Warn); + } } return {Source}; @@ -478,25 +487,7 @@ void IFDSTaintAnalysis::emitTextReport( const SolverResults & /*SR*/, llvm::raw_ostream &OS) { OS << "\n----- Found the following leaks -----\n"; - if (Leaks.empty()) { - OS << "No leaks found!\n"; - return; - } - - for (const auto &Leak : Leaks) { - OS << "At instruction\nIR : " << llvmIRToString(Leak.first) << '\n'; - OS << "\nLeak(s):\n"; - for (const auto *LeakedValue : Leak.second) { - OS << "IR : "; - // Get the actual leaked alloca instruction if possible - if (const auto *Load = llvm::dyn_cast(LeakedValue)) { - OS << llvmIRToString(Load->getPointerOperand()) << '\n'; - } else { - OS << llvmIRToString(LeakedValue) << '\n'; - } - } - OS << "-------------------\n"; - } + Printer->onFinalize(OS); } } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp index e71e30b0e..04d8eba6e 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp @@ -9,14 +9,13 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" #include -#include - using namespace std; using namespace psr; diff --git a/unittests/Utils/AnalysisPrinterTest.cpp b/unittests/Utils/AnalysisPrinterTest.cpp new file mode 100644 index 000000000..8f1dfb70f --- /dev/null +++ b/unittests/Utils/AnalysisPrinterTest.cpp @@ -0,0 +1,128 @@ +#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h" +#include "phasar/PhasarLLVM/HelperAnalyses.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" +#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" +#include "phasar/PhasarLLVM/TaintConfig/TaintConfigData.h" +#include "phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + +#include "llvm/ADT/DenseMap.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" +using namespace psr; +using CallBackPairTy = std::pair::config_callback_t, + IDEExtendedTaintAnalysis<>::config_callback_t>; + +// Use template to variate between Typesate and Taint analysis +class GroundTruthCollector + : public DefaultAnalysisPrinter { +public: + // constructor init Groundtruth in each fixture + GroundTruthCollector(llvm::DenseMap> &GroundTruth) + : GroundTruth(GroundTruth){}; + + void findAndRemove(llvm::DenseMap> &Map1, + llvm::DenseMap> &Map2) { + for (auto Entry = Map1.begin(); Entry != Map1.end();) { + auto Iter = Map2.find(Entry->first); + if (Iter != Map2.end() && Iter->second == Entry->second) { + Map2.erase(Iter); + } + ++Entry; + } + } + + void onResult(Warning War) override { + llvm::DenseMap> FoundLeak; + int SinkId = stoi(getMetaDataID(War.Instr)); + std::set LeakedValueIds; + LeakedValueIds.insert(getMetaDataID((War.Fact)->base())); + FoundLeak.try_emplace(SinkId, LeakedValueIds); + findAndRemove(FoundLeak, GroundTruth); + } + + void onFinalize(llvm::raw_ostream & /*OS*/ = llvm::outs()) const override { + EXPECT_TRUE(GroundTruth.empty()); + } + +private: + llvm::DenseMap> GroundTruth{}; +}; + +class AnalysisPrinterTest : public ::testing::Test { +protected: + static constexpr auto PathToLlFiles = PHASAR_BUILD_SUBFOLDER("xtaint/"); + const std::vector EntryPoints = {"main"}; + + void doAnalysisTest( + llvm::StringRef IRFile, GroundTruthCollector >Printer, + std::variant Config) { + HelperAnalyses Helpers(PathToLlFiles + IRFile, EntryPoints); + + auto TConfig = std::visit( + Overloaded{[&](std::monostate) { + return LLVMTaintConfig(Helpers.getProjectIRDB()); + }, + [&](TaintConfigData *JS) { + auto Ret = LLVMTaintConfig(Helpers.getProjectIRDB(), *JS); + return Ret; + }, + [&](CallBackPairTy &&CB) { + return LLVMTaintConfig(std::move(CB.first), + std::move(CB.second)); + }}, + std::move(Config)); + + auto TaintProblem = createAnalysisProblem>( + Helpers, TConfig, EntryPoints); + + TaintProblem.setAnalysisPrinter(>Printer); + IDESolver Solver(TaintProblem, &Helpers.getICFG()); + Solver.solve(); + + TaintProblem.emitTextReport(Solver.getSolverResults()); + } +}; + +/* ============== BASIC TESTS ============== */ + +TEST_F(AnalysisPrinterTest, HandleBasicTest_01) { + llvm::DenseMap> GroundTruth; + GroundTruth[7] = {"0"}; + + TaintConfigData Config; + + FunctionData FuncDataMain; + FuncDataMain.Name = "main"; + FuncDataMain.SourceValues.push_back(0); + + FunctionData FuncDataPrint; + FuncDataPrint.Name = "_Z5printi"; + FuncDataPrint.SinkValues.push_back(0); + + Config.Functions.push_back(std::move(FuncDataMain)); + Config.Functions.push_back(std::move(FuncDataPrint)); + + GroundTruthCollector GroundTruthPrinter = {GroundTruth}; + doAnalysisTest("xtaint01_json_cpp_dbg.ll", GroundTruthPrinter, &Config); +} + +TEST_F(AnalysisPrinterTest, XTaint01) { + llvm::DenseMap> GroundTruth; + + GroundTruth[15] = {"8"}; + GroundTruthCollector GroundTruthPrinter = {GroundTruth}; + doAnalysisTest("xtaint01_cpp.ll", GroundTruthPrinter, std::monostate{}); +} + +// main function for the test case +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} diff --git a/unittests/Utils/CMakeLists.txt b/unittests/Utils/CMakeLists.txt index 4edc79c48..fea979d61 100644 --- a/unittests/Utils/CMakeLists.txt +++ b/unittests/Utils/CMakeLists.txt @@ -6,6 +6,7 @@ set(UtilsSources LLVMShorthandsTest.cpp PAMMTest.cpp StableVectorTest.cpp + AnalysisPrinterTest.cpp ) if(PHASAR_ENABLE_DYNAMIC_LOG) From b07f56ab7d87e36290001f6ed3d5d181fb83b6a5 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Mon, 27 Nov 2023 17:45:19 +0100 Subject: [PATCH 46/59] Path Tracing (#640) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add explicit ExplodedSuperGraph and a version of the IDESolver that fills it with content. TODO: Add PathSensitivityManager + unittests * Add more TODOs * Add GraphTraits * Add pathsDagTo (not tested yet) * Add Z3 submodule * Set Z3 version * Add Z3-related stuff (WIP) * Added now basic functionality for path sensitivity (compiles, but not tested yet) * Implement LLVMPathConstraints * Add unittest for PathTracking (C/C++ test files are still missing) and resolve a lot of compilation errors * Make a lot of the unittests work (still not completed) * Fix Config propagation * Finally, fix all unittests * minor * redirect z3 submodule * Checkout the right z3 branch * bump z3 * add bulk dag-generation (not tested yet) * Some more fixes * Add filters to PSM * Better integrate filter into PSM * minor * Improve on reverseDAG * minor improvements in reverseDAG * Bump z3 * Fix depdendency issue with utils->config * Fix bugs indiced by reverse merging from development + bump z3 * Make Z3 optional * Workaround weird cmake behavior * Fix seeds in exploded supergraph * Add forward minimize graph * Add one Test for forward minimize DAG * Fix in createEquivalentGraphFrom * Fix filterOutUnreachableNodes * Fix: DFAMinimizer edge comparison * Fix compilation on ubuntu22 * Improve createEquivalentGraphFrom * Resolve errors due to merging * Fix z3 dependency * Fix UAF when copying an ExplicitESG * Get rid of NodeRef::DSI * Fix compile error due to merge * minor * More const in Table * Give the PathTracing Filters more power * Fix null error * Fix Path Tracing with chaotic edge saving due to new Worklist structure in IDESolver * Some cleanup * pre-commit * Apply some review comments * Write ESG to temp file instead of hard-coded file * minor * pre-commitIDESolver.h * pre-commit Utilities.h * trailing whitespace IDESolver.h * Fix errors due to merge * Integrate free-functions NToString and DToString into ExplicitESG * Adapt invariants due to chaotic solving (worklist vs recursion) * Add LLVMSSA version of pathsDagTo as temporary solution until f-IDESolverStrategy is merged * minor * Use system z3 * Find z3 from psr installation * Assert size overflow * Enable Z3 in CI * fix naming issue --------- Co-authored-by: Fabian Benedikt Schiebel Co-authored-by: Sebastian Böhm Co-authored-by: Martin Mory --- .clang-tidy | 2 +- .github/workflows/ci.yml | 1 + CMakeLists.txt | 23 +- Config.cmake.in | 5 + include/phasar/DataFlow.h | 3 + .../DataFlow/IfdsIde/Solver/ESGEdgeKind.h | 22 + .../DataFlow/IfdsIde/Solver/IDESolver.h | 27 +- .../IfdsIde/Solver/PathAwareIDESolver.h | 69 ++ .../phasar/DataFlow/IfdsIde/SolverResults.h | 1 + .../PathSensitivity/ExplodedSuperGraph.h | 382 ++++++++ .../DataFlow/PathSensitivity/FlowPath.h | 59 ++ .../PathSensitivity/PathSensitivityConfig.h | 57 ++ .../PathSensitivity/PathSensitivityManager.h | 54 ++ .../PathSensitivityManagerBase.h | 191 ++++ .../PathSensitivityManagerMixin.h | 342 +++++++ .../PathSensitivity/PathTracingFilter.h | 51 ++ .../PathSensitivity/LLVMPathConstraints.h | 97 ++ .../Z3BasedPathSensitivityConfig.h | 41 + .../Z3BasedPathSensitvityManager.h | 186 ++++ include/phasar/Utils/AdjacencyList.h | 301 ++++++ include/phasar/Utils/DFAMinimizer.h | 196 ++++ include/phasar/Utils/GraphTraits.h | 213 +++++ include/phasar/Utils/IotaIterator.h | 73 ++ include/phasar/Utils/MaybeUniquePtr.h | 98 +- include/phasar/Utils/RepeatIterator.h | 84 ++ include/phasar/Utils/StableVector.h | 42 +- include/phasar/Utils/TypeTraits.h | 17 +- include/phasar/Utils/Utilities.h | 26 + lib/PhasarLLVM/DataFlow/CMakeLists.txt | 1 + .../DataFlow/PathSensitivity/CMakeLists.txt | 44 + .../PathSensitivity/LLVMPathConstraints.cpp | 659 ++++++++++++++ .../PathSensitivityManagerBase.cpp | 5 + .../Z3BasedPathSensitivityManager.cpp | 580 ++++++++++++ lib/PhasarLLVM/Utils/LLVMShorthands.cpp | 13 + .../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 + tools/example-tool/myphasartool.cpp | 3 + tools/phasar-cli/phasar-cli.cpp | 6 +- unittests/PhasarLLVM/DataFlow/CMakeLists.txt | 1 + .../DataFlow/PathSensitivity/CMakeLists.txt | 9 + .../PathSensitivity/PathTracingTest.cpp | 861 ++++++++++++++++++ 62 files changed, 5090 insertions(+), 91 deletions(-) create mode 100644 include/phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h create mode 100644 include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h create mode 100644 include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h create mode 100644 include/phasar/DataFlow/PathSensitivity/FlowPath.h create mode 100644 include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h create mode 100644 include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h create mode 100644 include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h create mode 100644 include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h create mode 100644 include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h create mode 100644 include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h create mode 100644 include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h create mode 100644 include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h create mode 100644 include/phasar/Utils/AdjacencyList.h create mode 100644 include/phasar/Utils/DFAMinimizer.h create mode 100644 include/phasar/Utils/GraphTraits.h create mode 100644 include/phasar/Utils/IotaIterator.h create mode 100644 include/phasar/Utils/RepeatIterator.h create mode 100644 lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt create mode 100644 lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp create mode 100644 lib/PhasarLLVM/DataFlow/PathSensitivity/PathSensitivityManagerBase.cpp create mode 100644 lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp 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 create mode 100644 unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt create mode 100644 unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp diff --git a/.clang-tidy b/.clang-tidy index 5d40d294d..8447efed9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -31,7 +31,7 @@ Checks: '-*, modernize-*, -modernize-use-trailing-return-type, performance-*, - clang-analyzer-*, + clang-analyzer-* ' FormatStyle: LLVM diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d109a180f..67a32f1a5 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_USE_Z3=ON \ ${{ matrix.flags }} \ -G Ninja cmake --build . diff --git a/CMakeLists.txt b/CMakeLists.txt index a32ac2bc2..ab524715d 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) @@ -150,6 +150,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_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) option(PHASAR_ENABLE_CLANG_TIDY_DURING_BUILD "Run clang-tidy during build (default is OFF)" OFF) @@ -259,11 +261,13 @@ add_subdirectory(external/json) # 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") if (PHASAR_IN_TREE) set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json_schema_validator) + + set (PHASAR_USE_Z3 OFF) endif() # Json Schema Validator @@ -337,6 +341,21 @@ if(NOT LLVM_ENABLE_RTTI AND NOT PHASAR_IN_TREE) message(FATAL_ERROR "PhASAR requires a LLVM version that is built with RTTI") endif() +# Z3 Solver +if(PHASAR_USE_Z3) + # 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) + + if(NOT TARGET z3) + add_library(z3 IMPORTED SHARED) + set_property(TARGET z3 PROPERTY + IMPORTED_LOCATION ${Z3_LIBRARIES}) + set_property(TARGET z3 PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${Z3_INCLUDE_DIR}) + endif() +endif(PHASAR_USE_Z3) + # Clang option(BUILD_PHASAR_CLANG "Build the phasar_clang library (default is ON)" ON) diff --git a/Config.cmake.in b/Config.cmake.in index 5828af35e..8093b5f78 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() set(PHASAR_COMPONENTS utils diff --git a/include/phasar/DataFlow.h b/include/phasar/DataFlow.h index a642ae484..88453a251 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 new file mode 100644 index 000000000..94b98ed89 --- /dev/null +++ b/include/phasar/DataFlow/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_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H +#define PHASAR_DATAFLOW_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_DATAFLOW_IFDSIDE_SOLVER_ESGEDGEKIND_H diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index cfe82bacf..36b782b4c 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -26,6 +26,7 @@ #include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/DataFlow/IfdsIde/InitialSeeds.h" +#include "phasar/DataFlow/IfdsIde/Solver/ESGEdgeKind.h" #include "phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h" #include "phasar/DataFlow/IfdsIde/Solver/IDESolverAPIMixin.h" #include "phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h" @@ -297,20 +298,25 @@ class IDESolver } }); + 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); INC_COUNTER("SpecialSummary-FF Application", 1, Full); ADD_TO_HISTOGRAM("Data-flow facts", Res.size(), 1, Full); - saveEdges(n, ReturnSiteN, d2, Res, false); + saveEdges(n, ReturnSiteN, d2, Res, ESGEdgeKind::Summary); for (d_t d3 : Res) { EdgeFunction SumEdgFnE = CachedFlowEdgeFunctions.getSummaryEdgeFunction(n, d2, @@ -341,7 +347,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 = typename Table>::Cell; @@ -382,7 +389,7 @@ class IDESolver RetFunction, d3, d4, n, Container{d2}); ADD_TO_HISTOGRAM("Data-flow facts", ReturnedFacts.size(), 1, 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 @@ -439,7 +446,9 @@ class IDESolver container_type ReturnFacts = computeCallToReturnFlowFunction(CallToReturnFF, d1, d2); ADD_TO_HISTOGRAM("Data-flow facts", ReturnFacts.size(), 1, Full); - saveEdges(n, ReturnSiteN, d2, ReturnFacts, false); + saveEdges(n, ReturnSiteN, d2, ReturnFacts, + HasNoCalleeInformation ? ESGEdgeKind::SkipUnknownFn + : ESGEdgeKind::CallToRet); for (d_t d3 : ReturnFacts) { EdgeFunction EdgeFnE = CachedFlowEdgeFunctions.getCallToRetEdgeFunction(n, d2, ReturnSiteN, @@ -478,7 +487,7 @@ class IDESolver INC_COUNTER("FF Queries", 1, Full); const container_type Res = computeNormalFlowFunction(FlowFunc, d1, d2); ADD_TO_HISTOGRAM("Data-flow facts", Res.size(), 1, Full); - saveEdges(n, nPrime, d2, Res, false); + saveEdges(n, nPrime, d2, Res, ESGEdgeKind::Normal); for (d_t d3 : Res) { EdgeFunction g = CachedFlowEdgeFunctions.getNormalEdgeFunction(n, d2, nPrime, d3); @@ -690,12 +699,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()); } @@ -833,7 +842,7 @@ class IDESolver const container_type Targets = computeReturnFlowFunction(RetFunction, d1, d2, c, Entry.second); ADD_TO_HISTOGRAM("Data-flow facts", Targets.size(), 1, 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) { @@ -902,7 +911,7 @@ class IDESolver const container_type Targets = computeReturnFlowFunction( RetFunction, d1, d2, Caller, Container{ZeroValue}); ADD_TO_HISTOGRAM("Data-flow facts", Targets.size(), 1, Full); - saveEdges(n, RetSiteC, d2, Targets, true); + saveEdges(n, RetSiteC, d2, Targets, ESGEdgeKind::Ret); for (d_t d5 : Targets) { EdgeFunction f5 = CachedFlowEdgeFunctions.getReturnEdgeFunction( diff --git a/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h new file mode 100644 index 000000000..711932c87 --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathAwareIDESolver.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * 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_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" +#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; + +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, const i_t *ICF) + : base_t(Problem, ICF), ESG(Problem.getZeroValue()) { + + 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; + } + + [[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 { + ESG.saveEdges(std::move(Curr), std::move(CurrNode), std::move(Succ), + SuccNodes, Kind); + } + + ExplodedSuperGraph ESG; +}; + +template +PathAwareIDESolver(ProblemTy &) + -> PathAwareIDESolver; + +} // namespace psr + +#endif // PHASAR_DATAFLOW_IFDSIDE_SOLVER_PATHAWAREIDESOLVER_H diff --git a/include/phasar/DataFlow/IfdsIde/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h index 512d80063..65da6d5e8 100644 --- a/include/phasar/DataFlow/IfdsIde/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -232,6 +232,7 @@ class OwningSolverResults [[nodiscard]] operator SolverResults() const &noexcept { return get(); } + operator SolverResults() && = delete; private: diff --git a/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h new file mode 100644 index 000000000..df9d1ec3c --- /dev/null +++ b/include/phasar/DataFlow/PathSensitivity/ExplodedSuperGraph.h @@ -0,0 +1,382 @@ +/****************************************************************************** + * 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_DATAFLOW_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H +#define PHASAR_DATAFLOW_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" +#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 +#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; + + struct Node { + static constexpr size_t NoPredId = ~size_t(0); + }; + + struct NodeData { + d_t Value{}; + n_t Source{}; + }; + + 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); + } + + 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(d_t ZeroValue) noexcept( + std::is_nothrow_move_constructible_v) + : ZeroValue(std::move(ZeroValue)) {} + + 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( + std::make_pair(std::move(Inst), std::move(Fact))); + if (It != FlowFactVertexMap.end()) { + return NodeRef(It->second, this); + } + return nullptr; + } + + [[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, + ESGEdgeKind Kind) { + 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 + bool MaySkipEdge = Kind == ESGEdgeKind::CallToRet && CurrNode == ZeroValue; + for (const d_t &SuccNode : SuccNodes) { + saveEdge(PredId, Curr, CurrNode, Succ, SuccNode, MaySkipEdge); + } + } + + // NOLINTNEXTLINE(readability-identifier-naming) + [[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 { + assert(NodeAdjOwner.size() == NodeDataOwner.size()); + return llvm::map_iterator(llvm::seq(size_t(0), NodeDataOwner.size()).end(), + BuildNodeRef(this)); + } + [[nodiscard]] auto nodes() const noexcept { + assert(NodeAdjOwner.size() == NodeDataOwner.size()); + return llvm::map_range(llvm::seq(size_t(0), NodeDataOwner.size()), + BuildNodeRef(this)); + } + + [[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 (size_t I = 0, End = NodeDataOwner.size(); I != End; ++I) { + auto Nod = NodeRef(I, this); + OS << I << "[label=\""; + OS.write_escaped(DToString(Nod.value())) << "\"];\n"; + + OS << I << "->" << intptr_t(Nod.predecessor().id()) + << R"([style="bold" label=")"; + OS.write_escaped(NToString(Nod.source())) << "\"];\n"; + for (auto NB : Nod.neighbors()) { + OS << I << "->" << NB.id() << "[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, _] : FlowFactVertexMap) { + OS << "( " << NToString(Node.first) << "; " << 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; + } + }; + + [[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; + } + + void saveEdge(std::optional PredId, n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode, bool MaySkipEdge) { + 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; + + if (!PredId) { + // For the seeds: Just that the FlowFactVertexMap is filled at that + // position... + FlowFactVertexMap[std::make_pair(Curr, CurrNode)] = Ret; + } + + NodAdj.PredecessorIdx = PredId.value_or(Node::NoPredId); + NodData.Source = Curr; + + return Ret; + }; + + 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) { + SuccVtxNode = makeNode(); + NodeAdjOwner.back().PredecessorIdx = Node::NoPredId; + } + return; + } + + 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) { + SuccVtxNode = *PredId; + return; + } + + // This edge has already been here?! + if (*PredId == SuccVtxNode) { + return; + } + } + + if (Inserted) { + SuccVtxNode = makeNode(); + return; + } + + // 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(SuccVtxNode, this); + if (!SuccVtx.predecessor()) { + NodeAdjOwner[SuccVtxNode].PredecessorIdx = + PredId.value_or(Node::NoPredId); + NodeDataOwner[SuccVtxNode].Source = Curr; + 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) { + return Nd.predecessor().id() == Pred; + })) { + + auto NewNode = makeNode(); + NodeAdjOwner[SuccVtxNode].Neighbors.push_back(NewNode); + return; + } + } + + std::vector NodeDataOwner; + std::vector NodeAdjOwner; + std::unordered_map, size_t, PathInfoHash, PathInfoEq> + FlowFactVertexMap{}; + + // ZeroValue + d_t ZeroValue; +}; + +} // namespace psr + +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_EXPLODEDSUPERGRAPH_H diff --git a/include/phasar/DataFlow/PathSensitivity/FlowPath.h b/include/phasar/DataFlow/PathSensitivity/FlowPath.h new file mode 100644 index 000000000..532852ab0 --- /dev/null +++ b/include/phasar/DataFlow/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 "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" + +#include "z3++.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/DataFlow/PathSensitivity/PathSensitivityConfig.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h new file mode 100644 index 000000000..582dd02b1 --- /dev/null +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * 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_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H + +#include +#include + +namespace psr { + +template struct PathSensitivityConfigBase { + size_t DAGSizeThreshold = SIZE_MAX; + size_t DAGDepthThreshold = SIZE_MAX; + size_t NumPathsThreshold = SIZE_MAX; + bool MinimizeDAG = true; + + [[nodiscard]] DerivedConfig + withDAGSizeThreshold(size_t MaxDAGSize) const noexcept { + auto Ret = *static_cast(this); + Ret.DAGSizeThreshold = MaxDAGSize; + return Ret; + } + + [[nodiscard]] DerivedConfig + withDAGDepthThreshold(size_t MaxDAGDepth) const noexcept { + auto Ret = *static_cast(this); + Ret.DAGDepthThreshold = MaxDAGDepth; + return Ret; + } + + [[nodiscard]] DerivedConfig + withNumPathsThreshold(size_t MaxNumPaths) const noexcept { + auto Ret = *static_cast(this); + Ret.NumPathsThreshold = MaxNumPaths; + return Ret; + } + + [[nodiscard]] DerivedConfig withMinimizeDAG(bool DoMinimize) const noexcept { + auto Ret = *static_cast(this); + Ret.MinimizeDAG = DoMinimize; + return Ret; + } +}; + +struct PathSensitivityConfig + : PathSensitivityConfigBase {}; + +} // namespace psr + +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYCONFIG_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h new file mode 100644 index 000000000..d781d127f --- /dev/null +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManager.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * 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_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_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" +#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 + : 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 typename PathSensitivityManagerBase::graph_type; + + PathSensitivityManager( + const ExplodedSuperGraph *ESG) noexcept + : mixin_t(ESG) {} +}; +} // namespace psr + +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGER_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h new file mode 100644 index 000000000..e1195bb57 --- /dev/null +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h @@ -0,0 +1,191 @@ +/****************************************************************************** + * 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_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H + +#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 +class PathSensitivityManagerMixin; + +template class PathSensitivityManagerBase { +public: + using n_t = N; + using graph_type = AdjacencyList>; + + 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: + [[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)); + + // 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; + }; + + for (auto Rt : graph_traits_t::roots(Dag)) { + if (!doAssertIsDAG(doAssertIsDAG, Rt)) { + return false; + } + } + + return true; + } + + template + [[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); + } + + // 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 + + 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 + static constexpr size_t MaxNumBytesInStackBuf = 8192; + + auto *Buf = NumBytes <= MaxNumBytesInStackBuf + ? reinterpret_cast(alloca(NumBytes)) + : new char[NumBytes]; + std::unique_ptr Owner; // NOLINT + if (NumBytes > MaxNumBytesInStackBuf) { + Owner.reset(Buf); + } + + auto Cache = reinterpret_cast(Buf); + std::uninitialized_fill_n(Cache, EquivSize, graph_traits_t::Invalid); + + auto *WLConsumeBegin = + reinterpret_cast *>(Cache + EquivSize); + auto *WLConsumeEnd = WLConsumeBegin; + auto *WLInsertBegin = WLConsumeBegin + EquivSize; + auto *WLInsertEnd = WLInsertBegin; + + for (auto Rt : graph_traits_t::roots(Dag)) { + size_t Eq = std::invoke(Equiv, Rt); + if (Cache[Eq] == graph_traits_t::Invalid) { + Cache[Eq] = graph_traits_t::addNode(Ret, graph_traits_t::node(Dag, Rt)); + *WLConsumeEnd++ = {Rt, Cache[Eq]}; + } + } + + size_t Depth = 0; + + 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); + size_t Eq = std::invoke(Equiv, SuccVtx); + if (Cache[Eq] == graph_traits_t::Invalid) { + Cache[Eq] = graph_traits_t::addNode( + Ret, graph_traits_t::node(Dag, SuccVtx)); + *WLInsertEnd++ = {SuccVtx, Cache[Eq]}; + } + + 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); + } + } + + std::swap(WLConsumeBegin, WLInsertBegin); + WLConsumeEnd = std::exchange(WLInsertEnd, WLInsertBegin); + ++Depth; + } + + 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); + } + + 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_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERBASE_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h new file mode 100644 index 000000000..6a986d99c --- /dev/null +++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h @@ -0,0 +1,342 @@ +/****************************************************************************** + * 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_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_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/PhasarLLVM/Utils/LLVMIRToSrc.h" +#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" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include + +namespace llvm { +class DbgInfoIntrinsic; +} // namespace llvm + +namespace psr { +template +class PathSensitivityManagerMixin { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + + 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::SetVector> CurrPath; + }; + + static const ExplodedSuperGraph & + assertNotNull(const 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: + template < + typename FactsRangeTy, typename ConfigTy, + typename Filter = DefaultPathTracingFilter, + typename = std::enable_if_t>> + [[nodiscard]] GraphType + pathsDagToAll(n_t Inst, FactsRangeTy FactsRange, + 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)); + + 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(tmpnam(nullptr)) + "-explicitesg-err.dot"; + + { + std::error_code EC; + llvm::raw_fd_ostream ROS(FileName, EC); + ESG.printAsDot(ROS); + } + + llvm::errs() << "> ESG written to " << FileName << '\n'; + llvm::errs().flush(); + + abort(); + } + + /// 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); + } + } + +#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.DAGDepthThreshold != SIZE_MAX) { + Dag = Derived::reverseDAG(std::move(Dag), Config.DAGDepthThreshold); + } else { + Dag = reverseGraph(std::move(Dag)); + } + + if (Config.MinimizeDAG) { + + auto Equiv = minimizeGraph(Dag); + + Dag = createEquivalentGraphFrom(std::move(Dag), Equiv); + +#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 + } + + return Dag; + } + + 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 Filter &PFilter = {}) const { + auto Res = SR.resultsAt(Inst); + auto FactsRange = llvm::make_first_range(Res); + return pathsDagToAll(std::move(Inst), FactsRange, Config, PFilter); + } + + template < + typename ConfigTy, typename Filter = DefaultPathTracingFilter, + typename = std::enable_if_t>> + [[nodiscard]] GraphType + pathsDagTo(n_t Inst, d_t Fact, + const PathSensitivityConfigBase &Config, + const Filter &PFilter = {}) const { + + return pathsDagToAll(std::move(Inst), llvm::ArrayRef(&Fact, 1), Config, + 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, + graph_type &RetDag, const Filter &PFilter) const { + NodeRef Prev; + bool IsEnd = false; + bool IsError = false; + + do { + Prev = Vtx; + graph_traits_t::node(RetDag, Ret).push_back(Vtx.source()); + + Vtx = Vtx.predecessor(); + + if (PFilter.HasReachedEnd(Prev, Vtx)) { + IsEnd = true; + } else if (PFilter.IsErrorneousTransition(Prev, Vtx)) { + IsError = true; + } + + if (!Vtx) { + return !IsError; + } + + if (IsEnd || IsError) { + break; + } + + } while (!Vtx.hasNeighbors()); + + 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, &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); + } + }; + + 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); + } + + graph_traits_t::dedupOutEdges(RetDag, Ret); + + return IsEnd || graph_traits_t::outDegree(RetDag, Ret) != 0; + } + + template + 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 + + auto [It, Inserted] = + Ctx.Cache.try_emplace(Vtx.id(), graph_traits_t::Invalid); + if (!Inserted) { + return It->second; + } + + 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, PFilter)) { + /// NOTE: Don't erase Vtx from Cache to guarantee termination + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) -- fp + 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); + graph_traits_t::node(RetDag, Ret).clear(); + } + + return graph_traits_t::Invalid; + } + return Ret; + } + + template + 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()) { + auto NBNode = pathsToImplLA(NB, Ctx, RetDag, PFilter); + if (NBNode != graph_traits_t::Invalid) { + graph_traits_t::addEdge(RetDag, Ret, NBNode); + } + } + auto VtxNode = pathsToImplLA(Vtx, Ctx, RetDag, PFilter); + if (VtxNode != graph_traits_t::Invalid) { + graph_traits_t::addEdge(RetDag, Ret, VtxNode); + } + + graph_traits_t::dedupOutEdges(RetDag, Ret); + + return Ret; + } + + const ExplodedSuperGraph &ESG; +}; +} // namespace psr + +#endif // PHASAR_DATAFLOW_PATHSENSITIVITY_PATHSENSITIVITYMANAGERMIXIN_H diff --git a/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h b/include/phasar/DataFlow/PathSensitivity/PathTracingFilter.h new file mode 100644 index 000000000..8baaa1096 --- /dev/null +++ b/include/phasar/DataFlow/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_DATAFLOW_PATHSENSITIVITY_PATHTRACINGFILTER_H +#define PHASAR_DATAFLOW_PATHSENSITIVITY_PATHTRACINGFILTER_H + +#include + +namespace psr { +template struct PathTracingFilter { + using end_filter_t = EndFilter; + using err_filter_t = ErrFilter; + + [[no_unique_address]] end_filter_t HasReachedEnd; + [[no_unique_address]] err_filter_t 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< + PathTracingFilter, NodeRef, + 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_DATAFLOW_PATHSENSITIVITY_PATHTRACINGFILTER_H diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h new file mode 100644 index 000000000..887f4f54b --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * 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_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H +#define PHASAR_PHASARLLVM_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_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 { +public: + struct ConstraintAndVariables { + z3::expr Constraint; + llvm::SmallVector Variables; + }; + + 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); + + std::optional + getConstraintAndVariablesFromEdge(const llvm::Instruction *Curr, + const llvm::Instruction *Succ); + +private: + [[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 SizeGuardCheck; + friend class LoopGuardCheck; + + MaybeUniquePtr Z3Ctx; + std::unordered_map Z3Expr; + bool IgnoreDebugInstructions; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_PATHSENSITIVITY_LLVMPATHCONSTRAINTS_H diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h new file mode 100644 index 000000000..3d219f5fc --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityConfig.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * 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_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H +#define PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H + +#include "phasar/DataFlow/PathSensitivity/PathSensitivityConfig.h" + +#include "z3++.h" + +#include + +namespace psr { +struct Z3BasedPathSensitivityConfig + : PathSensitivityConfigBase { + 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_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYCONFIG_H diff --git a/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h new file mode 100644 index 000000000..988a977c4 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitvityManager.h @@ -0,0 +1,186 @@ +/****************************************************************************** + * 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_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H +#define PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_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" +#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 +#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!"); + +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; + + static void deduplicatePaths(FlowPathSequence &Paths); +}; + +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; + using MaybeFlowPathSeq = std::variant, z3::expr>; + + 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!"); + } + + 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-" + + 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() << "Paths DAG has " << Dag.Roots.size() << " roots\n"; + } +#endif + + 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(); + } + + 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(); + PHASAR_LOG_LEVEL_CAT(DEBUG, "PathSensitivityManager", Str); + } + +#endif // DYNAMIC_LOG +#endif // NDEBUG + + return Ret; + } + +private: + Z3BasedPathSensitivityConfig Config{}; + /// FIXME: Not using 'mutable' here + mutable MaybeUniquePtr LPC{}; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_PATHSENSITIVITY_Z3BASEDPATHSENSITIVITYMANAGER_H diff --git a/include/phasar/Utils/AdjacencyList.h b/include/phasar/Utils/AdjacencyList.h new file mode 100644 index 000000000..e09bb99fa --- /dev/null +++ b/include/phasar/Utils/AdjacencyList.h @@ -0,0 +1,301 @@ +/****************************************************************************** + * 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 "phasar/Utils/Utilities.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" + +#include +#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{}; +}; + +/// A simple graph implementation based on an adjacency list +template +struct GraphTraits> { + using graph_type = AdjacencyList; + 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; + + /// 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 + /// + /// \returns The vertex-descriptor for the newly created node + 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; + } + + /// 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) { + auto Ret = G.Adj.size(); + G.Adj.emplace_back(); + 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) { + assert(Vtx < G.Adj.size()); + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + 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()); + } + return G.Roots; + } + + /// 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) { + assert(G.Adj.size() == G.Nodes.size()); + } + 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 { + assert(Vtx < G.Adj.size()); + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + 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 { + assert(Vtx < G.Adj.size()); + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + 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 { + assert(Vtx < G.Adj.size()); + if constexpr (!std::is_same_v) { + 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()); + } + + /// 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 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 RepeatRangeType nodes(const graph_type &G) noexcept { + 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(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 { + assert(Vtx < G.Nodes.size()); + 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 { + assert(Vtx < G.Nodes.size()); + 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 llvm::NoneType node([[maybe_unused]] const graph_type &G, + [[maybe_unused]] vertex_t Vtx) noexcept { + assert(Vtx < G.Adj.size()); + 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()); + } + 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 { // NOLINT + 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()); + G.Nodes.reserve(Capacity); + } + + 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(); + if constexpr (!std::is_same_v) { + G.Nodes.pop_back(); + } + return true; + } + 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 parameter 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 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.Adj.size()); + if constexpr (!std::is_same_v) { + assert(G.Adj.size() == G.Nodes.size()); + } + 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; + } + + /// 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()); + } + 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 + static_assert(is_graph>); + static_assert(is_reservable_graph_trait>>); +#endif +}; + +} // 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 000000000..00a20f0db --- /dev/null +++ b/include/phasar/Utils/DFAMinimizer.h @@ -0,0 +1,196 @@ +/****************************************************************************** + * 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 "phasar/Utils/Utilities.h" + +#include "llvm/ADT/IntEqClasses.h" +#include "llvm/ADT/SmallBitVector.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::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)) { + auto EqRt = Eq[Rt]; + + 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); + } + WorkList.push_back(Rt); + } + + 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)); + } + } + + for (auto Vtx : traits_t::vertices(Ret)) { + traits_t::dedupOutEdges(Ret, Vtx); + } + + return Ret; +} + +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 = traits_t::size(G); + 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(LSucc, 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 new file mode 100644 index 000000000..be00b4b84 --- /dev/null +++ b/include/phasar/Utils/GraphTraits.h @@ -0,0 +1,213 @@ +/****************************************************************************** + * 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" + +#include "llvm/ADT/ArrayRef.h" +#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 +#include +#include +#include + +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 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; + +#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::vertices(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::roots_size(cgraph) } -> std::convertible_to; + { + GraphTrait::target(edge) + } -> std::convertible_to; + { + GraphTrait::withEdgeTarget(edge, vtx) + } -> std::convertible_to; + {GraphTrait::weight(edge)}; +}; + +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 {}; + +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(), + std::declval())), + decltype(GraphTrait::removeRoot( + std::declval(), + std::declval()))>> + : 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 +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)) { + traits_t::addNode(Ret, forward_like(Nod)); + } + 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)); + } + if (traits_t::outDegree(G, I) == 0) { + traits_t::addRoot(Ret, I); + } + } + return Ret; +} + +struct DefaultNodeTransform { + template std::string operator()(const N &Nod) const { + std::string Buf; + llvm::raw_string_ostream ROS(Buf); + ROS << Nod; + ROS.flush(); + return Buf; + } +}; + +template +void printGraph(const GraphTy &G, llvm::raw_ostream &OS, + llvm::StringRef Name = "", NodeTransform NodeToString = {}) +#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); + + for (size_t I = 0; I < Sz; ++I) { + OS << I; + if constexpr (!std::is_same_v) { + OS << "[label=\""; + OS.write_escaped(std::invoke(NodeToString, traits_t::node(G, I))); + OS << "\"]"; + } + OS << ";\n"; + for (const auto &Edge : traits_t::outEdges(G, I)) { + OS << I << "->" << Edge << ";\n"; + } + } +} + +} // 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 000000000..9eab786b6 --- /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/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index d5d0dd1aa..d7cc7db02 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -14,7 +14,6 @@ #include #include -#include namespace psr { @@ -26,71 +25,70 @@ template class MaybeUniquePtrBase { 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{}; - MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} - MaybeUniquePtrBase() noexcept = default; + constexpr MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + constexpr MaybeUniquePtrBase() noexcept = default; }; template class MaybeUniquePtrBase { protected: llvm::PointerIntPair Data{}; - MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} { - static_assert(alignof(T) > 1, - "Using MaybeUniquePtr requires alignment > 1!"); - } - MaybeUniquePtrBase() noexcept = default; + 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 be used as both, -/// owning and non-owning pointer. +/// 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 +/// \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: - MaybeUniquePtr() noexcept = default; + constexpr MaybeUniquePtr() noexcept = default; - MaybeUniquePtr(T *Pointer, bool Owns = false) noexcept - : detail::MaybeUniquePtrBase( - Pointer, Owns && Pointer != nullptr) {} + constexpr MaybeUniquePtr(T *Pointer, bool Owns = false) noexcept + : detail::MaybeUniquePtrBase(Pointer, Owns) {} - MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} template - MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} - MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept + constexpr MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept : detail::MaybeUniquePtrBase( std::exchange(Other.Data, {})) {} - void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other.Data); } + constexpr void swap(MaybeUniquePtr &Other) noexcept { + std::swap(Data, Other.Data); + } - friend void swap(MaybeUniquePtr &LHS, MaybeUniquePtr &RHS) noexcept { + constexpr friend void swap(MaybeUniquePtr &LHS, + MaybeUniquePtr &RHS) noexcept { LHS.swap(RHS); } - MaybeUniquePtr &operator=(MaybeUniquePtr &&Other) noexcept { + constexpr MaybeUniquePtr &operator=(MaybeUniquePtr &&Other) noexcept { swap(Other); return *this; } - MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + constexpr MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { if (owns()) { delete Data.getPointer(); } @@ -99,7 +97,7 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { } template - MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + constexpr MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { if (owns()) { delete Data.getPointer(); } @@ -110,24 +108,29 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { MaybeUniquePtr(const MaybeUniquePtr &) = delete; MaybeUniquePtr &operator=(const MaybeUniquePtr &) = delete; - ~MaybeUniquePtr() { +#if __cplusplus >= 202002L + constexpr +#endif + ~MaybeUniquePtr() { if (owns()) { delete Data.getPointer(); Data = {}; } } - [[nodiscard]] T *get() noexcept { return Data.getPointer(); } - [[nodiscard]] const T *get() const noexcept { return Data.getPointer(); } + [[nodiscard]] constexpr T *get() noexcept { return Data.getPointer(); } + [[nodiscard]] constexpr const T *get() const noexcept { + return Data.getPointer(); + } - [[nodiscard]] T *operator->() noexcept { return get(); } - [[nodiscard]] const T *operator->() const noexcept { return get(); } + [[nodiscard]] constexpr T *operator->() noexcept { return get(); } + [[nodiscard]] constexpr const T *operator->() const noexcept { return get(); } - [[nodiscard]] T &operator*() noexcept { + [[nodiscard]] constexpr T &operator*() noexcept { assert(get() != nullptr); return *get(); } - [[nodiscard]] const T &operator*() const noexcept { + [[nodiscard]] constexpr const T &operator*() const noexcept { assert(get() != nullptr); return *get(); } @@ -137,45 +140,48 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { return Data.getPointer(); } - void reset() noexcept { + constexpr void reset() noexcept { if (owns()) { delete Data.getPointer(); } Data = {}; } - [[nodiscard]] bool owns() const noexcept { + [[nodiscard]] constexpr bool owns() const noexcept { return Data.getInt() && Data.getPointer(); } - 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(); } - friend bool operator!=(const MaybeUniquePtr &LHS, - const MaybeUniquePtr &RHS) noexcept { + constexpr friend bool operator!=(const MaybeUniquePtr &LHS, + const MaybeUniquePtr &RHS) noexcept { return !(LHS == RHS); } - friend bool operator==(const MaybeUniquePtr &LHS, const T *RHS) noexcept { + constexpr friend bool operator==(const MaybeUniquePtr &LHS, + const T *RHS) noexcept { return LHS.Data.getPointer() == RHS; } - friend bool operator!=(const MaybeUniquePtr &LHS, const T *RHS) noexcept { + constexpr friend bool operator!=(const MaybeUniquePtr &LHS, + const T *RHS) noexcept { return !(LHS == RHS); } - friend bool operator==(const T *LHS, const MaybeUniquePtr &RHS) noexcept { + constexpr friend bool operator==(const T *LHS, + const MaybeUniquePtr &RHS) noexcept { return LHS == RHS.Data.getPointer(); } - friend bool operator!=(const T *LHS, const MaybeUniquePtr &RHS) noexcept { + constexpr friend bool operator!=(const T *LHS, + const MaybeUniquePtr &RHS) noexcept { return !(LHS == RHS); } - explicit operator bool() const noexcept { + constexpr explicit operator bool() const noexcept { return Data.getPointer() != nullptr; } }; - } // namespace psr #endif // PHASAR_UTILS_MAYBEUNIQUEPTR_H_ diff --git a/include/phasar/Utils/RepeatIterator.h b/include/phasar/Utils/RepeatIterator.h new file mode 100644 index 000000000..94245930a --- /dev/null +++ b/include/phasar/Utils/RepeatIterator.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * 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" + +#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::forward_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 + +#endif // PHASAR_UTILS_REPEATITERATOR_H diff --git a/include/phasar/Utils/StableVector.h b/include/phasar/Utils/StableVector.h index 68102efd3..12c18853e 100644 --- a/include/phasar/Utils/StableVector.h +++ b/include/phasar/Utils/StableVector.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace psr { @@ -153,20 +154,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), @@ -470,24 +472,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, @@ -553,13 +547,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) diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index d3022d72c..e954dd14e 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -10,6 +10,7 @@ #ifndef PHASAR_UTILS_TYPETRAITS_H #define PHASAR_UTILS_TYPETRAITS_H +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include @@ -33,19 +34,19 @@ namespace detail { template struct is_iterable : std::false_type {}; // NOLINT template -struct is_iterable().begin()), - decltype(std::declval().end())>> : std::true_type { -}; +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< - is_iterable::value && - std::is_convertible_v().begin()), U>>> - : std::true_type {}; + std::enable_if_t::value && + std::is_same_v()))>>>> + : public std::true_type {}; template struct is_pair : std::false_type {}; // NOLINT template diff --git a/include/phasar/Utils/Utilities.h b/include/phasar/Utils/Utilities.h index 5bc01ecd2..ec4f26cd0 100644 --- a/include/phasar/Utils/Utilities.h +++ b/include/phasar/Utils/Utilities.h @@ -257,6 +257,32 @@ 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 + // 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 { + 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); + } +}; + template >> llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const std::optional &Opt) { diff --git a/lib/PhasarLLVM/DataFlow/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/CMakeLists.txt index 509a22b31..3af5da486 100644 --- a/lib/PhasarLLVM/DataFlow/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(IfdsIde) add_subdirectory(Mono) +add_subdirectory(PathSensitivity) diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt new file mode 100644 index 000000000..1cbe6a3f6 --- /dev/null +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -0,0 +1,44 @@ +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}) + + + get_filename_component(Z3BasedPathSensitvityManager_src Z3BasedPathSensitvityManager.cpp ABSOLUTE) + # message("Not compiling ${Z3BasedPathSensitvityManager_src} since Z3 is disabled.") + # list(REMOVE_ITEM PATHSENSITIVITY_SRC ${Z3BasedPathSensitvityManager_src}) + + set(PATHSENSITIVITY_SRC + PathSensitivityManagerBase.cpp + ) + + message("Remaining PathSensitivity targets to build: ${PATHSENSITIVITY_SRC}") +endif() + + +if(PHASAR_USE_Z3) + set(ADDITIONAL_LINK_LIBS z3) +endif() + +add_phasar_library(phasar_llvm_pathsensitivity + ${PATHSENSITIVITY_SRC} + + LINKS + phasar_config + phasar_controlflow + phasar_llvm_controlflow + phasar_utils + phasar_llvm_utils + phasar_pointer + phasar_llvm_pointer + + LLVM_LINK_COMPONENTS + Core + Support + + LINK_PUBLIC + nlohmann_json::nlohmann_json + ${ADDITIONAL_LINK_LIBS} +) diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp new file mode 100644 index 000000000..9ea5c94fc --- /dev/null +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp @@ -0,0 +1,659 @@ +#include "phasar/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.h" + +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/PhasarLLVM/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 *Curr, + const llvm::Instruction *Succ) { + if (auto CV = internalGetConstraintAndVariablesFromEdge(Curr, Succ)) { + return CV->Constraint; + } + + return std::nullopt; +} + +auto LLVMPathConstraints::getConstraintAndVariablesFromEdge( + const llvm::Instruction *Curr, const llvm::Instruction *Succ) + -> std::optional { + auto CV = internalGetConstraintAndVariablesFromEdge(Curr, Succ); + 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 diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/PathSensitivityManagerBase.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/PathSensitivityManagerBase.cpp new file mode 100644 index 000000000..413e95f2d --- /dev/null +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/PathSensitivityManagerBase.cpp @@ -0,0 +1,5 @@ +#include "phasar/DataFlow/PathSensitivity/PathSensitivityManagerBase.h" + +namespace psr { +template class PathSensitivityManagerBase; +} // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp new file mode 100644 index 000000000..801a8e10f --- /dev/null +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/Z3BasedPathSensitivityManager.cpp @@ -0,0 +1,580 @@ +#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" + +namespace psr { +z3::expr Z3BasedPathSensitivityManagerBase::filterOutUnreachableNodes( + graph_type &RevDAG, vertex_t Leaf, + 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); + } + + // NOLINTNEXTLINE(readability-identifier-naming) + 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); + 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; + + 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; + 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) { + Iter = graph_traits_t::removeEdge(RevDAG, Vtx, It); + Ctx.Ctr++; + } else { + Ys.push_back(std::move(Y)); + } + + Ctx.Solver.pop(); + // Idx++; + } + + if (graph_traits_t::outDegree(RevDAG, Vtx) == 0) { + return Ctx.NodeConstraints[Vtx] = Vtx == Leaf ? 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 (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; + 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); + } + } + + 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)) { + PHASAR_LOG_LEVEL_CAT(DEBUG, "CallStackPathFilter", + "Push CS: " << llvmIRToString(CS)); + pushCS(CS); + + } else if (llvm::isa(Prev) || + llvm::isa(Prev)) { + /// 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 + } + } + + 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; + + 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()); + + 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 + /// 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 + /// 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) { + // llvm::errs() << "> Reached Leaf!\n"; + + 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; +} + +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/lib/PhasarLLVM/Utils/LLVMShorthands.cpp b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp index 62672afab..1525668be 100644 --- a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp +++ b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp @@ -177,6 +177,19 @@ std::string llvmIRToString(const llvm::Value *V) { return llvm::StringRef(IRBuffer).ltrim().str(); } +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 ""; 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 000000000..3a701b477 --- /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 000000000..71b0801f9 --- /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 000000000..2b5eedbbe --- /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 000000000..1208186b3 --- /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 000000000..8402d65d0 --- /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 000000000..d2ec59066 --- /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 000000000..99e8c4ecd --- /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 000000000..c7245ea57 --- /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 000000000..cf3797a41 --- /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 000000000..710a21ae4 --- /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 000000000..8b8e4a33a --- /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 000000000..9628566c6 --- /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 000000000..b9fe519b0 --- /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 000000000..b275d50e4 --- /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 000000000..b4411b86d --- /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 000000000..c89956da1 --- /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 000000000..f4cdbc7df --- /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 000000000..a3eab5f04 --- /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 000000000..0547c6bf2 --- /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 000000000..fc69a9f55 --- /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 000000000..26e77a673 --- /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 000000000..784712af1 --- /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 000000000..98f19aabe --- /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/tools/example-tool/myphasartool.cpp b/tools/example-tool/myphasartool.cpp index f95f34ce2..8080dabbe 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 c9c20f629..6781e8e4b 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, diff --git a/unittests/PhasarLLVM/DataFlow/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/CMakeLists.txt index 509a22b31..3af5da486 100644 --- a/unittests/PhasarLLVM/DataFlow/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlow/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(IfdsIde) add_subdirectory(Mono) +add_subdirectory(PathSensitivity) diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt new file mode 100644 index 000000000..ac70e1b3e --- /dev/null +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -0,0 +1,9 @@ +if(PHASAR_USE_Z3) + add_phasar_unittest(PathTracingTest.cpp) + + target_link_libraries(PathTracingTest + LINK_PUBLIC + phasar_llvm_pathsensitivity + z3 + ) +endif() diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp new file mode 100644 index 000000000..0194d0eea --- /dev/null +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/PathTracingTest.cpp @@ -0,0 +1,861 @@ +#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/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/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" +#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" + +#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 "TestConfig.h" +#include "gtest/gtest.h" + +#include +#include +#include +#include +#include +#include + +namespace { +// ============== TEST FIXTURE ============== // +class PathTracingTest : public ::testing::Test { +public: + static constexpr auto PathToLlFiles = PHASAR_BUILD_SUBFOLDER("path_tracing/"); + + static std::pair + getInterestingInstFact(psr::LLVMProjectIRDB &IRDB) { + 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}; + } + +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); + psr::LLVMTypeHierarchy TH(*IRDB); + 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(), &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] = 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 + doLambdaAnalysis(const std::string &LlvmFilePath, + size_t MaxDAGDepth = SIZE_MAX) { + IRDB = std::make_unique(PathToLlFiles + LlvmFilePath); + psr::LLVMTypeHierarchy TH(*IRDB); + psr::LLVMAliasSet PT(IRDB.get()); + psr::LLVMBasedICFG ICFG(IRDB.get(), psr::CallGraphAnalysisType::OTF, + {"main"}, &TH, &PT, psr::Soundness::Soundy, + /*IncludeGlobals*/ false); + + psr::LLVMTaintConfig Config(*IRDB); + psr::IDEExtendedTaintAnalysis<3, false> Analysis(IRDB.get(), &ICFG, &PT, + Config, {"main"}); + psr::PathAwareIDESolver Solver(Analysis, &ICFG); + Solver.solve(); + + 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), + &LPC); + + return PSM.pathsTo(LastInst, Analysis.getZeroValue()); + } + + void comparePaths( + const psr::FlowPathSequence &AnalyzedPaths, + const std::vector> &GroundTruth) { + 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; + } + 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) { + MatchingIndices.insert(Idx); + return true; + } + } + + return false; + }; + + for (const auto > : GroundTruth) { + EXPECT_TRUE(Matches(GT)) + << "No match found for " << psr::PrettyPrinter{GT} + << "; MatchingIndices.size() = " << MatchingIndices.size() + << "; AnalyzedPaths.size() = " << AnalyzedPaths.size(); + } + + 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, {{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 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, + {{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) { + 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) { + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "CallStackPathFilter"); + 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}}); +} + +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, {{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, + { + {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) { + /// 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", false); + 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) { + /// 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) { + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + /// 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"); + 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) { + 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, + { + {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, + 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) { + // 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}, + {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", 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 + /// contradictory + comparePaths( + PathsVec, + { + {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}, + {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}, + {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}, + {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, + // 13, 14, 15, 19, 10, 20, 21, 67, 68, 76, 77}, + }); +} + +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 + /// 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", false); + /// 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}, + {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, { + {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) { + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + GTEST_SKIP() << "Need globals support"; + auto PathsVec = doAnalysis("inter_10_cpp.ll", false); + /// 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, {{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"); + 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, + {{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}, + {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"); + 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}, + {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, {{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, {{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, {{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, + { + // {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) { + // 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, {{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) { + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + auto PathsVec = doAnalysis("intra_07_cpp.ll"); + /// 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}, + {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", 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 + /// 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) { + // psr::Logger::initializeStderrLogger(psr::SeverityLevel::DEBUG, + // "PathSensitivityManager"); + auto PathsVec = doAnalysis("intra_09_cpp.ll"); + /// FIXME: Same reason as Handle_Inter_08 + 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, {{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); +} + +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); + return RUN_ALL_TESTS(); +} From 1edd12dc131efdab286f900dadd0a072cce5e023 Mon Sep 17 00:00:00 2001 From: Alexander Lochmann Date: Mon, 11 Dec 2023 19:02:26 +0100 Subject: [PATCH 47/59] TaintConfigData need include cstdint for uint32_t (#691) --- include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h index 99a3896f8..ba92829e5 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigData.h @@ -10,6 +10,7 @@ #ifndef PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGDATA_H #define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGDATA_H +#include #include #include From c3f55911e4fefb778998abe03499922d219c4781 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 12 Dec 2023 11:09:58 +0100 Subject: [PATCH 48/59] The LLVMBasedICFGGlobCtorDtorTest needs LLVMLinker, so we better link explicitly, instead of relying on transitive linkage (#692) --- unittests/PhasarLLVM/ControlFlow/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt index 04cb11d94..656751ae9 100644 --- a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt +++ b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt @@ -12,6 +12,7 @@ set(ControlFlowSources LLVMBasedICFGSerializationTest.cpp ) +set(LLVM_LINK_COMPONENTS Linker) # The CtorDtorTest needs the linker foreach(TEST_SRC ${ControlFlowSources}) add_phasar_unittest(${TEST_SRC}) endforeach(TEST_SRC) From 385c305836db410145ea067d8f5f7e95fee82e19 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 12 Dec 2023 11:37:52 +0100 Subject: [PATCH 49/59] More General Statistics (#686) * Add some more statistics * Even more stats * Some more counters * minor * Make the GSA work again after the merge * More about globals * Formatting * minor --- .../Passes/GeneralStatisticsAnalysis.h | 97 +++-- .../Passes/GeneralStatisticsAnalysis.cpp | 343 ++++++++++++------ 2 files changed, 315 insertions(+), 125 deletions(-) diff --git a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h index ca6767a3a..a33b6e10d 100644 --- a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h +++ b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h @@ -33,107 +33,156 @@ class Module; namespace psr { -class GeneralStatistics { -private: - friend class GeneralStatisticsAnalysis; +struct GeneralStatistics { + size_t Functions = 0; + size_t ExternalFunctions = 0; + size_t FunctionDefinitions = 0; + size_t AddressTakenFunctions = 0; size_t Globals = 0; + size_t GlobalConsts = 0; + size_t ExternalGlobals = 0; + size_t GlobalsDefinitions = 0; size_t BasicBlocks = 0; size_t AllocationSites = 0; size_t CallSites = 0; + size_t DebugIntrinsics = 0; size_t Instructions = 0; size_t StoreInstructions = 0; size_t LoadInstructions = 0; size_t MemIntrinsics = 0; - size_t GlobalPointers = 0; size_t Branches = 0; + size_t Switches = 0; size_t GetElementPtrs = 0; + size_t LandingPads = 0; size_t PhiNodes = 0; - size_t GlobalConsts = 0; + size_t NumInlineAsm = 0; + size_t IndCalls = 0; + size_t TotalNumOperands = 0; + size_t TotalNumUses = 0; + size_t TotalNumPredecessorBBs = 0; + size_t TotalNumSuccessorBBs = 0; + size_t MaxNumOperands = 0; + size_t MaxNumUses = 0; + size_t MaxNumPredecessorBBs = 0; + size_t MaxNumSuccessorBBs = 0; + size_t NumInstWithMultipleUses = 0; + size_t NumInstsUsedOutsideBB = 0; + size_t NonVoidInsts = 0; std::set AllocatedTypes; std::set AllocaInstructions; std::set RetResInstructions; - std::string ModuleName = ""; + std::string ModuleName{}; -public: /** * @brief Returns the number of Allocation sites. */ - [[nodiscard]] size_t getAllocationsites() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use AllocationSites instead")]] size_t + getAllocationsites() const; /** * @brief Returns the number of Function calls. */ - [[nodiscard]] size_t getFunctioncalls() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use CallSites instead")]] size_t + getFunctioncalls() const; /** * @brief Returns the number of Instructions. */ - [[nodiscard]] size_t getInstructions() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use Instructions instead")]] size_t + getInstructions() const; /** * @brief Returns the number of global pointers. */ - [[nodiscard]] size_t getGlobalPointers() const; + [[nodiscard]] [[deprecated( + "All globals are pointers. Use Globals instead")]] size_t + getGlobalPointers() const; /** * @brief Returns the number of basic blocks. */ - [[nodiscard]] size_t getBasicBlocks() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use BasicBlocks instead")]] size_t + getBasicBlocks() const; /** * @brief Returns the number of functions. */ - [[nodiscard]] size_t getFunctions() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use Functions instead")]] size_t + getFunctions() const; /** * @brief Returns the number of globals. */ - [[nodiscard]] size_t getGlobals() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use Globals instead")]] size_t + getGlobals() const; /** * @brief Returns the number of constant globals. */ - [[nodiscard]] size_t getGlobalConsts() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use GlobalConsts instead")]] size_t + getGlobalConsts() const; /** * @brief Returns the number of memory intrinsics. */ - [[nodiscard]] size_t getMemoryIntrinsics() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use MemIntrinsics instead")]] size_t + getMemoryIntrinsics() const; /** * @brief Returns the number of store instructions. */ - [[nodiscard]] size_t getStoreInstructions() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use StoreInstructions instead")]] size_t + getStoreInstructions() const; /** * @brief Returns the number of load instructions. */ - [[nodiscard]] size_t getLoadInstructions(); + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use LoadInstructions instead; this " + "function seems to be broken anyway")]] size_t + getLoadInstructions(); /** * @brief Returns all possible Types. */ - [[nodiscard]] const std::set &getAllocatedTypes() const; + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use AllocatedTypes instead")]] const std:: + set & + getAllocatedTypes() const; /** * @brief Returns all stack and heap allocating instructions. */ - [[nodiscard]] const std::set & + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use AllocaInstructions " + "instead")]] const std::set & getAllocaInstructions() const; /** * @brief Returns all Return and Resume Instructions. */ - [[nodiscard]] const std::set & + [[nodiscard]] [[deprecated( + "Getters are no longer needed. Use RetResInstructions " + "instead")]] const std::set & getRetResInstructions() const; + [[nodiscard]] nlohmann::json getAsJson() const; void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const GeneralStatistics &Statistics); }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const GeneralStatistics &Statistics); + /** * This class uses the Module Pass Mechanism of LLVM to compute * some statistics about a Module. This includes the number of diff --git a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp index 0b46a0c6f..4ba840930 100644 --- a/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp +++ b/lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp @@ -7,49 +7,127 @@ * Philipp Schubert and others *****************************************************************************/ -/* - * MyHelloPass.cpp - * - * Created on: 05.07.2016 - * Author: pdschbrt - */ - #include "phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" +#include "phasar/Utils/NlohmannLogging.h" #include "phasar/Utils/PAMMMacros.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Demangle/Demangle.h" -#include "llvm/IR/AbstractCallSite.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/Function.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include - -using namespace std; -using namespace psr; +#include namespace psr { +static bool isAddressTaken(const llvm::Function &Fun) noexcept { + for (const auto &Use : Fun.uses()) { + const auto *Call = llvm::dyn_cast(Use.getUser()); + if (!Call || Use.get() != Call->getCalledOperand()) { + return true; + } + } + return false; +} + +template +static void collectAllocatedTypes(const llvm::CallBase *CallSite, Set &Into) { + for (const auto *User : CallSite->users()) { + if (const auto *Cast = llvm::dyn_cast(User)) { + if (Cast->getDestTy()->getPointerElementType()->isStructTy()) { + // finally check for ctor call + for (const auto *User : Cast->users()) { + if (llvm::isa(User) || + llvm::isa(User)) { + // potential call to the structures ctor + const auto *CTor = llvm::cast(User); + if (CTor->getCalledFunction() && + CTor->getCalledFunction()->getArg(0)->getType() == + Cast->getDestTy()) { + Into.insert(Cast->getDestTy()->getPointerElementType()); + } + } + } + } + } + } +} + llvm::AnalysisKey GeneralStatisticsAnalysis::Key; // NOLINT GeneralStatistics GeneralStatisticsAnalysis::runOnModule(llvm::Module &M) { PHASAR_LOG_LEVEL(INFO, "Running GeneralStatisticsAnalysis"); - static const std::set MemAllocatingFunctions = { - "operator new(unsigned long)", "operator new[](unsigned long)", "malloc", - "calloc", "realloc"}; - Stats.ModuleName = M.getName(); + LLVMBasedCFG CFG; + Stats.ModuleName = M.getName().str(); for (auto &F : M) { ++Stats.Functions; + + if (F.hasExternalLinkage()) { + ++Stats.ExternalFunctions; + } + if (!F.isDeclaration()) { + ++Stats.FunctionDefinitions; + } + + if (isAddressTaken(F)) { + ++Stats.AddressTakenFunctions; + } + for (auto &BB : F) { ++Stats.BasicBlocks; + + { + auto PredSize = llvm::pred_size(&BB); + auto SuccSize = llvm::succ_size(&BB); + Stats.TotalNumPredecessorBBs += PredSize; + Stats.TotalNumSuccessorBBs += SuccSize; + if (PredSize > Stats.MaxNumPredecessorBBs) { + ++Stats.MaxNumPredecessorBBs; + } + if (SuccSize > Stats.MaxNumSuccessorBBs) { + ++Stats.MaxNumSuccessorBBs; + } + } + for (auto &I : BB) { // found one more instruction ++Stats.Instructions; + + { + auto NumOps = I.getNumOperands(); + auto NumUses = I.getNumUses(); + Stats.TotalNumOperands += NumOps; + Stats.TotalNumUses += NumUses; + if (NumOps > Stats.MaxNumOperands) { + ++Stats.MaxNumOperands; + } + if (NumUses > Stats.MaxNumUses) { + ++Stats.MaxNumUses; + } + if (NumUses > 1) { + ++Stats.NumInstWithMultipleUses; + } + } + + if (!I.getType()->isVoidTy()) { + ++Stats.NonVoidInsts; + } + + if (I.isUsedOutsideOfBlock(I.getParent())) { + ++Stats.NumInstsUsedOutsideBB; + } + // check for alloca instruction for possible types if (const llvm::AllocaInst *Alloc = llvm::dyn_cast(&I)) { @@ -64,6 +142,9 @@ GeneralStatistics GeneralStatisticsAnalysis::runOnModule(llvm::Module &M) { if (llvm::isa(I)) { ++Stats.Branches; } + if (llvm::isa(I)) { + ++Stats.Switches; + } if (llvm::isa(I)) { ++Stats.GetElementPtrs; } @@ -79,60 +160,55 @@ GeneralStatistics GeneralStatisticsAnalysis::runOnModule(llvm::Module &M) { if (llvm::isa(I)) { ++Stats.LoadInstructions; } + if (llvm::isa(I)) { + ++Stats.LandingPads; + } // check for llvm's memory intrinsics if (llvm::isa(I)) { ++Stats.MemIntrinsics; } + + if (llvm::isa(I)) { + ++Stats.DebugIntrinsics; + } // check for function calls - if (llvm::isa(I) || llvm::isa(I)) { + if (const auto *CallSite = llvm::dyn_cast(&I)) { ++Stats.CallSites; - const llvm::CallBase *CallSite = llvm::cast(&I); - if (CallSite->getCalledFunction()) { - if (MemAllocatingFunctions.count(llvm::demangle( - CallSite->getCalledFunction()->getName().str()))) { + + const auto *CalledOp = + CallSite->getCalledOperand()->stripPointerCastsAndAliases(); + + if (llvm::isa(CalledOp)) { + ++Stats.NumInlineAsm; + } else if (const auto *CalleeFun = + llvm::dyn_cast(CalledOp)) { + if (CFG.isHeapAllocatingFunction(CalleeFun)) { // do not add allocas from llvm internal functions Stats.AllocaInstructions.insert(&I); ++Stats.AllocationSites; // check if an instance of a user-defined type is allocated on the // heap - for (auto *User : I.users()) { - if (auto *Cast = llvm::dyn_cast(User)) { - if (Cast->getDestTy() - ->getPointerElementType() - ->isStructTy()) { - // finally check for ctor call - for (auto *User : Cast->users()) { - if (llvm::isa(User) || - llvm::isa(User)) { - // potential call to the structures ctor - const llvm::CallBase *CTor = - llvm::cast(User); - if (CTor->getCalledFunction() && - CTor->getCalledFunction()->getArg(0)->getType() == - Cast->getDestTy()) { - Stats.AllocatedTypes.insert( - Cast->getDestTy()->getPointerElementType()); - } - } - } - } - } - } + collectAllocatedTypes(CallSite, Stats.AllocatedTypes); } + } else { + ++Stats.IndCalls; } } } } } // check for global pointers - for (auto const &Global : M.globals()) { - if (Global.getType()->isPointerTy()) { - ++Stats.GlobalPointers; - } + for (const auto &Global : M.globals()) { ++Stats.Globals; if (Global.isConstant()) { ++Stats.GlobalConsts; } + if (!Global.isDeclaration()) { + ++Stats.GlobalsDefinitions; + } + if (Global.hasExternalLinkage()) { + ++Stats.ExternalGlobals; + } } // register stuff in PAMM // For performance reasons (and out of sheer convenience) we simply initialize @@ -150,31 +226,27 @@ GeneralStatistics GeneralStatisticsAnalysis::runOnModule(llvm::Module &M) { REG_COUNTER("GS Load Instructions", Stats.LoadInstructions, Full); // Using the logging guard explicitly since we are printing allocated types // manually - IF_LOG_ENABLED( - PHASAR_LOG_LEVEL(INFO, "GeneralStatisticsAnalysis summary for module: '" - << M.getName() << "'"); - PHASAR_LOG_LEVEL(INFO, "Instructions : " << Stats.Instructions); - PHASAR_LOG_LEVEL(INFO, - "Allocated Types : " << Stats.AllocatedTypes.size()); - PHASAR_LOG_LEVEL(INFO, "Allocation Sites : " << Stats.AllocationSites); - PHASAR_LOG_LEVEL(INFO, "Basic Blocks : " << Stats.BasicBlocks); - PHASAR_LOG_LEVEL(INFO, "Calls Sites : " << Stats.CallSites); - PHASAR_LOG_LEVEL(INFO, "Functions : " << Stats.Functions); - PHASAR_LOG_LEVEL(INFO, "Globals : " << Stats.Globals); - PHASAR_LOG_LEVEL(INFO, "Global Pointer : " << Stats.GlobalPointers); - PHASAR_LOG_LEVEL(INFO, "Global Consts : " << Stats.GlobalConsts); - PHASAR_LOG_LEVEL(INFO, "Memory Intrinsics : " << Stats.MemIntrinsics); - PHASAR_LOG_LEVEL(INFO, - "Store Instructions : " << Stats.StoreInstructions); - PHASAR_LOG_LEVEL(INFO, ' '); PHASAR_LOG_LEVEL( - INFO, "Allocated Types << " << Stats.AllocatedTypes.size()); - for (const auto *Type - : Stats.AllocatedTypes) { - std::string TypeStr; - llvm::raw_string_ostream Rso(TypeStr); - Type->print(Rso); - PHASAR_LOG_LEVEL(INFO, " " << Rso.str()); - }); + IF_LOG_LEVEL_ENABLED(INFO, { + PHASAR_LOG_LEVEL(INFO, "GeneralStatisticsAnalysis summary for module: '" + << M.getName() << "'"); + PHASAR_LOG_LEVEL(INFO, "Instructions : " << Stats.Instructions); + PHASAR_LOG_LEVEL(INFO, + "Allocated Types : " << Stats.AllocatedTypes.size()); + PHASAR_LOG_LEVEL(INFO, "Allocation Sites : " << Stats.AllocationSites); + PHASAR_LOG_LEVEL(INFO, "Basic Blocks : " << Stats.BasicBlocks); + PHASAR_LOG_LEVEL(INFO, "Calls Sites : " << Stats.CallSites); + PHASAR_LOG_LEVEL(INFO, "Functions : " << Stats.Functions); + PHASAR_LOG_LEVEL(INFO, "Globals : " << Stats.Globals); + PHASAR_LOG_LEVEL(INFO, "Global Consts : " << Stats.GlobalConsts); + PHASAR_LOG_LEVEL(INFO, "Memory Intrinsics : " << Stats.MemIntrinsics); + PHASAR_LOG_LEVEL(INFO, "Store Instructions : " << Stats.StoreInstructions); + PHASAR_LOG_LEVEL(INFO, ' '); + PHASAR_LOG_LEVEL(INFO, + "Allocated Types << " << Stats.AllocatedTypes.size()); + for (const auto *Type : Stats.AllocatedTypes) { + PHASAR_LOG_LEVEL(INFO, " " << llvmTypeToString(Type)); + } + }); // now we are done and can return the results return Stats; } @@ -185,7 +257,7 @@ size_t GeneralStatistics::getFunctioncalls() const { return CallSites; } size_t GeneralStatistics::getInstructions() const { return Instructions; } -size_t GeneralStatistics::getGlobalPointers() const { return GlobalPointers; } +size_t GeneralStatistics::getGlobalPointers() const { return Globals; } size_t GeneralStatistics::getBasicBlocks() const { return BasicBlocks; } @@ -201,58 +273,127 @@ size_t GeneralStatistics::getStoreInstructions() const { return StoreInstructions; } -const set &GeneralStatistics::getAllocatedTypes() const { +const std::set & +GeneralStatistics::getAllocatedTypes() const { return AllocatedTypes; } -const set & +const std::set & GeneralStatistics::getAllocaInstructions() const { return AllocaInstructions; } -const set & +const std::set & GeneralStatistics::getRetResInstructions() const { return RetResInstructions; } void GeneralStatistics::printAsJson(llvm::raw_ostream &OS) const { - OS << getAsJson().dump(4) << '\n'; + OS << getAsJson() << '\n'; } nlohmann::json GeneralStatistics::getAsJson() const { nlohmann::json J; - J["ModuleName"] = GeneralStatistics::ModuleName; - J["Instructions"] = getInstructions(); + J["ModuleName"] = ModuleName; + J["Instructions"] = Instructions; J["Functions"] = Functions; + J["ExternalFunctions"] = ExternalFunctions; + J["FunctionDefinitions"] = FunctionDefinitions; + J["AddressTakenFunctions"] = AddressTakenFunctions; J["AllocaInstructions"] = AllocaInstructions.size(); J["CallSites"] = CallSites; + J["IndirectCallSites"] = IndCalls; + J["MemoryIntrinsics"] = MemIntrinsics; + J["DebugIntrinsics"] = DebugIntrinsics; + J["InlineAssembly"] = NumInlineAsm; J["GlobalVariables"] = Globals; J["Branches"] = Branches; J["GetElementPtrs"] = GetElementPtrs; J["BasicBlocks"] = BasicBlocks; J["PhiNodes"] = PhiNodes; + J["LandingPads"] = LandingPads; J["GlobalConsts"] = GlobalConsts; - J["GlobalPointers"] = GlobalPointers; return J; } -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const GeneralStatistics &Statistics) { - return OS << "General LLVM IR Statistics" - << "\n" - << "Module " << Statistics.ModuleName << ":\n" - << "LLVM IR instructions:\t" << Statistics.Instructions << "\n" - << "Functions:\t" << Statistics.Functions << "\n" - << "Global Variables:\t" << Statistics.Globals << "\n" - << "Global Variable Consts:\t" << Statistics.GlobalConsts << "\n" - << "Global Pointers:\t" << Statistics.GlobalPointers << "\n" - << "Alloca Instructions:\t" << Statistics.AllocaInstructions.size() - << "\n" - << "Call Sites:\t" << Statistics.CallSites << "\n" - << "Branches:\t" << Statistics.Branches << "\n" - << "GetElementPtrs:\t" << Statistics.GetElementPtrs << "\n" - << "Phi Nodes:\t" << Statistics.PhiNodes << "\n" - << "Basic Blocks:\t" << Statistics.BasicBlocks << "\n"; -} - } // namespace psr + +namespace { +template struct AlignNum { + llvm::StringRef Name; + T Num; + + AlignNum(llvm::StringRef Name, T Num) noexcept : Name(Name), Num(Num) {} + AlignNum(llvm::StringRef Name, size_t Numerator, size_t Denominator) noexcept + : Name(Name), Num(double(Numerator) / double(Denominator)) {} + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const AlignNum &AN) { + static constexpr size_t NumOffs = 32; + + auto Len = AN.Name.size() + 1; + auto Diff = -(Len < NumOffs) & (NumOffs - Len); + + OS << AN.Name << ':'; + // Default is two fixed-point decimal places, so shift the output by three + // spaces + OS.indent(Diff + std::is_floating_point_v * 3); + OS << llvm::formatv("{0,+7}\n", AN.Num); + + return OS; + } +}; +template AlignNum(llvm::StringRef, T) -> AlignNum; +AlignNum(llvm::StringRef, size_t, size_t)->AlignNum; +} // namespace + +llvm::raw_ostream &psr::operator<<(llvm::raw_ostream &OS, + const GeneralStatistics &Statistics) { + return OS + << "General LLVM IR Statistics\n" + << "Module " << Statistics.ModuleName << ":\n" + << "---------------------------------------\n" + << AlignNum("LLVM IR instructions", Statistics.Instructions) + << AlignNum("Functions", Statistics.Functions) + << AlignNum("External Functions", Statistics.ExternalFunctions) + << AlignNum("Function Definitions", Statistics.FunctionDefinitions) + << AlignNum("Address-Taken Functions", + Statistics.AddressTakenFunctions) + << AlignNum("Globals", Statistics.Globals) + << AlignNum("Global Constants", Statistics.GlobalConsts) + << AlignNum("Global Variables", + Statistics.Globals - Statistics.GlobalConsts) + << AlignNum("External Globals", Statistics.ExternalGlobals) + << AlignNum("Global Definitions", Statistics.GlobalsDefinitions) + << AlignNum("Alloca Instructions", + Statistics.AllocaInstructions.size()) + << AlignNum("Call Sites", Statistics.CallSites) + << AlignNum("Indirect Call Sites", Statistics.IndCalls) + << AlignNum("Inline Assemblies", Statistics.NumInlineAsm) + << AlignNum("Memory Intrinsics", Statistics.MemIntrinsics) + << AlignNum("Debug Intrinsics", Statistics.DebugIntrinsics) + << AlignNum("Switches", Statistics.Switches) + << AlignNum("GetElementPtrs", Statistics.GetElementPtrs) + << AlignNum("Phi Nodes", Statistics.PhiNodes) + << AlignNum("LandingPads", Statistics.LandingPads) + << AlignNum("Basic Blocks", Statistics.BasicBlocks) + << AlignNum("Avg #pred per BasicBlock", + Statistics.TotalNumPredecessorBBs, Statistics.BasicBlocks) + << AlignNum("Max #pred per BasicBlock", + Statistics.MaxNumPredecessorBBs) + << AlignNum("Avg #succ per BasicBlock", + Statistics.TotalNumSuccessorBBs, Statistics.BasicBlocks) + << AlignNum("Max #succ per BasicBlock", Statistics.MaxNumSuccessorBBs) + << AlignNum("Avg #operands per Inst", Statistics.TotalNumOperands, + Statistics.Instructions) + << AlignNum("Max #operands per Inst", Statistics.MaxNumOperands) + << AlignNum("Avg #uses per Inst", Statistics.TotalNumUses, + Statistics.Instructions) + << AlignNum("Max #uses per Inst", Statistics.MaxNumUses) + << AlignNum("Insts with >1 uses", Statistics.NumInstWithMultipleUses) + << AlignNum("Non-void Insts", Statistics.NonVoidInsts) + << AlignNum("Insts used outside its BB", + Statistics.NumInstsUsedOutsideBB) + + ; +} From 7f1237b66516b378e5f7d5b0448bc6e2c61dcd9c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 12 Dec 2023 13:29:36 +0100 Subject: [PATCH 50/59] Provide LLVM's CFL-based alias analyses (#687) Co-authored-by: Martin Mory --- .../Pointer/LLVMBasedAliasAnalysis.cpp | 5 +- .../Pointer/external/LLVM-LICENSE.txt | 278 ++++++ lib/PhasarLLVM/Pointer/external/README.md | 10 + .../external/llvm/AliasAnalysisSummary.h | 269 +++++ .../external/llvm/CFLAliasAnalysisUtils.h | 57 ++ .../external/llvm/CFLAndersAliasAnalysis.cpp | 934 ++++++++++++++++++ .../external/llvm/CFLAndersAliasAnalysis.h | 128 +++ .../Pointer/external/llvm/CFLGraph.h | 669 +++++++++++++ .../external/llvm/CFLSteensAliasAnalysis.cpp | 367 +++++++ .../external/llvm/CFLSteensAliasAnalysis.h | 145 +++ .../Pointer/external/llvm/StratifiedSets.h | 598 +++++++++++ 11 files changed, 3458 insertions(+), 2 deletions(-) create mode 100644 lib/PhasarLLVM/Pointer/external/LLVM-LICENSE.txt create mode 100644 lib/PhasarLLVM/Pointer/external/README.md create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/CFLAliasAnalysisUtils.h create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.h create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/CFLGraph.h create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.cpp create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.h create mode 100644 lib/PhasarLLVM/Pointer/external/llvm/StratifiedSets.h diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp index 319dbc4b7..a680ecb7e 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp @@ -18,8 +18,6 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BasicAliasAnalysis.h" -#include "llvm/Analysis/CFLAndersAliasAnalysis.h" -#include "llvm/Analysis/CFLSteensAliasAnalysis.h" #include "llvm/Analysis/ScopedNoAliasAA.h" #include "llvm/Analysis/TypeBasedAliasAnalysis.h" #include "llvm/IR/Argument.h" @@ -32,6 +30,9 @@ #include "llvm/IR/Verifier.h" #include "llvm/Passes/PassBuilder.h" +#include "external/llvm/CFLAndersAliasAnalysis.h" +#include "external/llvm/CFLSteensAliasAnalysis.h" + using namespace psr; namespace psr { diff --git a/lib/PhasarLLVM/Pointer/external/LLVM-LICENSE.txt b/lib/PhasarLLVM/Pointer/external/LLVM-LICENSE.txt new file mode 100644 index 000000000..571517657 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/LLVM-LICENSE.txt @@ -0,0 +1,278 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM Project contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. diff --git a/lib/PhasarLLVM/Pointer/external/README.md b/lib/PhasarLLVM/Pointer/external/README.md new file mode 100644 index 000000000..b35f89681 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/README.md @@ -0,0 +1,10 @@ +# External LLVM + +All files in the `llvm` subfolder are 1:1 copied from LLVM 14.0.6 and are subject to the LLVM license. +You can find a copy of the LLVM license [here](./LLVM-LICENSE.txt). + +Note that we needed to copy these files, as LLVM removed them in the transition from version 14 to 15. +To avoid LLVM from blocking PhASAR releases, we provide these files ourselves as a *temporary solution*. + +We, as the PhASAR development core team, do not aim for maintaining the here provided LLVM code and will not add any modifications to it (bugfixes, enhancements, etc.). +Rather, we will add a custom replacement eventually. diff --git a/lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h b/lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h new file mode 100644 index 000000000..6fcb6cc4b --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h @@ -0,0 +1,269 @@ +//=====- CFLSummary.h - Abstract stratified sets implementation. --------=====// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file defines various utility types and functions useful to +/// summary-based alias analysis. +/// +/// Summary-based analysis, also known as bottom-up analysis, is a style of +/// interprocedrual static analysis that tries to analyze the callees before the +/// callers get analyzed. The key idea of summary-based analysis is to first +/// process each function independently, outline its behavior in a condensed +/// summary, and then instantiate the summary at the callsite when the said +/// function is called elsewhere. This is often in contrast to another style +/// called top-down analysis, in which callers are always analyzed first before +/// the callees. +/// +/// In a summary-based analysis, functions must be examined independently and +/// out-of-context. We have no information on the state of the memory, the +/// arguments, the global values, and anything else external to the function. To +/// carry out the analysis conservative assumptions have to be made about those +/// external states. In exchange for the potential loss of precision, the +/// summary we obtain this way is highly reusable, which makes the analysis +/// easier to scale to large programs even if carried out context-sensitively. +/// +/// Currently, all CFL-based alias analyses adopt the summary-based approach +/// and therefore heavily rely on this header. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H +#define LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" + +#include + +namespace llvm { + +class CallBase; +class Value; + +namespace cflaa { + +//===----------------------------------------------------------------------===// +// AliasAttr related stuffs +//===----------------------------------------------------------------------===// + +/// The number of attributes that AliasAttr should contain. Attributes are +/// described below, and 32 was an arbitrary choice because it fits nicely in 32 +/// bits (because we use a bitset for AliasAttr). +static const unsigned NumAliasAttrs = 32; + +/// These are attributes that an alias analysis can use to mark certain special +/// properties of a given pointer. Refer to the related functions below to see +/// what kinds of attributes are currently defined. +typedef std::bitset AliasAttrs; + +/// Attr represent whether the said pointer comes from an unknown source +/// (such as opaque memory or an integer cast). +AliasAttrs getAttrNone(); + +/// AttrUnknown represent whether the said pointer comes from a source not known +/// to alias analyses (such as opaque memory or an integer cast). +AliasAttrs getAttrUnknown(); +bool hasUnknownAttr(AliasAttrs); + +/// AttrCaller represent whether the said pointer comes from a source not known +/// to the current function but known to the caller. Values pointed to by the +/// arguments of the current function have this attribute set +AliasAttrs getAttrCaller(); +bool hasCallerAttr(AliasAttrs); +bool hasUnknownOrCallerAttr(AliasAttrs); + +/// AttrEscaped represent whether the said pointer comes from a known source but +/// escapes to the unknown world (e.g. casted to an integer, or passed as an +/// argument to opaque function). Unlike non-escaped pointers, escaped ones may +/// alias pointers coming from unknown sources. +AliasAttrs getAttrEscaped(); +bool hasEscapedAttr(AliasAttrs); + +/// AttrGlobal represent whether the said pointer is a global value. +/// AttrArg represent whether the said pointer is an argument, and if so, what +/// index the argument has. +AliasAttrs getGlobalOrArgAttrFromValue(const Value &); +bool isGlobalOrArgAttr(AliasAttrs); + +/// Given an AliasAttrs, return a new AliasAttrs that only contains attributes +/// meaningful to the caller. This function is primarily used for +/// interprocedural analysis +/// Currently, externally visible AliasAttrs include AttrUnknown, AttrGlobal, +/// and AttrEscaped +AliasAttrs getExternallyVisibleAttrs(AliasAttrs); + +//===----------------------------------------------------------------------===// +// Function summary related stuffs +//===----------------------------------------------------------------------===// + +/// The maximum number of arguments we can put into a summary. +static const unsigned MaxSupportedArgsInSummary = 50; + +/// We use InterfaceValue to describe parameters/return value, as well as +/// potential memory locations that are pointed to by parameters/return value, +/// of a function. +/// Index is an integer which represents a single parameter or a return value. +/// When the index is 0, it refers to the return value. Non-zero index i refers +/// to the i-th parameter. +/// DerefLevel indicates the number of dereferences one must perform on the +/// parameter/return value to get this InterfaceValue. +struct InterfaceValue { + unsigned Index; + unsigned DerefLevel; +}; + +inline bool operator==(InterfaceValue LHS, InterfaceValue RHS) { + return LHS.Index == RHS.Index && LHS.DerefLevel == RHS.DerefLevel; +} +inline bool operator!=(InterfaceValue LHS, InterfaceValue RHS) { + return !(LHS == RHS); +} +inline bool operator<(InterfaceValue LHS, InterfaceValue RHS) { + return LHS.Index < RHS.Index || + (LHS.Index == RHS.Index && LHS.DerefLevel < RHS.DerefLevel); +} +inline bool operator>(InterfaceValue LHS, InterfaceValue RHS) { + return RHS < LHS; +} +inline bool operator<=(InterfaceValue LHS, InterfaceValue RHS) { + return !(RHS < LHS); +} +inline bool operator>=(InterfaceValue LHS, InterfaceValue RHS) { + return !(LHS < RHS); +} + +// We use UnknownOffset to represent pointer offsets that cannot be determined +// at compile time. Note that MemoryLocation::UnknownSize cannot be used here +// because we require a signed value. +static const int64_t UnknownOffset = INT64_MAX; + +inline int64_t addOffset(int64_t LHS, int64_t RHS) { + if (LHS == UnknownOffset || RHS == UnknownOffset) + return UnknownOffset; + // FIXME: Do we need to guard against integer overflow here? + return LHS + RHS; +} + +/// We use ExternalRelation to describe an externally visible aliasing relations +/// between parameters/return value of a function. +struct ExternalRelation { + InterfaceValue From, To; + int64_t Offset; +}; + +inline bool operator==(ExternalRelation LHS, ExternalRelation RHS) { + return LHS.From == RHS.From && LHS.To == RHS.To && LHS.Offset == RHS.Offset; +} +inline bool operator!=(ExternalRelation LHS, ExternalRelation RHS) { + return !(LHS == RHS); +} +inline bool operator<(ExternalRelation LHS, ExternalRelation RHS) { + if (LHS.From < RHS.From) + return true; + if (LHS.From > RHS.From) + return false; + if (LHS.To < RHS.To) + return true; + if (LHS.To > RHS.To) + return false; + return LHS.Offset < RHS.Offset; +} +inline bool operator>(ExternalRelation LHS, ExternalRelation RHS) { + return RHS < LHS; +} +inline bool operator<=(ExternalRelation LHS, ExternalRelation RHS) { + return !(RHS < LHS); +} +inline bool operator>=(ExternalRelation LHS, ExternalRelation RHS) { + return !(LHS < RHS); +} + +/// We use ExternalAttribute to describe an externally visible AliasAttrs +/// for parameters/return value. +struct ExternalAttribute { + InterfaceValue IValue; + AliasAttrs Attr; +}; + +/// AliasSummary is just a collection of ExternalRelation and ExternalAttribute +struct AliasSummary { + // RetParamRelations is a collection of ExternalRelations. + SmallVector RetParamRelations; + + // RetParamAttributes is a collection of ExternalAttributes. + SmallVector RetParamAttributes; +}; + +/// This is the result of instantiating InterfaceValue at a particular call +struct InstantiatedValue { + Value *Val; + unsigned DerefLevel; +}; +Optional instantiateInterfaceValue(InterfaceValue IValue, + CallBase &Call); + +inline bool operator==(InstantiatedValue LHS, InstantiatedValue RHS) { + return LHS.Val == RHS.Val && LHS.DerefLevel == RHS.DerefLevel; +} +inline bool operator!=(InstantiatedValue LHS, InstantiatedValue RHS) { + return !(LHS == RHS); +} +inline bool operator<(InstantiatedValue LHS, InstantiatedValue RHS) { + return std::less()(LHS.Val, RHS.Val) || + (LHS.Val == RHS.Val && LHS.DerefLevel < RHS.DerefLevel); +} +inline bool operator>(InstantiatedValue LHS, InstantiatedValue RHS) { + return RHS < LHS; +} +inline bool operator<=(InstantiatedValue LHS, InstantiatedValue RHS) { + return !(RHS < LHS); +} +inline bool operator>=(InstantiatedValue LHS, InstantiatedValue RHS) { + return !(LHS < RHS); +} + +/// This is the result of instantiating ExternalRelation at a particular +/// callsite +struct InstantiatedRelation { + InstantiatedValue From, To; + int64_t Offset; +}; +Optional +instantiateExternalRelation(ExternalRelation ERelation, CallBase &Call); + +/// This is the result of instantiating ExternalAttribute at a particular +/// callsite +struct InstantiatedAttr { + InstantiatedValue IValue; + AliasAttrs Attr; +}; +Optional instantiateExternalAttribute(ExternalAttribute EAttr, + CallBase &Call); +} // namespace cflaa + +template <> struct DenseMapInfo { + static inline cflaa::InstantiatedValue getEmptyKey() { + return cflaa::InstantiatedValue{DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey()}; + } + static inline cflaa::InstantiatedValue getTombstoneKey() { + return cflaa::InstantiatedValue{DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey()}; + } + static unsigned getHashValue(const cflaa::InstantiatedValue &IV) { + return DenseMapInfo>::getHashValue( + std::make_pair(IV.Val, IV.DerefLevel)); + } + static bool isEqual(const cflaa::InstantiatedValue &LHS, + const cflaa::InstantiatedValue &RHS) { + return LHS.Val == RHS.Val && LHS.DerefLevel == RHS.DerefLevel; + } +}; +} // namespace llvm + +#endif diff --git a/lib/PhasarLLVM/Pointer/external/llvm/CFLAliasAnalysisUtils.h b/lib/PhasarLLVM/Pointer/external/llvm/CFLAliasAnalysisUtils.h new file mode 100644 index 000000000..2eae2824b --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/CFLAliasAnalysisUtils.h @@ -0,0 +1,57 @@ +//=- CFLAliasAnalysisUtils.h - Utilities for CFL Alias Analysis ----*- C++-*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// \file +// These are the utilities/helpers used by the CFL Alias Analyses available in +// tree, i.e. Steensgaard's and Andersens'. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H +#define LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/ValueHandle.h" + +namespace llvm { +namespace cflaa { + +template struct FunctionHandle final : public CallbackVH { + FunctionHandle(Function *Fn, AAResult *Result) + : CallbackVH(Fn), Result(Result) { + assert(Fn != nullptr); + assert(Result != nullptr); + } + + void deleted() override { removeSelfFromCache(); } + void allUsesReplacedWith(Value *) override { removeSelfFromCache(); } + +private: + AAResult *Result; + + void removeSelfFromCache() { + assert(Result != nullptr); + auto *Val = getValPtr(); + Result->evict(cast(Val)); + setValPtr(nullptr); + } +}; + +static inline const Function *parentFunctionOfValue(const Value *Val) { + if (auto *Inst = dyn_cast(Val)) { + auto *Bb = Inst->getParent(); + return Bb->getParent(); + } + + if (auto *Arg = dyn_cast(Val)) + return Arg->getParent(); + return nullptr; +} +} // namespace cflaa +} // namespace llvm + +#endif // LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H diff --git a/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp new file mode 100644 index 000000000..404e0df3a --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp @@ -0,0 +1,934 @@ +//===- CFLAndersAliasAnalysis.cpp - Unification-based Alias Analysis ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a CFL-based, summary-based alias analysis algorithm. It +// differs from CFLSteensAliasAnalysis in its inclusion-based nature while +// CFLSteensAliasAnalysis is unification-based. This pass has worse performance +// than CFLSteensAliasAnalysis (the worst case complexity of +// CFLAndersAliasAnalysis is cubic, while the worst case complexity of +// CFLSteensAliasAnalysis is almost linear), but it is able to yield more +// precise analysis result. The precision of this analysis is roughly the same +// as that of an one level context-sensitive Andersen's algorithm. +// +// The algorithm used here is based on recursive state machine matching scheme +// proposed in "Demand-driven alias analysis for C" by Xin Zheng and Radu +// Rugina. The general idea is to extend the traditional transitive closure +// algorithm to perform CFL matching along the way: instead of recording +// "whether X is reachable from Y", we keep track of "whether X is reachable +// from Y at state Z", where the "state" field indicates where we are in the CFL +// matching process. To understand the matching better, it is advisable to have +// the state machine shown in Figure 3 of the paper available when reading the +// codes: all we do here is to selectively expand the transitive closure by +// discarding edges that are not recognized by the state machine. +// +// There are two differences between our current implementation and the one +// described in the paper: +// - Our algorithm eagerly computes all alias pairs after the CFLGraph is built, +// while in the paper the authors did the computation in a demand-driven +// fashion. We did not implement the demand-driven algorithm due to the +// additional coding complexity and higher memory profile, but if we found it +// necessary we may switch to it eventually. +// - In the paper the authors use a state machine that does not distinguish +// value reads from value writes. For example, if Y is reachable from X at state +// S3, it may be the case that X is written into Y, or it may be the case that +// there's a third value Z that writes into both X and Y. To make that +// distinction (which is crucial in building function summary as well as +// retrieving mod-ref info), we choose to duplicate some of the states in the +// paper's proposed state machine. The duplication does not change the set the +// machine accepts. Given a pair of reachable values, it only provides more +// detailed information on which value is being written into and which is being +// read from. +// +//===----------------------------------------------------------------------===// + +// N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and +// CFLAndersAA is interprocedural. This is *technically* A Bad Thing, because +// FunctionPasses are only allowed to inspect the Function that they're being +// run on. Realistically, this likely isn't a problem until we allow +// FunctionPasses to run concurrently. + +#include "llvm/Analysis/CFLAndersAliasAnalysis.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/MemoryLocation.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Type.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#include "AliasAnalysisSummary.h" +#include "CFLGraph.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::cflaa; + +#define DEBUG_TYPE "cfl-anders-aa" + +CFLAndersAAResult::CFLAndersAAResult( + std::function GetTLI) + : GetTLI(std::move(GetTLI)) {} +CFLAndersAAResult::CFLAndersAAResult(CFLAndersAAResult &&RHS) + : AAResultBase(std::move(RHS)), GetTLI(std::move(RHS.GetTLI)) {} +CFLAndersAAResult::~CFLAndersAAResult() = default; + +namespace { + +enum class MatchState : uint8_t { + // The following state represents S1 in the paper. + FlowFromReadOnly = 0, + // The following two states together represent S2 in the paper. + // The 'NoReadWrite' suffix indicates that there exists an alias path that + // does not contain assignment and reverse assignment edges. + // The 'ReadOnly' suffix indicates that there exists an alias path that + // contains reverse assignment edges only. + FlowFromMemAliasNoReadWrite, + FlowFromMemAliasReadOnly, + // The following two states together represent S3 in the paper. + // The 'WriteOnly' suffix indicates that there exists an alias path that + // contains assignment edges only. + // The 'ReadWrite' suffix indicates that there exists an alias path that + // contains both assignment and reverse assignment edges. Note that if X and Y + // are reachable at 'ReadWrite' state, it does NOT mean X is both read from + // and written to Y. Instead, it means that a third value Z is written to both + // X and Y. + FlowToWriteOnly, + FlowToReadWrite, + // The following two states together represent S4 in the paper. + FlowToMemAliasWriteOnly, + FlowToMemAliasReadWrite, +}; + +using StateSet = std::bitset<7>; + +const unsigned ReadOnlyStateMask = + (1U << static_cast(MatchState::FlowFromReadOnly)) | + (1U << static_cast(MatchState::FlowFromMemAliasReadOnly)); +const unsigned WriteOnlyStateMask = + (1U << static_cast(MatchState::FlowToWriteOnly)) | + (1U << static_cast(MatchState::FlowToMemAliasWriteOnly)); + +// A pair that consists of a value and an offset +struct OffsetValue { + const Value *Val; + int64_t Offset; +}; + +bool operator==(OffsetValue LHS, OffsetValue RHS) { + return LHS.Val == RHS.Val && LHS.Offset == RHS.Offset; +} +bool operator<(OffsetValue LHS, OffsetValue RHS) { + return std::less()(LHS.Val, RHS.Val) || + (LHS.Val == RHS.Val && LHS.Offset < RHS.Offset); +} + +// A pair that consists of an InstantiatedValue and an offset +struct OffsetInstantiatedValue { + InstantiatedValue IVal; + int64_t Offset; +}; + +bool operator==(OffsetInstantiatedValue LHS, OffsetInstantiatedValue RHS) { + return LHS.IVal == RHS.IVal && LHS.Offset == RHS.Offset; +} + +// We use ReachabilitySet to keep track of value aliases (The nonterminal "V" in +// the paper) during the analysis. +class ReachabilitySet { + using ValueStateMap = DenseMap; + using ValueReachMap = DenseMap; + + ValueReachMap ReachMap; + +public: + using const_valuestate_iterator = ValueStateMap::const_iterator; + using const_value_iterator = ValueReachMap::const_iterator; + + // Insert edge 'From->To' at state 'State' + bool insert(InstantiatedValue From, InstantiatedValue To, MatchState State) { + assert(From != To); + auto &States = ReachMap[To][From]; + auto Idx = static_cast(State); + if (!States.test(Idx)) { + States.set(Idx); + return true; + } + return false; + } + + // Return the set of all ('From', 'State') pair for a given node 'To' + iterator_range + reachableValueAliases(InstantiatedValue V) const { + auto Itr = ReachMap.find(V); + if (Itr == ReachMap.end()) + return make_range(const_valuestate_iterator(), + const_valuestate_iterator()); + return make_range(Itr->second.begin(), + Itr->second.end()); + } + + iterator_range value_mappings() const { + return make_range(ReachMap.begin(), ReachMap.end()); + } +}; + +// We use AliasMemSet to keep track of all memory aliases (the nonterminal "M" +// in the paper) during the analysis. +class AliasMemSet { + using MemSet = DenseSet; + using MemMapType = DenseMap; + + MemMapType MemMap; + +public: + using const_mem_iterator = MemSet::const_iterator; + + bool insert(InstantiatedValue LHS, InstantiatedValue RHS) { + // Top-level values can never be memory aliases because one cannot take the + // addresses of them + assert(LHS.DerefLevel > 0 && RHS.DerefLevel > 0); + return MemMap[LHS].insert(RHS).second; + } + + const MemSet *getMemoryAliases(InstantiatedValue V) const { + auto Itr = MemMap.find(V); + if (Itr == MemMap.end()) + return nullptr; + return &Itr->second; + } +}; + +// We use AliasAttrMap to keep track of the AliasAttr of each node. +class AliasAttrMap { + using MapType = DenseMap; + + MapType AttrMap; + +public: + using const_iterator = MapType::const_iterator; + + bool add(InstantiatedValue V, AliasAttrs Attr) { + auto &OldAttr = AttrMap[V]; + auto NewAttr = OldAttr | Attr; + if (OldAttr == NewAttr) + return false; + OldAttr = NewAttr; + return true; + } + + AliasAttrs getAttrs(InstantiatedValue V) const { + AliasAttrs Attr; + auto Itr = AttrMap.find(V); + if (Itr != AttrMap.end()) + Attr = Itr->second; + return Attr; + } + + iterator_range mappings() const { + return make_range(AttrMap.begin(), AttrMap.end()); + } +}; + +struct WorkListItem { + InstantiatedValue From; + InstantiatedValue To; + MatchState State; +}; + +struct ValueSummary { + struct Record { + InterfaceValue IValue; + unsigned DerefLevel; + }; + SmallVector FromRecords, ToRecords; +}; + +} // end anonymous namespace + +namespace llvm { + +// Specialize DenseMapInfo for OffsetValue. +template <> struct DenseMapInfo { + static OffsetValue getEmptyKey() { + return OffsetValue{DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey()}; + } + + static OffsetValue getTombstoneKey() { + return OffsetValue{DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getEmptyKey()}; + } + + static unsigned getHashValue(const OffsetValue &OVal) { + return DenseMapInfo>::getHashValue( + std::make_pair(OVal.Val, OVal.Offset)); + } + + static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) { + return LHS == RHS; + } +}; + +// Specialize DenseMapInfo for OffsetInstantiatedValue. +template <> struct DenseMapInfo { + static OffsetInstantiatedValue getEmptyKey() { + return OffsetInstantiatedValue{ + DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey()}; + } + + static OffsetInstantiatedValue getTombstoneKey() { + return OffsetInstantiatedValue{ + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getEmptyKey()}; + } + + static unsigned getHashValue(const OffsetInstantiatedValue &OVal) { + return DenseMapInfo>::getHashValue( + std::make_pair(OVal.IVal, OVal.Offset)); + } + + static bool isEqual(const OffsetInstantiatedValue &LHS, + const OffsetInstantiatedValue &RHS) { + return LHS == RHS; + } +}; + +} // end namespace llvm + +class CFLAndersAAResult::FunctionInfo { + /// Map a value to other values that may alias it + /// Since the alias relation is symmetric, to save some space we assume values + /// are properly ordered: if a and b alias each other, and a < b, then b is in + /// AliasMap[a] but not vice versa. + DenseMap> AliasMap; + + /// Map a value to its corresponding AliasAttrs + DenseMap AttrMap; + + /// Summary of externally visible effects. + AliasSummary Summary; + + Optional getAttrs(const Value *) const; + +public: + FunctionInfo(const Function &, const SmallVectorImpl &, + const ReachabilitySet &, const AliasAttrMap &); + + bool mayAlias(const Value *, LocationSize, const Value *, LocationSize) const; + const AliasSummary &getAliasSummary() const { return Summary; } +}; + +static bool hasReadOnlyState(StateSet Set) { + return (Set & StateSet(ReadOnlyStateMask)).any(); +} + +static bool hasWriteOnlyState(StateSet Set) { + return (Set & StateSet(WriteOnlyStateMask)).any(); +} + +static Optional +getInterfaceValue(InstantiatedValue IValue, + const SmallVectorImpl &RetVals) { + auto Val = IValue.Val; + + Optional Index; + if (auto Arg = dyn_cast(Val)) + Index = Arg->getArgNo() + 1; + else if (is_contained(RetVals, Val)) + Index = 0; + + if (Index) + return InterfaceValue{*Index, IValue.DerefLevel}; + return None; +} + +static void populateAttrMap(DenseMap &AttrMap, + const AliasAttrMap &AMap) { + for (const auto &Mapping : AMap.mappings()) { + auto IVal = Mapping.first; + + // Insert IVal into the map + auto &Attr = AttrMap[IVal.Val]; + // AttrMap only cares about top-level values + if (IVal.DerefLevel == 0) + Attr |= Mapping.second; + } +} + +static void +populateAliasMap(DenseMap> &AliasMap, + const ReachabilitySet &ReachSet) { + for (const auto &OuterMapping : ReachSet.value_mappings()) { + // AliasMap only cares about top-level values + if (OuterMapping.first.DerefLevel > 0) + continue; + + auto Val = OuterMapping.first.Val; + auto &AliasList = AliasMap[Val]; + for (const auto &InnerMapping : OuterMapping.second) { + // Again, AliasMap only cares about top-level values + if (InnerMapping.first.DerefLevel == 0) + AliasList.push_back(OffsetValue{InnerMapping.first.Val, UnknownOffset}); + } + + // Sort AliasList for faster lookup + llvm::sort(AliasList); + } +} + +static void populateExternalRelations( + SmallVectorImpl &ExtRelations, const Function &Fn, + const SmallVectorImpl &RetVals, const ReachabilitySet &ReachSet) { + // If a function only returns one of its argument X, then X will be both an + // argument and a return value at the same time. This is an edge case that + // needs special handling here. + for (const auto &Arg : Fn.args()) { + if (is_contained(RetVals, &Arg)) { + auto ArgVal = InterfaceValue{Arg.getArgNo() + 1, 0}; + auto RetVal = InterfaceValue{0, 0}; + ExtRelations.push_back(ExternalRelation{ArgVal, RetVal, 0}); + } + } + + // Below is the core summary construction logic. + // A naive solution of adding only the value aliases that are parameters or + // return values in ReachSet to the summary won't work: It is possible that a + // parameter P is written into an intermediate value I, and the function + // subsequently returns *I. In that case, *I is does not value alias anything + // in ReachSet, and the naive solution will miss a summary edge from (P, 1) to + // (I, 1). + // To account for the aforementioned case, we need to check each non-parameter + // and non-return value for the possibility of acting as an intermediate. + // 'ValueMap' here records, for each value, which InterfaceValues read from or + // write into it. If both the read list and the write list of a given value + // are non-empty, we know that a particular value is an intermidate and we + // need to add summary edges from the writes to the reads. + DenseMap ValueMap; + for (const auto &OuterMapping : ReachSet.value_mappings()) { + if (auto Dst = getInterfaceValue(OuterMapping.first, RetVals)) { + for (const auto &InnerMapping : OuterMapping.second) { + // If Src is a param/return value, we get a same-level assignment. + if (auto Src = getInterfaceValue(InnerMapping.first, RetVals)) { + // This may happen if both Dst and Src are return values + if (*Dst == *Src) + continue; + + if (hasReadOnlyState(InnerMapping.second)) + ExtRelations.push_back(ExternalRelation{*Dst, *Src, UnknownOffset}); + // No need to check for WriteOnly state, since ReachSet is symmetric + } else { + // If Src is not a param/return, add it to ValueMap + auto SrcIVal = InnerMapping.first; + if (hasReadOnlyState(InnerMapping.second)) + ValueMap[SrcIVal.Val].FromRecords.push_back( + ValueSummary::Record{*Dst, SrcIVal.DerefLevel}); + if (hasWriteOnlyState(InnerMapping.second)) + ValueMap[SrcIVal.Val].ToRecords.push_back( + ValueSummary::Record{*Dst, SrcIVal.DerefLevel}); + } + } + } + } + + for (const auto &Mapping : ValueMap) { + for (const auto &FromRecord : Mapping.second.FromRecords) { + for (const auto &ToRecord : Mapping.second.ToRecords) { + auto ToLevel = ToRecord.DerefLevel; + auto FromLevel = FromRecord.DerefLevel; + // Same-level assignments should have already been processed by now + if (ToLevel == FromLevel) + continue; + + auto SrcIndex = FromRecord.IValue.Index; + auto SrcLevel = FromRecord.IValue.DerefLevel; + auto DstIndex = ToRecord.IValue.Index; + auto DstLevel = ToRecord.IValue.DerefLevel; + if (ToLevel > FromLevel) + SrcLevel += ToLevel - FromLevel; + else + DstLevel += FromLevel - ToLevel; + + ExtRelations.push_back(ExternalRelation{ + InterfaceValue{SrcIndex, SrcLevel}, + InterfaceValue{DstIndex, DstLevel}, UnknownOffset}); + } + } + } + + // Remove duplicates in ExtRelations + llvm::sort(ExtRelations); + ExtRelations.erase(std::unique(ExtRelations.begin(), ExtRelations.end()), + ExtRelations.end()); +} + +static void populateExternalAttributes( + SmallVectorImpl &ExtAttributes, const Function &Fn, + const SmallVectorImpl &RetVals, const AliasAttrMap &AMap) { + for (const auto &Mapping : AMap.mappings()) { + if (auto IVal = getInterfaceValue(Mapping.first, RetVals)) { + auto Attr = getExternallyVisibleAttrs(Mapping.second); + if (Attr.any()) + ExtAttributes.push_back(ExternalAttribute{*IVal, Attr}); + } + } +} + +CFLAndersAAResult::FunctionInfo::FunctionInfo( + const Function &Fn, const SmallVectorImpl &RetVals, + const ReachabilitySet &ReachSet, const AliasAttrMap &AMap) { + populateAttrMap(AttrMap, AMap); + populateExternalAttributes(Summary.RetParamAttributes, Fn, RetVals, AMap); + populateAliasMap(AliasMap, ReachSet); + populateExternalRelations(Summary.RetParamRelations, Fn, RetVals, ReachSet); +} + +Optional +CFLAndersAAResult::FunctionInfo::getAttrs(const Value *V) const { + assert(V != nullptr); + + auto Itr = AttrMap.find(V); + if (Itr != AttrMap.end()) + return Itr->second; + return None; +} + +bool CFLAndersAAResult::FunctionInfo::mayAlias( + const Value *LHS, LocationSize MaybeLHSSize, const Value *RHS, + LocationSize MaybeRHSSize) const { + assert(LHS && RHS); + + // Check if we've seen LHS and RHS before. Sometimes LHS or RHS can be created + // after the analysis gets executed, and we want to be conservative in those + // cases. + auto MaybeAttrsA = getAttrs(LHS); + auto MaybeAttrsB = getAttrs(RHS); + if (!MaybeAttrsA || !MaybeAttrsB) + return true; + + // Check AliasAttrs before AliasMap lookup since it's cheaper + auto AttrsA = *MaybeAttrsA; + auto AttrsB = *MaybeAttrsB; + if (hasUnknownOrCallerAttr(AttrsA)) + return AttrsB.any(); + if (hasUnknownOrCallerAttr(AttrsB)) + return AttrsA.any(); + if (isGlobalOrArgAttr(AttrsA)) + return isGlobalOrArgAttr(AttrsB); + if (isGlobalOrArgAttr(AttrsB)) + return isGlobalOrArgAttr(AttrsA); + + // At this point both LHS and RHS should point to locally allocated objects + + auto Itr = AliasMap.find(LHS); + if (Itr != AliasMap.end()) { + + // Find out all (X, Offset) where X == RHS + auto Comparator = [](OffsetValue LHS, OffsetValue RHS) { + return std::less()(LHS.Val, RHS.Val); + }; +#ifdef EXPENSIVE_CHECKS + assert(llvm::is_sorted(Itr->second, Comparator)); +#endif + auto RangePair = std::equal_range(Itr->second.begin(), Itr->second.end(), + OffsetValue{RHS, 0}, Comparator); + + if (RangePair.first != RangePair.second) { + // Be conservative about unknown sizes + if (!MaybeLHSSize.hasValue() || !MaybeRHSSize.hasValue()) + return true; + + const uint64_t LHSSize = MaybeLHSSize.getValue(); + const uint64_t RHSSize = MaybeRHSSize.getValue(); + + for (const auto &OVal : make_range(RangePair)) { + // Be conservative about UnknownOffset + if (OVal.Offset == UnknownOffset) + return true; + + // We know that LHS aliases (RHS + OVal.Offset) if the control flow + // reaches here. The may-alias query essentially becomes integer + // range-overlap queries over two ranges [OVal.Offset, OVal.Offset + + // LHSSize) and [0, RHSSize). + + // Try to be conservative on super large offsets + if (LLVM_UNLIKELY(LHSSize > INT64_MAX || RHSSize > INT64_MAX)) + return true; + + auto LHSStart = OVal.Offset; + // FIXME: Do we need to guard against integer overflow? + auto LHSEnd = OVal.Offset + static_cast(LHSSize); + auto RHSStart = 0; + auto RHSEnd = static_cast(RHSSize); + if (LHSEnd > RHSStart && LHSStart < RHSEnd) + return true; + } + } + } + + return false; +} + +static void propagate(InstantiatedValue From, InstantiatedValue To, + MatchState State, ReachabilitySet &ReachSet, + std::vector &WorkList) { + if (From == To) + return; + if (ReachSet.insert(From, To, State)) + WorkList.push_back(WorkListItem{From, To, State}); +} + +static void initializeWorkList(std::vector &WorkList, + ReachabilitySet &ReachSet, + const CFLGraph &Graph) { + for (const auto &Mapping : Graph.value_mappings()) { + auto Val = Mapping.first; + auto &ValueInfo = Mapping.second; + assert(ValueInfo.getNumLevels() > 0); + + // Insert all immediate assignment neighbors to the worklist + for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) { + auto Src = InstantiatedValue{Val, I}; + // If there's an assignment edge from X to Y, it means Y is reachable from + // X at S3 and X is reachable from Y at S1 + for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges) { + propagate(Edge.Other, Src, MatchState::FlowFromReadOnly, ReachSet, + WorkList); + propagate(Src, Edge.Other, MatchState::FlowToWriteOnly, ReachSet, + WorkList); + } + } + } +} + +static Optional getNodeBelow(const CFLGraph &Graph, + InstantiatedValue V) { + auto NodeBelow = InstantiatedValue{V.Val, V.DerefLevel + 1}; + if (Graph.getNode(NodeBelow)) + return NodeBelow; + return None; +} + +static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph, + ReachabilitySet &ReachSet, AliasMemSet &MemSet, + std::vector &WorkList) { + auto FromNode = Item.From; + auto ToNode = Item.To; + + auto NodeInfo = Graph.getNode(ToNode); + assert(NodeInfo != nullptr); + + // TODO: propagate field offsets + + // FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds + // relations that are symmetric, we could actually cut the storage by half by + // sorting FromNode and ToNode before insertion happens. + + // The newly added value alias pair may potentially generate more memory + // alias pairs. Check for them here. + auto FromNodeBelow = getNodeBelow(Graph, FromNode); + auto ToNodeBelow = getNodeBelow(Graph, ToNode); + if (FromNodeBelow && ToNodeBelow && + MemSet.insert(*FromNodeBelow, *ToNodeBelow)) { + propagate(*FromNodeBelow, *ToNodeBelow, + MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList); + for (const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) { + auto Src = Mapping.first; + auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) { + if (Mapping.second.test(static_cast(FromState))) + propagate(Src, *ToNodeBelow, ToState, ReachSet, WorkList); + }; + + MemAliasPropagate(MatchState::FlowFromReadOnly, + MatchState::FlowFromMemAliasReadOnly); + MemAliasPropagate(MatchState::FlowToWriteOnly, + MatchState::FlowToMemAliasWriteOnly); + MemAliasPropagate(MatchState::FlowToReadWrite, + MatchState::FlowToMemAliasReadWrite); + } + } + + // This is the core of the state machine walking algorithm. We expand ReachSet + // based on which state we are at (which in turn dictates what edges we + // should examine) + // From a high-level point of view, the state machine here guarantees two + // properties: + // - If *X and *Y are memory aliases, then X and Y are value aliases + // - If Y is an alias of X, then reverse assignment edges (if there is any) + // should precede any assignment edges on the path from X to Y. + auto NextAssignState = [&](MatchState State) { + for (const auto &AssignEdge : NodeInfo->Edges) + propagate(FromNode, AssignEdge.Other, State, ReachSet, WorkList); + }; + auto NextRevAssignState = [&](MatchState State) { + for (const auto &RevAssignEdge : NodeInfo->ReverseEdges) + propagate(FromNode, RevAssignEdge.Other, State, ReachSet, WorkList); + }; + auto NextMemState = [&](MatchState State) { + if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) { + for (const auto &MemAlias : *AliasSet) + propagate(FromNode, MemAlias, State, ReachSet, WorkList); + } + }; + + switch (Item.State) { + case MatchState::FlowFromReadOnly: + NextRevAssignState(MatchState::FlowFromReadOnly); + NextAssignState(MatchState::FlowToReadWrite); + NextMemState(MatchState::FlowFromMemAliasReadOnly); + break; + + case MatchState::FlowFromMemAliasNoReadWrite: + NextRevAssignState(MatchState::FlowFromReadOnly); + NextAssignState(MatchState::FlowToWriteOnly); + break; + + case MatchState::FlowFromMemAliasReadOnly: + NextRevAssignState(MatchState::FlowFromReadOnly); + NextAssignState(MatchState::FlowToReadWrite); + break; + + case MatchState::FlowToWriteOnly: + NextAssignState(MatchState::FlowToWriteOnly); + NextMemState(MatchState::FlowToMemAliasWriteOnly); + break; + + case MatchState::FlowToReadWrite: + NextAssignState(MatchState::FlowToReadWrite); + NextMemState(MatchState::FlowToMemAliasReadWrite); + break; + + case MatchState::FlowToMemAliasWriteOnly: + NextAssignState(MatchState::FlowToWriteOnly); + break; + + case MatchState::FlowToMemAliasReadWrite: + NextAssignState(MatchState::FlowToReadWrite); + break; + } +} + +static AliasAttrMap buildAttrMap(const CFLGraph &Graph, + const ReachabilitySet &ReachSet) { + AliasAttrMap AttrMap; + std::vector WorkList, NextList; + + // Initialize each node with its original AliasAttrs in CFLGraph + for (const auto &Mapping : Graph.value_mappings()) { + auto Val = Mapping.first; + auto &ValueInfo = Mapping.second; + for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) { + auto Node = InstantiatedValue{Val, I}; + AttrMap.add(Node, ValueInfo.getNodeInfoAtLevel(I).Attr); + WorkList.push_back(Node); + } + } + + while (!WorkList.empty()) { + for (const auto &Dst : WorkList) { + auto DstAttr = AttrMap.getAttrs(Dst); + if (DstAttr.none()) + continue; + + // Propagate attr on the same level + for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) { + auto Src = Mapping.first; + if (AttrMap.add(Src, DstAttr)) + NextList.push_back(Src); + } + + // Propagate attr to the levels below + auto DstBelow = getNodeBelow(Graph, Dst); + while (DstBelow) { + if (AttrMap.add(*DstBelow, DstAttr)) { + NextList.push_back(*DstBelow); + break; + } + DstBelow = getNodeBelow(Graph, *DstBelow); + } + } + WorkList.swap(NextList); + NextList.clear(); + } + + return AttrMap; +} + +CFLAndersAAResult::FunctionInfo +CFLAndersAAResult::buildInfoFrom(const Function &Fn) { + CFLGraphBuilder GraphBuilder( + *this, GetTLI(const_cast(Fn)), + // Cast away the constness here due to GraphBuilder's API requirement + const_cast(Fn)); + auto &Graph = GraphBuilder.getCFLGraph(); + + ReachabilitySet ReachSet; + AliasMemSet MemSet; + + std::vector WorkList, NextList; + initializeWorkList(WorkList, ReachSet, Graph); + // TODO: make sure we don't stop before the fix point is reached + while (!WorkList.empty()) { + for (const auto &Item : WorkList) + processWorkListItem(Item, Graph, ReachSet, MemSet, NextList); + + NextList.swap(WorkList); + NextList.clear(); + } + + // Now that we have all the reachability info, propagate AliasAttrs according + // to it + auto IValueAttrMap = buildAttrMap(Graph, ReachSet); + + return FunctionInfo(Fn, GraphBuilder.getReturnValues(), ReachSet, + std::move(IValueAttrMap)); +} + +void CFLAndersAAResult::scan(const Function &Fn) { + auto InsertPair = Cache.insert(std::make_pair(&Fn, Optional())); + (void)InsertPair; + assert(InsertPair.second && + "Trying to scan a function that has already been cached"); + + // Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call + // may get evaluated after operator[], potentially triggering a DenseMap + // resize and invalidating the reference returned by operator[] + auto FunInfo = buildInfoFrom(Fn); + Cache[&Fn] = std::move(FunInfo); + Handles.emplace_front(const_cast(&Fn), this); +} + +void CFLAndersAAResult::evict(const Function *Fn) { Cache.erase(Fn); } + +const Optional & +CFLAndersAAResult::ensureCached(const Function &Fn) { + auto Iter = Cache.find(&Fn); + if (Iter == Cache.end()) { + scan(Fn); + Iter = Cache.find(&Fn); + assert(Iter != Cache.end()); + assert(Iter->second.hasValue()); + } + return Iter->second; +} + +const AliasSummary *CFLAndersAAResult::getAliasSummary(const Function &Fn) { + auto &FunInfo = ensureCached(Fn); + if (FunInfo.hasValue()) + return &FunInfo->getAliasSummary(); + else + return nullptr; +} + +AliasResult CFLAndersAAResult::query(const MemoryLocation &LocA, + const MemoryLocation &LocB) { + auto *ValA = LocA.Ptr; + auto *ValB = LocB.Ptr; + + if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy()) + return AliasResult::NoAlias; + + auto *Fn = parentFunctionOfValue(ValA); + if (!Fn) { + Fn = parentFunctionOfValue(ValB); + if (!Fn) { + // The only times this is known to happen are when globals + InlineAsm are + // involved + LLVM_DEBUG( + dbgs() + << "CFLAndersAA: could not extract parent function information.\n"); + return AliasResult::MayAlias; + } + } else { + assert(!parentFunctionOfValue(ValB) || parentFunctionOfValue(ValB) == Fn); + } + + assert(Fn != nullptr); + auto &FunInfo = ensureCached(*Fn); + + // AliasMap lookup + if (FunInfo->mayAlias(ValA, LocA.Size, ValB, LocB.Size)) + return AliasResult::MayAlias; + return AliasResult::NoAlias; +} + +AliasResult CFLAndersAAResult::alias(const MemoryLocation &LocA, + const MemoryLocation &LocB, + AAQueryInfo &AAQI) { + if (LocA.Ptr == LocB.Ptr) + return AliasResult::MustAlias; + + // Comparisons between global variables and other constants should be + // handled by BasicAA. + // CFLAndersAA may report NoAlias when comparing a GlobalValue and + // ConstantExpr, but every query needs to have at least one Value tied to a + // Function, and neither GlobalValues nor ConstantExprs are. + if (isa(LocA.Ptr) && isa(LocB.Ptr)) + return AAResultBase::alias(LocA, LocB, AAQI); + + AliasResult QueryResult = query(LocA, LocB); + if (QueryResult == AliasResult::MayAlias) + return AAResultBase::alias(LocA, LocB, AAQI); + + return QueryResult; +} + +AnalysisKey CFLAndersAA::Key; + +CFLAndersAAResult CFLAndersAA::run(Function &F, FunctionAnalysisManager &AM) { + auto GetTLI = [&AM](Function &F) -> TargetLibraryInfo & { + return AM.getResult(F); + }; + return CFLAndersAAResult(GetTLI); +} + +char CFLAndersAAWrapperPass::ID = 0; +INITIALIZE_PASS(CFLAndersAAWrapperPass, "cfl-anders-aa", + "Inclusion-Based CFL Alias Analysis", false, true) + +ImmutablePass *llvm::createCFLAndersAAWrapperPass() { + return new CFLAndersAAWrapperPass(); +} + +CFLAndersAAWrapperPass::CFLAndersAAWrapperPass() : ImmutablePass(ID) { + initializeCFLAndersAAWrapperPassPass(*PassRegistry::getPassRegistry()); +} + +void CFLAndersAAWrapperPass::initializePass() { + auto GetTLI = [this](Function &F) -> TargetLibraryInfo & { + return this->getAnalysis().getTLI(F); + }; + Result.reset(new CFLAndersAAResult(GetTLI)); +} + +void CFLAndersAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); +} diff --git a/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.h b/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.h new file mode 100644 index 000000000..ddc290885 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.h @@ -0,0 +1,128 @@ +//==- CFLAndersAliasAnalysis.h - Unification-based Alias Analysis -*- C++-*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This is the interface for LLVM's inclusion-based alias analysis +/// implemented with CFL graph reachability. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H +#define LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CFLAliasAnalysisUtils.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" + +#include +#include + +namespace llvm { + +class Function; +class MemoryLocation; +class TargetLibraryInfo; + +namespace cflaa { + +struct AliasSummary; + +} // end namespace cflaa + +class CFLAndersAAResult : public AAResultBase { + friend AAResultBase; + + class FunctionInfo; + +public: + explicit CFLAndersAAResult( + std::function GetTLI); + CFLAndersAAResult(CFLAndersAAResult &&RHS); + ~CFLAndersAAResult(); + + /// Handle invalidation events from the new pass manager. + /// By definition, this result is stateless and so remains valid. + bool invalidate(Function &, const PreservedAnalyses &, + FunctionAnalysisManager::Invalidator &) { + return false; + } + + /// Evict the given function from cache + void evict(const Function *Fn); + + /// Get the alias summary for the given function + /// Return nullptr if the summary is not found or not available + const cflaa::AliasSummary *getAliasSummary(const Function &); + + AliasResult query(const MemoryLocation &, const MemoryLocation &); + AliasResult alias(const MemoryLocation &, const MemoryLocation &, + AAQueryInfo &); + +private: + /// Ensures that the given function is available in the cache. + /// Returns the appropriate entry from the cache. + const Optional &ensureCached(const Function &); + + /// Inserts the given Function into the cache. + void scan(const Function &); + + /// Build summary for a given function + FunctionInfo buildInfoFrom(const Function &); + + std::function GetTLI; + + /// Cached mapping of Functions to their StratifiedSets. + /// If a function's sets are currently being built, it is marked + /// in the cache as an Optional without a value. This way, if we + /// have any kind of recursion, it is discernable from a function + /// that simply has empty sets. + DenseMap> Cache; + + std::forward_list> Handles; +}; + +/// Analysis pass providing a never-invalidated alias analysis result. +/// +/// FIXME: We really should refactor CFL to use the analysis more heavily, and +/// in particular to leverage invalidation to trigger re-computation. +class CFLAndersAA : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + + static AnalysisKey Key; + +public: + using Result = CFLAndersAAResult; + + CFLAndersAAResult run(Function &F, FunctionAnalysisManager &AM); +}; + +/// Legacy wrapper pass to provide the CFLAndersAAResult object. +class CFLAndersAAWrapperPass : public ImmutablePass { + std::unique_ptr Result; + +public: + static char ID; + + CFLAndersAAWrapperPass(); + + CFLAndersAAResult &getResult() { return *Result; } + const CFLAndersAAResult &getResult() const { return *Result; } + + void initializePass() override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +// createCFLAndersAAWrapperPass - This pass implements a set-based approach to +// alias analysis. +ImmutablePass *createCFLAndersAAWrapperPass(); + +} // end namespace llvm + +#endif // LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H diff --git a/lib/PhasarLLVM/Pointer/external/llvm/CFLGraph.h b/lib/PhasarLLVM/Pointer/external/llvm/CFLGraph.h new file mode 100644 index 000000000..1e50223cb --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/CFLGraph.h @@ -0,0 +1,669 @@ +//===- CFLGraph.h - Abstract stratified sets implementation. -----*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// This file defines CFLGraph, an auxiliary data structure used by CFL-based +/// alias analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_ANALYSIS_CFLGRAPH_H +#define LLVM_LIB_ANALYSIS_CFLGRAPH_H + +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" + +#include "AliasAnalysisSummary.h" + +#include +#include +#include + +namespace llvm { +namespace cflaa { + +/// The Program Expression Graph (PEG) of CFL analysis +/// CFLGraph is auxiliary data structure used by CFL-based alias analysis to +/// describe flow-insensitive pointer-related behaviors. Given an LLVM function, +/// the main purpose of this graph is to abstract away unrelated facts and +/// translate the rest into a form that can be easily digested by CFL analyses. +/// Each Node in the graph is an InstantiatedValue, and each edge represent a +/// pointer assignment between InstantiatedValue. Pointer +/// references/dereferences are not explicitly stored in the graph: we +/// implicitly assume that for each node (X, I) it has a dereference edge to (X, +/// I+1) and a reference edge to (X, I-1). +class CFLGraph { +public: + using Node = InstantiatedValue; + + struct Edge { + Node Other; + int64_t Offset; + }; + + using EdgeList = std::vector; + + struct NodeInfo { + EdgeList Edges, ReverseEdges; + AliasAttrs Attr; + }; + + class ValueInfo { + std::vector Levels; + + public: + bool addNodeToLevel(unsigned Level) { + auto NumLevels = Levels.size(); + if (NumLevels > Level) + return false; + Levels.resize(Level + 1); + return true; + } + + NodeInfo &getNodeInfoAtLevel(unsigned Level) { + assert(Level < Levels.size()); + return Levels[Level]; + } + const NodeInfo &getNodeInfoAtLevel(unsigned Level) const { + assert(Level < Levels.size()); + return Levels[Level]; + } + + unsigned getNumLevels() const { return Levels.size(); } + }; + +private: + using ValueMap = DenseMap; + + ValueMap ValueImpls; + + NodeInfo *getNode(Node N) { + auto Itr = ValueImpls.find(N.Val); + if (Itr == ValueImpls.end() || Itr->second.getNumLevels() <= N.DerefLevel) + return nullptr; + return &Itr->second.getNodeInfoAtLevel(N.DerefLevel); + } + +public: + using const_value_iterator = ValueMap::const_iterator; + + bool addNode(Node N, AliasAttrs Attr = AliasAttrs()) { + assert(N.Val != nullptr); + auto &ValInfo = ValueImpls[N.Val]; + auto Changed = ValInfo.addNodeToLevel(N.DerefLevel); + ValInfo.getNodeInfoAtLevel(N.DerefLevel).Attr |= Attr; + return Changed; + } + + void addAttr(Node N, AliasAttrs Attr) { + auto *Info = getNode(N); + assert(Info != nullptr); + Info->Attr |= Attr; + } + + void addEdge(Node From, Node To, int64_t Offset = 0) { + auto *FromInfo = getNode(From); + assert(FromInfo != nullptr); + auto *ToInfo = getNode(To); + assert(ToInfo != nullptr); + + FromInfo->Edges.push_back(Edge{To, Offset}); + ToInfo->ReverseEdges.push_back(Edge{From, Offset}); + } + + const NodeInfo *getNode(Node N) const { + auto Itr = ValueImpls.find(N.Val); + if (Itr == ValueImpls.end() || Itr->second.getNumLevels() <= N.DerefLevel) + return nullptr; + return &Itr->second.getNodeInfoAtLevel(N.DerefLevel); + } + + AliasAttrs attrFor(Node N) const { + auto *Info = getNode(N); + assert(Info != nullptr); + return Info->Attr; + } + + iterator_range value_mappings() const { + return make_range(ValueImpls.begin(), + ValueImpls.end()); + } +}; + +/// A builder class used to create CFLGraph instance from a given function +/// The CFL-AA that uses this builder must provide its own type as a template +/// argument. This is necessary for interprocedural processing: CFLGraphBuilder +/// needs a way of obtaining the summary of other functions when callinsts are +/// encountered. +/// As a result, we expect the said CFL-AA to expose a getAliasSummary() public +/// member function that takes a Function& and returns the corresponding summary +/// as a const AliasSummary*. +template class CFLGraphBuilder { + // Input of the builder + CFLAA &Analysis; + const TargetLibraryInfo &TLI; + + // Output of the builder + CFLGraph Graph; + SmallVector ReturnedValues; + + // Helper class + /// Gets the edges our graph should have, based on an Instruction* + class GetEdgesVisitor : public InstVisitor { + CFLAA &AA; + const DataLayout &DL; + const TargetLibraryInfo &TLI; + + CFLGraph &Graph; + SmallVectorImpl &ReturnValues; + + static bool hasUsefulEdges(ConstantExpr *CE) { + // ConstantExpr doesn't have terminators, invokes, or fences, so only + // needs to check for compares. + return CE->getOpcode() != Instruction::ICmp && + CE->getOpcode() != Instruction::FCmp; + } + + // Returns possible functions called by CS into the given SmallVectorImpl. + // Returns true if targets found, false otherwise. + static bool getPossibleTargets(CallBase &Call, + SmallVectorImpl &Output) { + if (auto *Fn = Call.getCalledFunction()) { + Output.push_back(Fn); + return true; + } + + // TODO: If the call is indirect, we might be able to enumerate all + // potential targets of the call and return them, rather than just + // failing. + return false; + } + + void addNode(Value *Val, AliasAttrs Attr = AliasAttrs()) { + assert(Val != nullptr && Val->getType()->isPointerTy()); + if (auto GVal = dyn_cast(Val)) { + if (Graph.addNode(InstantiatedValue{GVal, 0}, + getGlobalOrArgAttrFromValue(*GVal))) + Graph.addNode(InstantiatedValue{GVal, 1}, getAttrUnknown()); + } else if (auto CExpr = dyn_cast(Val)) { + if (hasUsefulEdges(CExpr)) { + if (Graph.addNode(InstantiatedValue{CExpr, 0})) + visitConstantExpr(CExpr); + } + } else + Graph.addNode(InstantiatedValue{Val, 0}, Attr); + } + + void addAssignEdge(Value *From, Value *To, int64_t Offset = 0) { + assert(From != nullptr && To != nullptr); + if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy()) + return; + addNode(From); + if (To != From) { + addNode(To); + Graph.addEdge(InstantiatedValue{From, 0}, InstantiatedValue{To, 0}, + Offset); + } + } + + void addDerefEdge(Value *From, Value *To, bool IsRead) { + assert(From != nullptr && To != nullptr); + // FIXME: This is subtly broken, due to how we model some instructions + // (e.g. extractvalue, extractelement) as loads. Since those take + // non-pointer operands, we'll entirely skip adding edges for those. + // + // addAssignEdge seems to have a similar issue with insertvalue, etc. + if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy()) + return; + addNode(From); + addNode(To); + if (IsRead) { + Graph.addNode(InstantiatedValue{From, 1}); + Graph.addEdge(InstantiatedValue{From, 1}, InstantiatedValue{To, 0}); + } else { + Graph.addNode(InstantiatedValue{To, 1}); + Graph.addEdge(InstantiatedValue{From, 0}, InstantiatedValue{To, 1}); + } + } + + void addLoadEdge(Value *From, Value *To) { addDerefEdge(From, To, true); } + void addStoreEdge(Value *From, Value *To) { addDerefEdge(From, To, false); } + + public: + GetEdgesVisitor(CFLGraphBuilder &Builder, const DataLayout &DL) + : AA(Builder.Analysis), DL(DL), TLI(Builder.TLI), Graph(Builder.Graph), + ReturnValues(Builder.ReturnedValues) {} + + void visitInstruction(Instruction &) { + llvm_unreachable("Unsupported instruction encountered"); + } + + void visitReturnInst(ReturnInst &Inst) { + if (auto RetVal = Inst.getReturnValue()) { + if (RetVal->getType()->isPointerTy()) { + addNode(RetVal); + ReturnValues.push_back(RetVal); + } + } + } + + void visitPtrToIntInst(PtrToIntInst &Inst) { + auto *Ptr = Inst.getOperand(0); + addNode(Ptr, getAttrEscaped()); + } + + void visitIntToPtrInst(IntToPtrInst &Inst) { + auto *Ptr = &Inst; + addNode(Ptr, getAttrUnknown()); + } + + void visitCastInst(CastInst &Inst) { + auto *Src = Inst.getOperand(0); + addAssignEdge(Src, &Inst); + } + + void visitFreezeInst(FreezeInst &Inst) { + // Accessing freeze(ptr) is equivalent to accessing ptr. + // The former raises UB iff latter raises UB. + auto *Src = Inst.getOperand(0); + addAssignEdge(Src, &Inst); + } + + void visitBinaryOperator(BinaryOperator &Inst) { + auto *Op1 = Inst.getOperand(0); + auto *Op2 = Inst.getOperand(1); + addAssignEdge(Op1, &Inst); + addAssignEdge(Op2, &Inst); + } + + void visitUnaryOperator(UnaryOperator &Inst) { + auto *Src = Inst.getOperand(0); + addAssignEdge(Src, &Inst); + } + + void visitAtomicCmpXchgInst(AtomicCmpXchgInst &Inst) { + auto *Ptr = Inst.getPointerOperand(); + auto *Val = Inst.getNewValOperand(); + addStoreEdge(Val, Ptr); + } + + void visitAtomicRMWInst(AtomicRMWInst &Inst) { + auto *Ptr = Inst.getPointerOperand(); + auto *Val = Inst.getValOperand(); + addStoreEdge(Val, Ptr); + } + + void visitPHINode(PHINode &Inst) { + for (Value *Val : Inst.incoming_values()) + addAssignEdge(Val, &Inst); + } + + void visitGEP(GEPOperator &GEPOp) { + uint64_t Offset = UnknownOffset; + APInt APOffset(DL.getPointerSizeInBits(GEPOp.getPointerAddressSpace()), + 0); + if (GEPOp.accumulateConstantOffset(DL, APOffset)) + Offset = APOffset.getSExtValue(); + + auto *Op = GEPOp.getPointerOperand(); + addAssignEdge(Op, &GEPOp, Offset); + } + + void visitGetElementPtrInst(GetElementPtrInst &Inst) { + auto *GEPOp = cast(&Inst); + visitGEP(*GEPOp); + } + + void visitSelectInst(SelectInst &Inst) { + // Condition is not processed here (The actual statement producing + // the condition result is processed elsewhere). For select, the + // condition is evaluated, but not loaded, stored, or assigned + // simply as a result of being the condition of a select. + + auto *TrueVal = Inst.getTrueValue(); + auto *FalseVal = Inst.getFalseValue(); + addAssignEdge(TrueVal, &Inst); + addAssignEdge(FalseVal, &Inst); + } + + void visitAllocaInst(AllocaInst &Inst) { addNode(&Inst); } + + void visitLoadInst(LoadInst &Inst) { + auto *Ptr = Inst.getPointerOperand(); + auto *Val = &Inst; + addLoadEdge(Ptr, Val); + } + + void visitStoreInst(StoreInst &Inst) { + auto *Ptr = Inst.getPointerOperand(); + auto *Val = Inst.getValueOperand(); + addStoreEdge(Val, Ptr); + } + + void visitVAArgInst(VAArgInst &Inst) { + // We can't fully model va_arg here. For *Ptr = Inst.getOperand(0), it + // does + // two things: + // 1. Loads a value from *((T*)*Ptr). + // 2. Increments (stores to) *Ptr by some target-specific amount. + // For now, we'll handle this like a landingpad instruction (by placing + // the + // result in its own group, and having that group alias externals). + if (Inst.getType()->isPointerTy()) + addNode(&Inst, getAttrUnknown()); + } + + static bool isFunctionExternal(Function *Fn) { + return !Fn->hasExactDefinition(); + } + + bool tryInterproceduralAnalysis(CallBase &Call, + const SmallVectorImpl &Fns) { + assert(Fns.size() > 0); + + if (Call.arg_size() > MaxSupportedArgsInSummary) + return false; + + // Exit early if we'll fail anyway + for (auto *Fn : Fns) { + if (isFunctionExternal(Fn) || Fn->isVarArg()) + return false; + // Fail if the caller does not provide enough arguments + assert(Fn->arg_size() <= Call.arg_size()); + if (!AA.getAliasSummary(*Fn)) + return false; + } + + for (auto *Fn : Fns) { + auto Summary = AA.getAliasSummary(*Fn); + assert(Summary != nullptr); + + auto &RetParamRelations = Summary->RetParamRelations; + for (auto &Relation : RetParamRelations) { + auto IRelation = instantiateExternalRelation(Relation, Call); + if (IRelation.hasValue()) { + Graph.addNode(IRelation->From); + Graph.addNode(IRelation->To); + Graph.addEdge(IRelation->From, IRelation->To); + } + } + + auto &RetParamAttributes = Summary->RetParamAttributes; + for (auto &Attribute : RetParamAttributes) { + auto IAttr = instantiateExternalAttribute(Attribute, Call); + if (IAttr.hasValue()) + Graph.addNode(IAttr->IValue, IAttr->Attr); + } + } + + return true; + } + + void visitCallBase(CallBase &Call) { + // Make sure all arguments and return value are added to the graph first + for (Value *V : Call.args()) + if (V->getType()->isPointerTy()) + addNode(V); + if (Call.getType()->isPointerTy()) + addNode(&Call); + + // Check if Inst is a call to a library function that + // allocates/deallocates on the heap. Those kinds of functions do not + // introduce any aliases. + // TODO: address other common library functions such as realloc(), + // strdup(), etc. + if (isMallocOrCallocLikeFn(&Call, &TLI) || isFreeCall(&Call, &TLI)) + return; + + // TODO: Add support for noalias args/all the other fun function + // attributes that we can tack on. + SmallVector Targets; + if (getPossibleTargets(Call, Targets)) + if (tryInterproceduralAnalysis(Call, Targets)) + return; + + // Because the function is opaque, we need to note that anything + // could have happened to the arguments (unless the function is marked + // readonly or readnone), and that the result could alias just about + // anything, too (unless the result is marked noalias). + if (!Call.onlyReadsMemory()) + for (Value *V : Call.args()) { + if (V->getType()->isPointerTy()) { + // The argument itself escapes. + Graph.addAttr(InstantiatedValue{V, 0}, getAttrEscaped()); + // The fate of argument memory is unknown. Note that since + // AliasAttrs is transitive with respect to dereference, we only + // need to specify it for the first-level memory. + Graph.addNode(InstantiatedValue{V, 1}, getAttrUnknown()); + } + } + + if (Call.getType()->isPointerTy()) { + auto *Fn = Call.getCalledFunction(); + if (Fn == nullptr || !Fn->returnDoesNotAlias()) + // No need to call addNode() since we've added Inst at the + // beginning of this function and we know it is not a global. + Graph.addAttr(InstantiatedValue{&Call, 0}, getAttrUnknown()); + } + } + + /// Because vectors/aggregates are immutable and unaddressable, there's + /// nothing we can do to coax a value out of them, other than calling + /// Extract{Element,Value}. We can effectively treat them as pointers to + /// arbitrary memory locations we can store in and load from. + void visitExtractElementInst(ExtractElementInst &Inst) { + auto *Ptr = Inst.getVectorOperand(); + auto *Val = &Inst; + addLoadEdge(Ptr, Val); + } + + void visitInsertElementInst(InsertElementInst &Inst) { + auto *Vec = Inst.getOperand(0); + auto *Val = Inst.getOperand(1); + addAssignEdge(Vec, &Inst); + addStoreEdge(Val, &Inst); + } + + void visitLandingPadInst(LandingPadInst &Inst) { + // Exceptions come from "nowhere", from our analysis' perspective. + // So we place the instruction its own group, noting that said group may + // alias externals + if (Inst.getType()->isPointerTy()) + addNode(&Inst, getAttrUnknown()); + } + + void visitInsertValueInst(InsertValueInst &Inst) { + auto *Agg = Inst.getOperand(0); + auto *Val = Inst.getOperand(1); + addAssignEdge(Agg, &Inst); + addStoreEdge(Val, &Inst); + } + + void visitExtractValueInst(ExtractValueInst &Inst) { + auto *Ptr = Inst.getAggregateOperand(); + addLoadEdge(Ptr, &Inst); + } + + void visitShuffleVectorInst(ShuffleVectorInst &Inst) { + auto *From1 = Inst.getOperand(0); + auto *From2 = Inst.getOperand(1); + addAssignEdge(From1, &Inst); + addAssignEdge(From2, &Inst); + } + + void visitConstantExpr(ConstantExpr *CE) { + switch (CE->getOpcode()) { + case Instruction::GetElementPtr: { + auto GEPOp = cast(CE); + visitGEP(*GEPOp); + break; + } + + case Instruction::PtrToInt: { + addNode(CE->getOperand(0), getAttrEscaped()); + break; + } + + case Instruction::IntToPtr: { + addNode(CE, getAttrUnknown()); + break; + } + + case Instruction::BitCast: + case Instruction::AddrSpaceCast: + case Instruction::Trunc: + case Instruction::ZExt: + case Instruction::SExt: + case Instruction::FPExt: + case Instruction::FPTrunc: + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPToUI: + case Instruction::FPToSI: { + addAssignEdge(CE->getOperand(0), CE); + break; + } + + case Instruction::Select: { + addAssignEdge(CE->getOperand(1), CE); + addAssignEdge(CE->getOperand(2), CE); + break; + } + + case Instruction::InsertElement: + case Instruction::InsertValue: { + addAssignEdge(CE->getOperand(0), CE); + addStoreEdge(CE->getOperand(1), CE); + break; + } + + case Instruction::ExtractElement: + case Instruction::ExtractValue: { + addLoadEdge(CE->getOperand(0), CE); + break; + } + + case Instruction::Add: + case Instruction::FAdd: + case Instruction::Sub: + case Instruction::FSub: + case Instruction::Mul: + case Instruction::FMul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::FDiv: + case Instruction::URem: + case Instruction::SRem: + case Instruction::FRem: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + case Instruction::ICmp: + case Instruction::FCmp: + case Instruction::ShuffleVector: { + addAssignEdge(CE->getOperand(0), CE); + addAssignEdge(CE->getOperand(1), CE); + break; + } + + case Instruction::FNeg: { + addAssignEdge(CE->getOperand(0), CE); + break; + } + + default: + llvm_unreachable("Unknown instruction type encountered!"); + } + } + }; + + // Helper functions + + // Determines whether or not we an instruction is useless to us (e.g. + // FenceInst) + static bool hasUsefulEdges(Instruction *Inst) { + bool IsNonInvokeRetTerminator = Inst->isTerminator() && + !isa(Inst) && + !isa(Inst); + return !isa(Inst) && !isa(Inst) && + !IsNonInvokeRetTerminator; + } + + void addArgumentToGraph(Argument &Arg) { + if (Arg.getType()->isPointerTy()) { + Graph.addNode(InstantiatedValue{&Arg, 0}, + getGlobalOrArgAttrFromValue(Arg)); + // Pointees of a formal parameter is known to the caller + Graph.addNode(InstantiatedValue{&Arg, 1}, getAttrCaller()); + } + } + + // Given an Instruction, this will add it to the graph, along with any + // Instructions that are potentially only available from said Instruction + // For example, given the following line: + // %0 = load i16* getelementptr ([1 x i16]* @a, 0, 0), align 2 + // addInstructionToGraph would add both the `load` and `getelementptr` + // instructions to the graph appropriately. + void addInstructionToGraph(GetEdgesVisitor &Visitor, Instruction &Inst) { + if (!hasUsefulEdges(&Inst)) + return; + + Visitor.visit(Inst); + } + + // Builds the graph needed for constructing the StratifiedSets for the given + // function + void buildGraphFrom(Function &Fn) { + GetEdgesVisitor Visitor(*this, Fn.getParent()->getDataLayout()); + + for (auto &Bb : Fn.getBasicBlockList()) + for (auto &Inst : Bb.getInstList()) + addInstructionToGraph(Visitor, Inst); + + for (auto &Arg : Fn.args()) + addArgumentToGraph(Arg); + } + +public: + CFLGraphBuilder(CFLAA &Analysis, const TargetLibraryInfo &TLI, Function &Fn) + : Analysis(Analysis), TLI(TLI) { + buildGraphFrom(Fn); + } + + const CFLGraph &getCFLGraph() const { return Graph; } + const SmallVector &getReturnValues() const { + return ReturnedValues; + } +}; + +} // end namespace cflaa +} // end namespace llvm + +#endif // LLVM_LIB_ANALYSIS_CFLGRAPH_H diff --git a/lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.cpp new file mode 100644 index 000000000..1a17153b3 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.cpp @@ -0,0 +1,367 @@ +//===- CFLSteensAliasAnalysis.cpp - Unification-based Alias Analysis ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a CFL-base, summary-based alias analysis algorithm. It +// does not depend on types. The algorithm is a mixture of the one described in +// "Demand-driven alias analysis for C" by Xin Zheng and Radu Rugina, and "Fast +// algorithms for Dyck-CFL-reachability with applications to Alias Analysis" by +// Zhang Q, Lyu M R, Yuan H, and Su Z. -- to summarize the papers, we build a +// graph of the uses of a variable, where each node is a memory location, and +// each edge is an action that happened on that memory location. The "actions" +// can be one of Dereference, Reference, or Assign. The precision of this +// analysis is roughly the same as that of an one level context-sensitive +// Steensgaard's algorithm. +// +// Two variables are considered as aliasing iff you can reach one value's node +// from the other value's node and the language formed by concatenating all of +// the edge labels (actions) conforms to a context-free grammar. +// +// Because this algorithm requires a graph search on each query, we execute the +// algorithm outlined in "Fast algorithms..." (mentioned above) +// in order to transform the graph into sets of variables that may alias in +// ~nlogn time (n = number of variables), which makes queries take constant +// time. +//===----------------------------------------------------------------------===// + +// N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and +// CFLSteensAA is interprocedural. This is *technically* A Bad Thing, because +// FunctionPasses are only allowed to inspect the Function that they're being +// run on. Realistically, this likely isn't a problem until we allow +// FunctionPasses to run concurrently. + +#include "llvm/Analysis/CFLSteensAliasAnalysis.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#include "AliasAnalysisSummary.h" +#include "CFLGraph.h" +#include "StratifiedSets.h" + +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::cflaa; + +#define DEBUG_TYPE "cfl-steens-aa" + +CFLSteensAAResult::CFLSteensAAResult( + std::function GetTLI) + : GetTLI(std::move(GetTLI)) {} +CFLSteensAAResult::CFLSteensAAResult(CFLSteensAAResult &&Arg) + : AAResultBase(std::move(Arg)), GetTLI(std::move(Arg.GetTLI)) {} +CFLSteensAAResult::~CFLSteensAAResult() = default; + +/// Information we have about a function and would like to keep around. +class CFLSteensAAResult::FunctionInfo { + StratifiedSets Sets; + AliasSummary Summary; + +public: + FunctionInfo(Function &Fn, const SmallVectorImpl &RetVals, + StratifiedSets S); + + const StratifiedSets &getStratifiedSets() const { + return Sets; + } + + const AliasSummary &getAliasSummary() const { return Summary; } +}; + +const StratifiedIndex StratifiedLink::SetSentinel = + std::numeric_limits::max(); + +//===----------------------------------------------------------------------===// +// Function declarations that require types defined in the namespace above +//===----------------------------------------------------------------------===// + +/// Determines whether it would be pointless to add the given Value to our sets. +static bool canSkipAddingToSets(Value *Val) { + // Constants can share instances, which may falsely unify multiple + // sets, e.g. in + // store i32* null, i32** %ptr1 + // store i32* null, i32** %ptr2 + // clearly ptr1 and ptr2 should not be unified into the same set, so + // we should filter out the (potentially shared) instance to + // i32* null. + if (isa(Val)) { + // TODO: Because all of these things are constant, we can determine whether + // the data is *actually* mutable at graph building time. This will probably + // come for free/cheap with offset awareness. + bool CanStoreMutableData = isa(Val) || + isa(Val) || + isa(Val); + return !CanStoreMutableData; + } + + return false; +} + +CFLSteensAAResult::FunctionInfo::FunctionInfo( + Function &Fn, const SmallVectorImpl &RetVals, + StratifiedSets S) + : Sets(std::move(S)) { + // Historically, an arbitrary upper-bound of 50 args was selected. We may want + // to remove this if it doesn't really matter in practice. + if (Fn.arg_size() > MaxSupportedArgsInSummary) + return; + + DenseMap InterfaceMap; + + // Our intention here is to record all InterfaceValues that share the same + // StratifiedIndex in RetParamRelations. For each valid InterfaceValue, we + // have its StratifiedIndex scanned here and check if the index is presented + // in InterfaceMap: if it is not, we add the correspondence to the map; + // otherwise, an aliasing relation is found and we add it to + // RetParamRelations. + + auto AddToRetParamRelations = [&](unsigned InterfaceIndex, + StratifiedIndex SetIndex) { + unsigned Level = 0; + while (true) { + InterfaceValue CurrValue{InterfaceIndex, Level}; + + auto Itr = InterfaceMap.find(SetIndex); + if (Itr != InterfaceMap.end()) { + if (CurrValue != Itr->second) + Summary.RetParamRelations.push_back( + ExternalRelation{CurrValue, Itr->second, UnknownOffset}); + break; + } + + auto &Link = Sets.getLink(SetIndex); + InterfaceMap.insert(std::make_pair(SetIndex, CurrValue)); + auto ExternalAttrs = getExternallyVisibleAttrs(Link.Attrs); + if (ExternalAttrs.any()) + Summary.RetParamAttributes.push_back( + ExternalAttribute{CurrValue, ExternalAttrs}); + + if (!Link.hasBelow()) + break; + + ++Level; + SetIndex = Link.Below; + } + }; + + // Populate RetParamRelations for return values + for (auto *RetVal : RetVals) { + assert(RetVal != nullptr); + assert(RetVal->getType()->isPointerTy()); + auto RetInfo = Sets.find(InstantiatedValue{RetVal, 0}); + if (RetInfo.hasValue()) + AddToRetParamRelations(0, RetInfo->Index); + } + + // Populate RetParamRelations for parameters + unsigned I = 0; + for (auto &Param : Fn.args()) { + if (Param.getType()->isPointerTy()) { + auto ParamInfo = Sets.find(InstantiatedValue{&Param, 0}); + if (ParamInfo.hasValue()) + AddToRetParamRelations(I + 1, ParamInfo->Index); + } + ++I; + } +} + +// Builds the graph + StratifiedSets for a function. +CFLSteensAAResult::FunctionInfo CFLSteensAAResult::buildSetsFrom(Function *Fn) { + CFLGraphBuilder GraphBuilder(*this, GetTLI(*Fn), *Fn); + StratifiedSetsBuilder SetBuilder; + + // Add all CFLGraph nodes and all Dereference edges to StratifiedSets + auto &Graph = GraphBuilder.getCFLGraph(); + for (const auto &Mapping : Graph.value_mappings()) { + auto Val = Mapping.first; + if (canSkipAddingToSets(Val)) + continue; + auto &ValueInfo = Mapping.second; + + assert(ValueInfo.getNumLevels() > 0); + SetBuilder.add(InstantiatedValue{Val, 0}); + SetBuilder.noteAttributes(InstantiatedValue{Val, 0}, + ValueInfo.getNodeInfoAtLevel(0).Attr); + for (unsigned I = 0, E = ValueInfo.getNumLevels() - 1; I < E; ++I) { + SetBuilder.add(InstantiatedValue{Val, I + 1}); + SetBuilder.noteAttributes(InstantiatedValue{Val, I + 1}, + ValueInfo.getNodeInfoAtLevel(I + 1).Attr); + SetBuilder.addBelow(InstantiatedValue{Val, I}, + InstantiatedValue{Val, I + 1}); + } + } + + // Add all assign edges to StratifiedSets + for (const auto &Mapping : Graph.value_mappings()) { + auto Val = Mapping.first; + if (canSkipAddingToSets(Val)) + continue; + auto &ValueInfo = Mapping.second; + + for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) { + auto Src = InstantiatedValue{Val, I}; + for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges) + SetBuilder.addWith(Src, Edge.Other); + } + } + + return FunctionInfo(*Fn, GraphBuilder.getReturnValues(), SetBuilder.build()); +} + +void CFLSteensAAResult::scan(Function *Fn) { + auto InsertPair = Cache.insert(std::make_pair(Fn, Optional())); + (void)InsertPair; + assert(InsertPair.second && + "Trying to scan a function that has already been cached"); + + // Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call + // may get evaluated after operator[], potentially triggering a DenseMap + // resize and invalidating the reference returned by operator[] + auto FunInfo = buildSetsFrom(Fn); + Cache[Fn] = std::move(FunInfo); + + Handles.emplace_front(Fn, this); +} + +void CFLSteensAAResult::evict(Function *Fn) { Cache.erase(Fn); } + +/// Ensures that the given function is available in the cache, and returns the +/// entry. +const Optional & +CFLSteensAAResult::ensureCached(Function *Fn) { + auto Iter = Cache.find(Fn); + if (Iter == Cache.end()) { + scan(Fn); + Iter = Cache.find(Fn); + assert(Iter != Cache.end()); + assert(Iter->second.hasValue()); + } + return Iter->second; +} + +const AliasSummary *CFLSteensAAResult::getAliasSummary(Function &Fn) { + auto &FunInfo = ensureCached(&Fn); + if (FunInfo.hasValue()) + return &FunInfo->getAliasSummary(); + else + return nullptr; +} + +AliasResult CFLSteensAAResult::query(const MemoryLocation &LocA, + const MemoryLocation &LocB) { + auto *ValA = const_cast(LocA.Ptr); + auto *ValB = const_cast(LocB.Ptr); + + if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy()) + return AliasResult::NoAlias; + + Function *Fn = nullptr; + Function *MaybeFnA = const_cast(parentFunctionOfValue(ValA)); + Function *MaybeFnB = const_cast(parentFunctionOfValue(ValB)); + if (!MaybeFnA && !MaybeFnB) { + // The only times this is known to happen are when globals + InlineAsm are + // involved + LLVM_DEBUG( + dbgs() + << "CFLSteensAA: could not extract parent function information.\n"); + return AliasResult::MayAlias; + } + + if (MaybeFnA) { + Fn = MaybeFnA; + assert((!MaybeFnB || MaybeFnB == MaybeFnA) && + "Interprocedural queries not supported"); + } else { + Fn = MaybeFnB; + } + + assert(Fn != nullptr); + auto &MaybeInfo = ensureCached(Fn); + assert(MaybeInfo.hasValue()); + + auto &Sets = MaybeInfo->getStratifiedSets(); + auto MaybeA = Sets.find(InstantiatedValue{ValA, 0}); + if (!MaybeA.hasValue()) + return AliasResult::MayAlias; + + auto MaybeB = Sets.find(InstantiatedValue{ValB, 0}); + if (!MaybeB.hasValue()) + return AliasResult::MayAlias; + + auto SetA = *MaybeA; + auto SetB = *MaybeB; + auto AttrsA = Sets.getLink(SetA.Index).Attrs; + auto AttrsB = Sets.getLink(SetB.Index).Attrs; + + // If both values are local (meaning the corresponding set has attribute + // AttrNone or AttrEscaped), then we know that CFLSteensAA fully models them: + // they may-alias each other if and only if they are in the same set. + // If at least one value is non-local (meaning it either is global/argument or + // it comes from unknown sources like integer cast), the situation becomes a + // bit more interesting. We follow three general rules described below: + // - Non-local values may alias each other + // - AttrNone values do not alias any non-local values + // - AttrEscaped do not alias globals/arguments, but they may alias + // AttrUnknown values + if (SetA.Index == SetB.Index) + return AliasResult::MayAlias; + if (AttrsA.none() || AttrsB.none()) + return AliasResult::NoAlias; + if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB)) + return AliasResult::MayAlias; + if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB)) + return AliasResult::MayAlias; + return AliasResult::NoAlias; +} + +AnalysisKey CFLSteensAA::Key; + +CFLSteensAAResult CFLSteensAA::run(Function &F, FunctionAnalysisManager &AM) { + auto GetTLI = [&AM](Function &F) -> const TargetLibraryInfo & { + return AM.getResult(F); + }; + return CFLSteensAAResult(GetTLI); +} + +char CFLSteensAAWrapperPass::ID = 0; +INITIALIZE_PASS(CFLSteensAAWrapperPass, "cfl-steens-aa", + "Unification-Based CFL Alias Analysis", false, true) + +ImmutablePass *llvm::createCFLSteensAAWrapperPass() { + return new CFLSteensAAWrapperPass(); +} + +CFLSteensAAWrapperPass::CFLSteensAAWrapperPass() : ImmutablePass(ID) { + initializeCFLSteensAAWrapperPassPass(*PassRegistry::getPassRegistry()); +} + +void CFLSteensAAWrapperPass::initializePass() { + auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & { + return this->getAnalysis().getTLI(F); + }; + Result.reset(new CFLSteensAAResult(GetTLI)); +} + +void CFLSteensAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); +} diff --git a/lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.h b/lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.h new file mode 100644 index 000000000..b0ab37baa --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.h @@ -0,0 +1,145 @@ +//==- CFLSteensAliasAnalysis.h - Unification-based Alias Analysis -*- C++-*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This is the interface for LLVM's unification-based alias analysis +/// implemented with CFL graph reachability. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H +#define LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CFLAliasAnalysisUtils.h" +#include "llvm/Analysis/MemoryLocation.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Support/Casting.h" + +#include +#include + +namespace llvm { + +class Function; +class TargetLibraryInfo; + +namespace cflaa { + +struct AliasSummary; + +} // end namespace cflaa + +class CFLSteensAAResult : public AAResultBase { + friend AAResultBase; + + class FunctionInfo; + +public: + explicit CFLSteensAAResult( + std::function GetTLI); + CFLSteensAAResult(CFLSteensAAResult &&Arg); + ~CFLSteensAAResult(); + + /// Handle invalidation events from the new pass manager. + /// + /// By definition, this result is stateless and so remains valid. + bool invalidate(Function &, const PreservedAnalyses &, + FunctionAnalysisManager::Invalidator &) { + return false; + } + + /// Inserts the given Function into the cache. + void scan(Function *Fn); + + void evict(Function *Fn); + + /// Ensures that the given function is available in the cache. + /// Returns the appropriate entry from the cache. + const Optional &ensureCached(Function *Fn); + + /// Get the alias summary for the given function + /// Return nullptr if the summary is not found or not available + const cflaa::AliasSummary *getAliasSummary(Function &Fn); + + AliasResult query(const MemoryLocation &LocA, const MemoryLocation &LocB); + + AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB, + AAQueryInfo &AAQI) { + if (LocA.Ptr == LocB.Ptr) + return AliasResult::MustAlias; + + // Comparisons between global variables and other constants should be + // handled by BasicAA. + // CFLSteensAA may report NoAlias when comparing a GlobalValue and + // ConstantExpr, but every query needs to have at least one Value tied to a + // Function, and neither GlobalValues nor ConstantExprs are. + if (isa(LocA.Ptr) && isa(LocB.Ptr)) + return AAResultBase::alias(LocA, LocB, AAQI); + + AliasResult QueryResult = query(LocA, LocB); + if (QueryResult == AliasResult::MayAlias) + return AAResultBase::alias(LocA, LocB, AAQI); + + return QueryResult; + } + +private: + std::function GetTLI; + + /// Cached mapping of Functions to their StratifiedSets. + /// If a function's sets are currently being built, it is marked + /// in the cache as an Optional without a value. This way, if we + /// have any kind of recursion, it is discernable from a function + /// that simply has empty sets. + DenseMap> Cache; + std::forward_list> Handles; + + FunctionInfo buildSetsFrom(Function *F); +}; + +/// Analysis pass providing a never-invalidated alias analysis result. +/// +/// FIXME: We really should refactor CFL to use the analysis more heavily, and +/// in particular to leverage invalidation to trigger re-computation of sets. +class CFLSteensAA : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + + static AnalysisKey Key; + +public: + using Result = CFLSteensAAResult; + + CFLSteensAAResult run(Function &F, FunctionAnalysisManager &AM); +}; + +/// Legacy wrapper pass to provide the CFLSteensAAResult object. +class CFLSteensAAWrapperPass : public ImmutablePass { + std::unique_ptr Result; + +public: + static char ID; + + CFLSteensAAWrapperPass(); + + CFLSteensAAResult &getResult() { return *Result; } + const CFLSteensAAResult &getResult() const { return *Result; } + + void initializePass() override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +// createCFLSteensAAWrapperPass - This pass implements a set-based approach to +// alias analysis. +ImmutablePass *createCFLSteensAAWrapperPass(); + +} // end namespace llvm + +#endif // LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H diff --git a/lib/PhasarLLVM/Pointer/external/llvm/StratifiedSets.h b/lib/PhasarLLVM/Pointer/external/llvm/StratifiedSets.h new file mode 100644 index 000000000..71f07af54 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/llvm/StratifiedSets.h @@ -0,0 +1,598 @@ +//===- StratifiedSets.h - Abstract stratified sets implementation. --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRATIFIEDSETS_H +#define LLVM_ADT_STRATIFIEDSETS_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" + +#include "AliasAnalysisSummary.h" + +#include +#include +#include +#include +#include +#include + +namespace llvm { +namespace cflaa { +/// An index into Stratified Sets. +typedef unsigned StratifiedIndex; +/// NOTE: ^ This can't be a short -- bootstrapping clang has a case where +/// ~1M sets exist. + +// Container of information related to a value in a StratifiedSet. +struct StratifiedInfo { + StratifiedIndex Index; + /// For field sensitivity, etc. we can tack fields on here. +}; + +/// A "link" between two StratifiedSets. +struct StratifiedLink { + /// This is a value used to signify "does not exist" where the + /// StratifiedIndex type is used. + /// + /// This is used instead of Optional because + /// Optional would eat up a considerable amount of extra + /// memory, after struct padding/alignment is taken into account. + static const StratifiedIndex SetSentinel; + + /// The index for the set "above" current + StratifiedIndex Above; + + /// The link for the set "below" current + StratifiedIndex Below; + + /// Attributes for these StratifiedSets. + AliasAttrs Attrs; + + StratifiedLink() : Above(SetSentinel), Below(SetSentinel) {} + + bool hasBelow() const { return Below != SetSentinel; } + bool hasAbove() const { return Above != SetSentinel; } + + void clearBelow() { Below = SetSentinel; } + void clearAbove() { Above = SetSentinel; } +}; + +/// These are stratified sets, as described in "Fast algorithms for +/// Dyck-CFL-reachability with applications to Alias Analysis" by Zhang Q, Lyu M +/// R, Yuan H, and Su Z. -- in short, this is meant to represent different sets +/// of Value*s. If two Value*s are in the same set, or if both sets have +/// overlapping attributes, then the Value*s are said to alias. +/// +/// Sets may be related by position, meaning that one set may be considered as +/// above or below another. In CFL Alias Analysis, this gives us an indication +/// of how two variables are related; if the set of variable A is below a set +/// containing variable B, then at some point, a variable that has interacted +/// with B (or B itself) was either used in order to extract the variable A, or +/// was used as storage of variable A. +/// +/// Sets may also have attributes (as noted above). These attributes are +/// generally used for noting whether a variable in the set has interacted with +/// a variable whose origins we don't quite know (i.e. globals/arguments), or if +/// the variable may have had operations performed on it (modified in a function +/// call). All attributes that exist in a set A must exist in all sets marked as +/// below set A. +template class StratifiedSets { +public: + StratifiedSets() = default; + StratifiedSets(StratifiedSets &&) = default; + StratifiedSets &operator=(StratifiedSets &&) = default; + + StratifiedSets(DenseMap Map, + std::vector Links) + : Values(std::move(Map)), Links(std::move(Links)) {} + + Optional find(const T &Elem) const { + auto Iter = Values.find(Elem); + if (Iter == Values.end()) + return None; + return Iter->second; + } + + const StratifiedLink &getLink(StratifiedIndex Index) const { + assert(inbounds(Index)); + return Links[Index]; + } + +private: + DenseMap Values; + std::vector Links; + + bool inbounds(StratifiedIndex Idx) const { return Idx < Links.size(); } +}; + +/// Generic Builder class that produces StratifiedSets instances. +/// +/// The goal of this builder is to efficiently produce correct StratifiedSets +/// instances. To this end, we use a few tricks: +/// > Set chains (A method for linking sets together) +/// > Set remaps (A method for marking a set as an alias [irony?] of another) +/// +/// ==== Set chains ==== +/// This builder has a notion of some value A being above, below, or with some +/// other value B: +/// > The `A above B` relationship implies that there is a reference edge +/// going from A to B. Namely, it notes that A can store anything in B's set. +/// > The `A below B` relationship is the opposite of `A above B`. It implies +/// that there's a dereference edge going from A to B. +/// > The `A with B` relationship states that there's an assignment edge going +/// from A to B, and that A and B should be treated as equals. +/// +/// As an example, take the following code snippet: +/// +/// %a = alloca i32, align 4 +/// %ap = alloca i32*, align 8 +/// %app = alloca i32**, align 8 +/// store %a, %ap +/// store %ap, %app +/// %aw = getelementptr %ap, i32 0 +/// +/// Given this, the following relations exist: +/// - %a below %ap & %ap above %a +/// - %ap below %app & %app above %ap +/// - %aw with %ap & %ap with %aw +/// +/// These relations produce the following sets: +/// [{%a}, {%ap, %aw}, {%app}] +/// +/// ...Which state that the only MayAlias relationship in the above program is +/// between %ap and %aw. +/// +/// Because LLVM allows arbitrary casts, code like the following needs to be +/// supported: +/// %ip = alloca i64, align 8 +/// %ipp = alloca i64*, align 8 +/// %i = bitcast i64** ipp to i64 +/// store i64* %ip, i64** %ipp +/// store i64 %i, i64* %ip +/// +/// Which, because %ipp ends up *both* above and below %ip, is fun. +/// +/// This is solved by merging %i and %ipp into a single set (...which is the +/// only way to solve this, since their bit patterns are equivalent). Any sets +/// that ended up in between %i and %ipp at the time of merging (in this case, +/// the set containing %ip) also get conservatively merged into the set of %i +/// and %ipp. In short, the resulting StratifiedSet from the above code would be +/// {%ip, %ipp, %i}. +/// +/// ==== Set remaps ==== +/// More of an implementation detail than anything -- when merging sets, we need +/// to update the numbers of all of the elements mapped to those sets. Rather +/// than doing this at each merge, we note in the BuilderLink structure that a +/// remap has occurred, and use this information so we can defer renumbering set +/// elements until build time. +template class StratifiedSetsBuilder { + /// Represents a Stratified Set, with information about the Stratified + /// Set above it, the set below it, and whether the current set has been + /// remapped to another. + struct BuilderLink { + const StratifiedIndex Number; + + BuilderLink(StratifiedIndex N) : Number(N) { + Remap = StratifiedLink::SetSentinel; + } + + bool hasAbove() const { + assert(!isRemapped()); + return Link.hasAbove(); + } + + bool hasBelow() const { + assert(!isRemapped()); + return Link.hasBelow(); + } + + void setBelow(StratifiedIndex I) { + assert(!isRemapped()); + Link.Below = I; + } + + void setAbove(StratifiedIndex I) { + assert(!isRemapped()); + Link.Above = I; + } + + void clearBelow() { + assert(!isRemapped()); + Link.clearBelow(); + } + + void clearAbove() { + assert(!isRemapped()); + Link.clearAbove(); + } + + StratifiedIndex getBelow() const { + assert(!isRemapped()); + assert(hasBelow()); + return Link.Below; + } + + StratifiedIndex getAbove() const { + assert(!isRemapped()); + assert(hasAbove()); + return Link.Above; + } + + AliasAttrs getAttrs() { + assert(!isRemapped()); + return Link.Attrs; + } + + void setAttrs(AliasAttrs Other) { + assert(!isRemapped()); + Link.Attrs |= Other; + } + + bool isRemapped() const { return Remap != StratifiedLink::SetSentinel; } + + /// For initial remapping to another set + void remapTo(StratifiedIndex Other) { + assert(!isRemapped()); + Remap = Other; + } + + StratifiedIndex getRemapIndex() const { + assert(isRemapped()); + return Remap; + } + + /// Should only be called when we're already remapped. + void updateRemap(StratifiedIndex Other) { + assert(isRemapped()); + Remap = Other; + } + + /// Prefer the above functions to calling things directly on what's returned + /// from this -- they guard against unexpected calls when the current + /// BuilderLink is remapped. + const StratifiedLink &getLink() const { return Link; } + + private: + StratifiedLink Link; + StratifiedIndex Remap; + }; + + /// This function performs all of the set unioning/value renumbering + /// that we've been putting off, and generates a vector that + /// may be placed in a StratifiedSets instance. + void finalizeSets(std::vector &StratLinks) { + DenseMap Remaps; + for (auto &Link : Links) { + if (Link.isRemapped()) + continue; + + StratifiedIndex Number = StratLinks.size(); + Remaps.insert(std::make_pair(Link.Number, Number)); + StratLinks.push_back(Link.getLink()); + } + + for (auto &Link : StratLinks) { + if (Link.hasAbove()) { + auto &Above = linksAt(Link.Above); + auto Iter = Remaps.find(Above.Number); + assert(Iter != Remaps.end()); + Link.Above = Iter->second; + } + + if (Link.hasBelow()) { + auto &Below = linksAt(Link.Below); + auto Iter = Remaps.find(Below.Number); + assert(Iter != Remaps.end()); + Link.Below = Iter->second; + } + } + + for (auto &Pair : Values) { + auto &Info = Pair.second; + auto &Link = linksAt(Info.Index); + auto Iter = Remaps.find(Link.Number); + assert(Iter != Remaps.end()); + Info.Index = Iter->second; + } + } + + /// There's a guarantee in StratifiedLink where all bits set in a + /// Link.externals will be set in all Link.externals "below" it. + static void propagateAttrs(std::vector &Links) { + const auto getHighestParentAbove = [&Links](StratifiedIndex Idx) { + const auto *Link = &Links[Idx]; + while (Link->hasAbove()) { + Idx = Link->Above; + Link = &Links[Idx]; + } + return Idx; + }; + + SmallSet Visited; + for (unsigned I = 0, E = Links.size(); I < E; ++I) { + auto CurrentIndex = getHighestParentAbove(I); + if (!Visited.insert(CurrentIndex).second) + continue; + + while (Links[CurrentIndex].hasBelow()) { + auto &CurrentBits = Links[CurrentIndex].Attrs; + auto NextIndex = Links[CurrentIndex].Below; + auto &NextBits = Links[NextIndex].Attrs; + NextBits |= CurrentBits; + CurrentIndex = NextIndex; + } + } + } + +public: + /// Builds a StratifiedSet from the information we've been given since either + /// construction or the prior build() call. + StratifiedSets build() { + std::vector StratLinks; + finalizeSets(StratLinks); + propagateAttrs(StratLinks); + Links.clear(); + return StratifiedSets(std::move(Values), std::move(StratLinks)); + } + + bool has(const T &Elem) const { return get(Elem).hasValue(); } + + bool add(const T &Main) { + if (get(Main).hasValue()) + return false; + + auto NewIndex = getNewUnlinkedIndex(); + return addAtMerging(Main, NewIndex); + } + + /// Restructures the stratified sets as necessary to make "ToAdd" in a + /// set above "Main". There are some cases where this is not possible (see + /// above), so we merge them such that ToAdd and Main are in the same set. + bool addAbove(const T &Main, const T &ToAdd) { + assert(has(Main)); + auto Index = *indexOf(Main); + if (!linksAt(Index).hasAbove()) + addLinkAbove(Index); + + auto Above = linksAt(Index).getAbove(); + return addAtMerging(ToAdd, Above); + } + + /// Restructures the stratified sets as necessary to make "ToAdd" in a + /// set below "Main". There are some cases where this is not possible (see + /// above), so we merge them such that ToAdd and Main are in the same set. + bool addBelow(const T &Main, const T &ToAdd) { + assert(has(Main)); + auto Index = *indexOf(Main); + if (!linksAt(Index).hasBelow()) + addLinkBelow(Index); + + auto Below = linksAt(Index).getBelow(); + return addAtMerging(ToAdd, Below); + } + + bool addWith(const T &Main, const T &ToAdd) { + assert(has(Main)); + auto MainIndex = *indexOf(Main); + return addAtMerging(ToAdd, MainIndex); + } + + void noteAttributes(const T &Main, AliasAttrs NewAttrs) { + assert(has(Main)); + auto *Info = *get(Main); + auto &Link = linksAt(Info->Index); + Link.setAttrs(NewAttrs); + } + +private: + DenseMap Values; + std::vector Links; + + /// Adds the given element at the given index, merging sets if necessary. + bool addAtMerging(const T &ToAdd, StratifiedIndex Index) { + StratifiedInfo Info = {Index}; + auto Pair = Values.insert(std::make_pair(ToAdd, Info)); + if (Pair.second) + return true; + + auto &Iter = Pair.first; + auto &IterSet = linksAt(Iter->second.Index); + auto &ReqSet = linksAt(Index); + + // Failed to add where we wanted to. Merge the sets. + if (&IterSet != &ReqSet) + merge(IterSet.Number, ReqSet.Number); + + return false; + } + + /// Gets the BuilderLink at the given index, taking set remapping into + /// account. + BuilderLink &linksAt(StratifiedIndex Index) { + auto *Start = &Links[Index]; + if (!Start->isRemapped()) + return *Start; + + auto *Current = Start; + while (Current->isRemapped()) + Current = &Links[Current->getRemapIndex()]; + + auto NewRemap = Current->Number; + + // Run through everything that has yet to be updated, and update them to + // remap to NewRemap + Current = Start; + while (Current->isRemapped()) { + auto *Next = &Links[Current->getRemapIndex()]; + Current->updateRemap(NewRemap); + Current = Next; + } + + return *Current; + } + + /// Merges two sets into one another. Assumes that these sets are not + /// already one in the same. + void merge(StratifiedIndex Idx1, StratifiedIndex Idx2) { + assert(inbounds(Idx1) && inbounds(Idx2)); + assert(&linksAt(Idx1) != &linksAt(Idx2) && + "Merging a set into itself is not allowed"); + + // CASE 1: If the set at `Idx1` is above or below `Idx2`, we need to merge + // both the + // given sets, and all sets between them, into one. + if (tryMergeUpwards(Idx1, Idx2)) + return; + + if (tryMergeUpwards(Idx2, Idx1)) + return; + + // CASE 2: The set at `Idx1` is not in the same chain as the set at `Idx2`. + // We therefore need to merge the two chains together. + mergeDirect(Idx1, Idx2); + } + + /// Merges two sets assuming that the set at `Idx1` is unreachable from + /// traversing above or below the set at `Idx2`. + void mergeDirect(StratifiedIndex Idx1, StratifiedIndex Idx2) { + assert(inbounds(Idx1) && inbounds(Idx2)); + + auto *LinksInto = &linksAt(Idx1); + auto *LinksFrom = &linksAt(Idx2); + // Merging everything above LinksInto then proceeding to merge everything + // below LinksInto becomes problematic, so we go as far "up" as possible! + while (LinksInto->hasAbove() && LinksFrom->hasAbove()) { + LinksInto = &linksAt(LinksInto->getAbove()); + LinksFrom = &linksAt(LinksFrom->getAbove()); + } + + if (LinksFrom->hasAbove()) { + LinksInto->setAbove(LinksFrom->getAbove()); + auto &NewAbove = linksAt(LinksInto->getAbove()); + NewAbove.setBelow(LinksInto->Number); + } + + // Merging strategy: + // > If neither has links below, stop. + // > If only `LinksInto` has links below, stop. + // > If only `LinksFrom` has links below, reset `LinksInto.Below` to + // match `LinksFrom.Below` + // > If both have links above, deal with those next. + while (LinksInto->hasBelow() && LinksFrom->hasBelow()) { + auto FromAttrs = LinksFrom->getAttrs(); + LinksInto->setAttrs(FromAttrs); + + // Remap needs to happen after getBelow(), but before + // assignment of LinksFrom + auto *NewLinksFrom = &linksAt(LinksFrom->getBelow()); + LinksFrom->remapTo(LinksInto->Number); + LinksFrom = NewLinksFrom; + LinksInto = &linksAt(LinksInto->getBelow()); + } + + if (LinksFrom->hasBelow()) { + LinksInto->setBelow(LinksFrom->getBelow()); + auto &NewBelow = linksAt(LinksInto->getBelow()); + NewBelow.setAbove(LinksInto->Number); + } + + LinksInto->setAttrs(LinksFrom->getAttrs()); + LinksFrom->remapTo(LinksInto->Number); + } + + /// Checks to see if lowerIndex is at a level lower than upperIndex. If so, it + /// will merge lowerIndex with upperIndex (and all of the sets between) and + /// return true. Otherwise, it will return false. + bool tryMergeUpwards(StratifiedIndex LowerIndex, StratifiedIndex UpperIndex) { + assert(inbounds(LowerIndex) && inbounds(UpperIndex)); + auto *Lower = &linksAt(LowerIndex); + auto *Upper = &linksAt(UpperIndex); + if (Lower == Upper) + return true; + + SmallVector Found; + auto *Current = Lower; + auto Attrs = Current->getAttrs(); + while (Current->hasAbove() && Current != Upper) { + Found.push_back(Current); + Attrs |= Current->getAttrs(); + Current = &linksAt(Current->getAbove()); + } + + if (Current != Upper) + return false; + + Upper->setAttrs(Attrs); + + if (Lower->hasBelow()) { + auto NewBelowIndex = Lower->getBelow(); + Upper->setBelow(NewBelowIndex); + auto &NewBelow = linksAt(NewBelowIndex); + NewBelow.setAbove(UpperIndex); + } else { + Upper->clearBelow(); + } + + for (const auto &Ptr : Found) + Ptr->remapTo(Upper->Number); + + return true; + } + + Optional get(const T &Val) const { + auto Result = Values.find(Val); + if (Result == Values.end()) + return None; + return &Result->second; + } + + Optional get(const T &Val) { + auto Result = Values.find(Val); + if (Result == Values.end()) + return None; + return &Result->second; + } + + Optional indexOf(const T &Val) { + auto MaybeVal = get(Val); + if (!MaybeVal.hasValue()) + return None; + auto *Info = *MaybeVal; + auto &Link = linksAt(Info->Index); + return Link.Number; + } + + StratifiedIndex addLinkBelow(StratifiedIndex Set) { + auto At = addLinks(); + Links[Set].setBelow(At); + Links[At].setAbove(Set); + return At; + } + + StratifiedIndex addLinkAbove(StratifiedIndex Set) { + auto At = addLinks(); + Links[At].setBelow(Set); + Links[Set].setAbove(At); + return At; + } + + StratifiedIndex getNewUnlinkedIndex() { return addLinks(); } + + StratifiedIndex addLinks() { + auto Link = Links.size(); + Links.push_back(BuilderLink(Link)); + return Link; + } + + bool inbounds(StratifiedIndex N) const { return N < Links.size(); } +}; +} // namespace cflaa +} // namespace llvm +#endif // LLVM_ADT_STRATIFIEDSETS_H From 61b3a30cfad86a19a0c104a983b23cb5aa4167f7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Tue, 12 Dec 2023 19:35:25 +0100 Subject: [PATCH 51/59] Make the old way of configuring phasar work again (#694) --- Config.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config.cmake.in b/Config.cmake.in index 8093b5f78..87b54bd0b 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -56,7 +56,7 @@ foreach(component ${phasar_FIND_COMPONENTS}) list(APPEND PHASAR_NEEDED_LIBS phasar::${component}) endforeach() -if (phasar_FOUND) +if (NOT DEFINED phasar_FOUND OR phasar_FOUND EQUAL TRUE) foreach(component ${phasar_FIND_COMPONENTS}) # For backwards compatibility -- will be removed with next release add_library(phasar::phasar_${component} ALIAS phasar::${component}) From 7aae84dcffbfcaeac3a91471801fccf30eb19635 Mon Sep 17 00:00:00 2001 From: Alexander Lochmann Date: Thu, 1 Feb 2024 11:09:42 +0100 Subject: [PATCH 52/59] Allow LLVM beeing installed in a custom path (#690) Currently, the custom build of LLVM must be located in /usr/local/llvm-14. If not, CMake will either fail finding LLVMConfig.cmake or use a different LLVM installation, e.g., the system-wide one. This will, for example, result in an include path different from the custom LLVM installation. This commit extends 'bootstrap.sh' to set 'LLVM_ROOT' to the custom installation. Moreover, it allows the user to select an arbitrary location for LLVM. (Fixed #689) Co-authored-by: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> --- bootstrap.sh | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 2caf67eea..bb641b5da 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -5,8 +5,8 @@ set -eo pipefail source ./utils/safeCommandsSet.sh readonly PHASAR_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -readonly PHASAR_INSTALL_DIR="/usr/local/phasar" -readonly LLVM_INSTALL_DIR="/usr/local/llvm-14" +PHASAR_INSTALL_DIR="/usr/local/phasar" +LLVM_INSTALL_DIR="/usr/local/llvm-14" NUM_THREADS=$(nproc) LLVM_RELEASE=llvmorg-14.0.6 @@ -26,7 +26,8 @@ function usage { echo -e "\t-DBOOST_DIR=\t\t- The directory where boost should be installed (optional)" echo -e "\t-DBOOST_VERSION=\t- The desired boost version to install (optional)" echo -e "\t-DCMAKE_BUILD_TYPE=\t- The build mode for building PhASAR. One of {Debug, RelWithDebInfo, Release} (default is Release)" - echo -e "\t-DPHASAR_INSTALL_DIR=\t- The folder where to install PhASAR if --install is specified (default is /usr/local/phasar)" + echo -e "\t-DPHASAR_INSTALL_DIR=\t- The folder where to install PhASAR if --install is specified (default is ${PHASAR_INSTALL_DIR})" + echo -e "\t-DLLVM_INSTALL_DIR=\t- The folder where to install LLVM if --install is specified (default is ${LLVM_INSTALL_DIR})" } # Parsing command-line-parameters @@ -82,6 +83,15 @@ case $key in PHASAR_INSTALL_DIR="${key#*=}" shift # past argument=value ;; + -DLLVM_INSTALL_DIR) + LLVM_INSTALL_DIR="$2" + shift # past argument + shift # past value + ;; + -DLLVM_INSTALL_DIR=*) + LLVM_INSTALL_DIR="${key#*=}" + shift # past argument=value + ;; -h|--help) usage exit 0 @@ -157,6 +167,9 @@ tmp_dir=$(mktemp -d "llvm-build.XXXXXXXX" --tmpdir) rm -rf "${tmp_dir}" echo "dependencies successfully installed" +# *Always* set the LLVM root to ensure the Phasar script uses the proper toolchain +LLVM_PARAMS=-DLLVM_ROOT="${LLVM_INSTALL_DIR}" + echo "Updating the submodules..." git submodule update --init echo "Submodules successfully updated" @@ -169,7 +182,7 @@ export CXX=${LLVM_INSTALL_DIR}/bin/clang++ mkdir -p "${PHASAR_DIR}"/build safe_cd "${PHASAR_DIR}"/build -cmake -G Ninja -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" "${BOOST_PARAMS}" -DPHASAR_BUILD_UNITTESTS="${DO_UNIT_TEST}" "${PHASAR_DIR}" +cmake -G Ninja -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" "${BOOST_PARAMS}" -DPHASAR_BUILD_UNITTESTS="${DO_UNIT_TEST}" "${LLVM_PARAMS}" "${PHASAR_DIR}" cmake --build . -j "${NUM_THREADS}" echo "phasar successfully built" From cd302d8d6e810e0cb9d3ce80ef6efc858bcafc0f Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 1 Feb 2024 13:36:45 +0100 Subject: [PATCH 53/59] Misc Fixes (#698) * Fix InitialSeeds Join values correctly when reaching a seed location from a different path * Fix MaybeUniquePtr --------- --- .../DataFlow/IfdsIde/Solver/IDESolver.h | 5 +- .../PhasarLLVM/ControlFlow/LLVMBasedICFG.h | 1 + .../phasar/PhasarLLVM/DB/LLVMProjectIRDB.h | 2 +- include/phasar/Utils/DFAMinimizer.h | 2 - include/phasar/Utils/MaybeUniquePtr.h | 53 ++++++++++++------- .../TaintConfig/LLVMTaintConfig.cpp | 1 - unittests/Utils/CMakeLists.txt | 3 ++ unittests/Utils/CompilationTests.cpp | 14 +++++ 8 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 unittests/Utils/CompilationTests.cpp diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index 36b782b4c..eb2c323c3 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -725,7 +725,10 @@ class IDESolver << ", value: " << LToString(Value)); // initialize the initial seeds with the top element as we have no // information at the beginning of the value computation problem - setVal(StartPoint, Fact, Value); + l_t OldVal = val(StartPoint, Fact); + auto NewVal = IDEProblem.join(Value, std::move(OldVal)); + setVal(StartPoint, Fact, std::move(NewVal)); + std::pair SuperGraphNode(StartPoint, Fact); valuePropagationTask(std::move(SuperGraphNode)); } diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index f1af71970..12bc78493 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -96,6 +96,7 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { const nlohmann::json &SerializedCG, LLVMTypeHierarchy *TH = nullptr); + // Deleter of LLVMTypeHierarchy may be unknown here... ~LLVMBasedICFG(); LLVMBasedICFG(const LLVMBasedICFG &) = delete; diff --git a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h index 590ffafa6..47df476ad 100644 --- a/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h +++ b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h @@ -109,7 +109,7 @@ class LLVMProjectIRDB : public ProjectIRDBBase { [[nodiscard]] m_t getModuleImpl() const noexcept { return Mod.get(); } [[nodiscard]] bool debugInfoAvailableImpl() const; [[nodiscard]] FunctionRange getAllFunctionsImpl() const { - return llvm::map_range(Mod->functions(), + return llvm::map_range(ProjectIRDBBase::getModule()->functions(), Ref2PointerConverter{}); } [[nodiscard]] f_t getFunctionImpl(llvm::StringRef FunctionName) const { diff --git a/include/phasar/Utils/DFAMinimizer.h b/include/phasar/Utils/DFAMinimizer.h index 00a20f0db..9c08a3b7c 100644 --- a/include/phasar/Utils/DFAMinimizer.h +++ b/include/phasar/Utils/DFAMinimizer.h @@ -110,8 +110,6 @@ template } } - size_t Idx = 0; - llvm::IntEqClasses Equiv(traits_t::size(G)); auto isEquivalent = [&Equiv](edge_t LHS, edge_t RHS) { diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index d7cc7db02..fe086fc85 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -11,6 +11,7 @@ #define PHASAR_UTILS_MAYBEUNIQUEPTR_H_ #include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/PointerLikeTypeTraits.h" #include #include @@ -39,8 +40,12 @@ template class MaybeUniquePtrBase { }; template class MaybeUniquePtrBase { + struct PointerTraits : llvm::PointerLikeTypeTraits { + static constexpr int NumLowBitsAvailable = 1; + }; + protected: - llvm::PointerIntPair Data{}; + llvm::PointerIntPair Data{}; constexpr MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} constexpr MaybeUniquePtrBase() noexcept = default; @@ -61,12 +66,15 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { constexpr MaybeUniquePtr() noexcept = default; constexpr MaybeUniquePtr(T *Pointer, bool Owns = false) noexcept - : detail::MaybeUniquePtrBase(Pointer, Owns) {} + : detail::MaybeUniquePtrBase(Pointer, + Owns && Pointer) {} constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} - template + template && + std::is_convertible_v>> constexpr MaybeUniquePtr(std::unique_ptr &&Owner) noexcept : MaybeUniquePtr(Owner.release(), true) {} @@ -92,16 +100,20 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { if (owns()) { delete Data.getPointer(); } - Data = {Owner.release(), true}; + auto *Ptr = Owner.release(); + Data = {Ptr, Ptr != nullptr}; return *this; } - template + template && + std::is_convertible_v>> constexpr MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { if (owns()) { delete Data.getPointer(); } - Data = {Owner.release(), true}; + auto *Ptr = Owner.release(); + Data = {Ptr, Ptr != nullptr}; return *this; } @@ -118,24 +130,16 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { } } - [[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 { - assert(get() != nullptr); - return *get(); - } - [[nodiscard]] constexpr const T &operator*() const noexcept { + [[nodiscard]] constexpr T &operator*() const noexcept { assert(get() != nullptr); return *get(); } - T *release() noexcept { + constexpr T *release() noexcept { Data.setInt(false); return Data.getPointer(); } @@ -147,8 +151,19 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase { Data = {}; } + template + constexpr void reset(MaybeUniquePtr &&Other) noexcept { + *this = std::move(Other); + } + + template + constexpr void reset(std::unique_ptr &&Other) noexcept { + *this = std::move(Other); + } + [[nodiscard]] constexpr bool owns() const noexcept { - return Data.getInt() && Data.getPointer(); + assert(Data.getPointer() || !Data.getInt()); + return Data.getInt(); } constexpr friend bool operator==(const MaybeUniquePtr &LHS, diff --git a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp index a448f43f1..e814aba76 100644 --- a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp +++ b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp @@ -130,7 +130,6 @@ LLVMTaintConfig::LLVMTaintConfig(const psr::LLVMProjectIRDB &Code, std::unordered_map StructConfigMap; // read all struct types from config - size_t Counter = 0; for (const auto &VarDesc : Config.Variables) { llvm::DebugInfoFinder DIF; const auto *M = Code.getModule(); diff --git a/unittests/Utils/CMakeLists.txt b/unittests/Utils/CMakeLists.txt index fea979d61..62831a3c1 100644 --- a/unittests/Utils/CMakeLists.txt +++ b/unittests/Utils/CMakeLists.txt @@ -1,4 +1,5 @@ set(UtilsSources + CompilationTests.cpp BitVectorSetTest.cpp EquivalenceClassMapTest.cpp IOTest.cpp @@ -16,3 +17,5 @@ endif() foreach(TEST_SRC ${UtilsSources}) add_phasar_unittest(${TEST_SRC}) endforeach(TEST_SRC) + +target_compile_options(CompilationTests PRIVATE -Wno-delete-incomplete) diff --git a/unittests/Utils/CompilationTests.cpp b/unittests/Utils/CompilationTests.cpp new file mode 100644 index 000000000..40b21b58a --- /dev/null +++ b/unittests/Utils/CompilationTests.cpp @@ -0,0 +1,14 @@ + +#include "phasar/Utils/MaybeUniquePtr.h" + +#include + +struct IncompleteType; + +using MUP = psr::MaybeUniquePtr; +MUP maybeUniquePtrSupportsIncompleteTypes( + std::unique_ptr &&UP) { + return std::move(UP); +} + +int main() {} From 8a786aca8263ee741a88f62cc4b5b2575e394446 Mon Sep 17 00:00:00 2001 From: Sriteja Kummita <38907381+sritejakv@users.noreply.github.com> Date: Sun, 25 Feb 2024 15:18:07 +0100 Subject: [PATCH 54/59] Implementing On-The-Fly Reporting (#701) * Analysis Printer (#17) * Initial Commit * AnalysisPrinter Second commit * Initial Commit * Integrate Printer with client Analysis and test * Addressing Review comments * Integrate AnalysisPrinter with all analyses and template class modified * vector emplace_back instead of push_back * Testcase for AnalysisPrinter * GroundTruth derived class initial commit * AnalysisPrinter Test complete and Test * fixing myphasartool file * Test pre-commit fix * Adding Test cases and fixing PR failure * 1.template params to N,D,L 2.remove AnalysisType param from AnalysisResults 3.rearranging class variables * 1.template params to N,D,L 2.remove AnalysisType param from AnalysisResults 3.rearranging class variables * Null AnalysisPrinter singleton * Adding AnalysisPrinter to IDETabulation Problem * making free (N,D,L)ToString functions * disable copy and move for analysis-printer * Default NullAnalysisPrinter and explicit print methods * removing SetAnalysisPrinter from client analyses and modified Testcase for AnalysisPrinter * Adding superclass for AnalysisPrinter * Addressing review comments and fixing PR build failure * fix: minors * fix: minor (clang-tidy) * fix: review feedback * misc: minor refactoring --------- Co-authored-by: SanthoshMohan Co-authored-by: Sriteja Kummita * OnTheFlyReporting Initial Commit * fix: review feedback * onTheFlyAnalysis makeUniquePtr * OnTheFlyReporting Initial Commit * onTheFlyAnalysis makeUniquePtr * addressing minor error in prev commit * Refactoring Warn Variable and Refactoring lambda flow for AnalysisPrinter * Integrating sourceMgr to AnalysisPrinter * Testcase for OnTheFlyAnalysisPrinting * Testcase for SourceMgrPrinter * MaybeUniquePtr for SourceMgrPrinter * Minor review comments * refactoring the printers * adding TODOs * more TODOs * Refactor AnalysisPrinter part1 * Refactor AnalysisPrinter part2 * dev: update AnalysisPrinterBase, integrate and fix tests * adding warning kind * fix ci * update codeowners for analysis-printer * Refactor SourceManagerPrinter * Minor in OTF Printer Test * fixing review feedback * fix l_t printing * Mandating analysisType to tyestate descriptions --------- Co-authored-by: SanthoshMohan Co-authored-by: Fabian Schiebel --- .clang-tidy | 1 + .github/CODEOWNERS | 6 + .../DataFlow/IfdsIde/IDETabulationProblem.h | 2 +- .../IfdsIde/Problems/IDETypeStateAnalysis.h | 13 +- .../CSTDFILEIOTypeStateDescription.h | 1 + .../OpenSSLEVPKDFCTXDescription.h | 1 + .../OpenSSLEVPKDFDescription.h | 2 + .../OpenSSLSecureHeapDescription.h | 1 + .../OpenSSLSecureMemoryDescription.h | 1 + .../TypeStateDescription.h | 3 + .../PhasarLLVM/Utils/AnalysisPrinterBase.h | 44 ------- .../PhasarLLVM/Utils/DefaultAnalysisPrinter.h | 47 ------- include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h | 11 ++ .../PhasarLLVM/Utils/LLVMSourceManager.h | 36 ++++++ .../PhasarLLVM/Utils/SourceMgrPrinter.h | 71 +++++++++++ include/phasar/Utils/AnalysisPrinterBase.h | 54 ++++++++ include/phasar/Utils/DefaultAnalysisPrinter.h | 73 +++++++++++ .../Utils/NullAnalysisPrinter.h | 13 +- .../phasar/Utils/OnTheFlyAnalysisPrinter.h | 49 ++++++++ .../Problems/IDEExtendedTaintAnalysis.cpp | 13 +- .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 13 +- .../Problems/IFDSUninitializedVariables.cpp | 51 ++++---- .../CSTDFILEIOTypeStateDescription.cpp | 5 + .../OpenSSLEVPKDFCTXDescription.cpp | 5 + .../OpenSSLEVPKDFDescription.cpp | 5 + .../OpenSSLSecureHeapDescription.cpp | 5 + .../OpenSSLSecureMemoryDescription.cpp | 5 + lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp | 118 +++++++++++------- lib/PhasarLLVM/Utils/LLVMSourceManager.cpp | 54 ++++++++ lib/PhasarLLVM/Utils/SourceMgrPrinter.cpp | 16 +++ .../ControlFlow/LLVMBasedICFGExportTest.cpp | 29 +++-- unittests/Utils/AnalysisPrinterTest.cpp | 20 +-- unittests/Utils/CMakeLists.txt | 2 + .../Utils/OnTheFlyAnalysisPrinterTest.cpp | 105 ++++++++++++++++ unittests/Utils/SourceMgrPrinterTest.cpp | 95 ++++++++++++++ 35 files changed, 757 insertions(+), 213 deletions(-) delete mode 100644 include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h delete mode 100644 include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h create mode 100644 include/phasar/PhasarLLVM/Utils/LLVMSourceManager.h create mode 100644 include/phasar/PhasarLLVM/Utils/SourceMgrPrinter.h create mode 100644 include/phasar/Utils/AnalysisPrinterBase.h create mode 100644 include/phasar/Utils/DefaultAnalysisPrinter.h rename include/phasar/{PhasarLLVM => }/Utils/NullAnalysisPrinter.h (58%) create mode 100644 include/phasar/Utils/OnTheFlyAnalysisPrinter.h create mode 100644 lib/PhasarLLVM/Utils/LLVMSourceManager.cpp create mode 100644 lib/PhasarLLVM/Utils/SourceMgrPrinter.cpp create mode 100644 unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp create mode 100644 unittests/Utils/SourceMgrPrinterTest.cpp diff --git a/.clang-tidy b/.clang-tidy index 8447efed9..54f04105c 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,7 @@ Checks: '-*, misc-*, -misc-non-private-member-variables-in-classes, -misc-no-recursion, + -misc-use-anonymous-namespace, readability-*, -readability-function-cognitive-complexity, -readability-else-after*, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bfd339c16..3e7412921 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,3 +26,9 @@ Dockerfile @janniclas /.docker/ @janniclas /include/phasar/Utils/Logger.h @MMory +/include/phasar/Utils/AnalysisPrinterBase.h @sritejakv +/include/phasar/Utils/DefaultAnalysisPrinter.h @sritejakv +/include/phasar/Utils/NullAnalysisPrinter.h @sritejakv +/include/phasar/Utils/OnTheFlyAnalysisPrinter.h @sritejakv +/include/phasar/PhasarLLVM/Utils/SourceMgrPrinter.h @sritejakv +/lib/PhasarLLVM/Utils/SourceMgrPrinter.cpp @sritejakv diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index 35bd80ae5..d3c75c1ae 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -19,8 +19,8 @@ #include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h" #include "phasar/DataFlow/IfdsIde/InitialSeeds.h" #include "phasar/DataFlow/IfdsIde/SolverResults.h" -#include "phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h" #include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/NullAnalysisPrinter.h" #include "phasar/Utils/Printer.h" #include "phasar/Utils/Soundness.h" diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 19bdd525a..be868e560 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -19,6 +19,7 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" #include "phasar/Utils/ByRef.h" #include "phasar/Utils/JoinLattice.h" #include "phasar/Utils/Logger.h" @@ -529,10 +530,9 @@ class IDETypeStateAnalysis if (const auto *Alloca = llvm::dyn_cast(Res.first)) { if (Res.second == TSD->error()) { - Warning> - Warn(&I, Res.first, TSD->error()); // ERROR STATE DETECTED - this->Printer->onResult(Warn); + this->Printer->onResult(&I, Res.first, TSD->error(), + TSD->analysisType()); } } } @@ -541,10 +541,9 @@ class IDETypeStateAnalysis if (const auto *Alloca = llvm::dyn_cast(Res.first)) { if (Res.second == TSD->error()) { - Warning> - Warn(&I, Res.first, TSD->error()); // ERROR STATE DETECTED - this->Printer->onResult(Warn); + this->Printer->onResult(&I, Res.first, TSD->error(), + TSD->analysisType()); } } } @@ -553,7 +552,7 @@ class IDETypeStateAnalysis } } - this->Printer->onFinalize(OS); + this->Printer->onFinalize(); } private: diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h index 1f28206d1..c7cad7975 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h @@ -72,6 +72,7 @@ class CSTDFILEIOTypeStateDescription [[nodiscard]] TypeStateDescription::State uninit() const override; [[nodiscard]] TypeStateDescription::State start() const override; [[nodiscard]] TypeStateDescription::State error() const override; + [[nodiscard]] DataFlowAnalysisType analysisType() const override; }; extern template class IDETypeStateAnalysis; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h index 081b94a46..144d3571c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h @@ -102,6 +102,7 @@ class OpenSSLEVPKDFCTXDescription [[nodiscard]] State uninit() const override; [[nodiscard]] State start() const override; [[nodiscard]] State error() const override; + [[nodiscard]] DataFlowAnalysisType analysisType() const override; /* /// Checks all callSites, where a EVP_KDF object needs to be in a /// certain state, such that the state transition for EVP_KDF_CTX is valid. diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h index 34023c863..324333c62 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h @@ -85,6 +85,8 @@ class OpenSSLEVPKDFDescription [[nodiscard]] TypeStateDescription::State start() const override; [[nodiscard]] TypeStateDescription::State error() const override; + + [[nodiscard]] DataFlowAnalysisType analysisType() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h index cb69f4fe7..597fa2795 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h @@ -72,6 +72,7 @@ class OpenSSLSecureHeapDescription [[nodiscard]] TypeStateDescription::State uninit() const override; [[nodiscard]] TypeStateDescription::State start() const override; [[nodiscard]] TypeStateDescription::State error() const override; + [[nodiscard]] DataFlowAnalysisType analysisType() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h index a1c41d1c2..57c41710c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h @@ -41,6 +41,7 @@ class OpenSSLSecureMemoryDescription [[nodiscard]] TypeStateDescription::State uninit() const override; [[nodiscard]] TypeStateDescription::State start() const override; [[nodiscard]] TypeStateDescription::State error() const override; + [[nodiscard]] DataFlowAnalysisType analysisType() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h index 883b1d89d..a7e14e8fc 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h @@ -10,6 +10,8 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" + #include "llvm/IR/InstrTypes.h" #include @@ -28,6 +30,7 @@ struct TypeStateDescriptionBase { getConsumerParamIdx(llvm::StringRef F) const = 0; [[nodiscard]] virtual std::set getFactoryParamIdx(llvm::StringRef F) const = 0; + [[nodiscard]] virtual DataFlowAnalysisType analysisType() const = 0; }; /** diff --git a/include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h b/include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h deleted file mode 100644 index 9190ead07..000000000 --- a/include/phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H -#define PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H - -#include "llvm/Support/raw_ostream.h" - -namespace psr { - -template struct Warning { - using n_t = typename AnalysisDomainTy::n_t; - using d_t = typename AnalysisDomainTy::d_t; - using l_t = typename AnalysisDomainTy::l_t; - - n_t Instr; - d_t Fact; - l_t LatticeElement; - - // Constructor - Warning(n_t Inst, d_t DfFact, l_t Lattice) - : Instr(std::move(Inst)), Fact(std::move(DfFact)), - LatticeElement(std::move(Lattice)) {} -}; - -template struct DataflowAnalysisResults { - std::vector> War; -}; - -template class AnalysisPrinterBase { -public: - virtual void onResult(Warning /*War*/) = 0; - virtual void onInitialize() = 0; - virtual void onFinalize(llvm::raw_ostream & /*OS*/) const = 0; - - AnalysisPrinterBase() = default; - virtual ~AnalysisPrinterBase() = default; - AnalysisPrinterBase(const AnalysisPrinterBase &) = delete; - AnalysisPrinterBase &operator=(const AnalysisPrinterBase &) = delete; - - AnalysisPrinterBase(AnalysisPrinterBase &&) = delete; - AnalysisPrinterBase &operator=(AnalysisPrinterBase &&) = delete; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h b/include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h deleted file mode 100644 index 7cbdf476b..000000000 --- a/include/phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H -#define PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H - -#include "phasar/Domain/BinaryDomain.h" -#include "phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" -#include "phasar/Utils/Printer.h" - -#include -#include -#include - -namespace psr { - -template -class DefaultAnalysisPrinter : public AnalysisPrinterBase { - using l_t = typename AnalysisDomainTy::l_t; - -public: - ~DefaultAnalysisPrinter() override = default; - DefaultAnalysisPrinter() = default; - - void onResult(Warning War) override { - AnalysisResults.War.emplace_back(std::move(War)); - } - - void onInitialize() override{}; - void onFinalize(llvm::raw_ostream &OS = llvm::outs()) const override { - for (const auto &Iter : AnalysisResults.War) { - - OS << "\nAt IR statement: " << NToString(Iter.Instr) << "\n"; - - OS << "\tFact: " << DToString(Iter.Fact) << "\n"; - - if constexpr (std::is_same_v) { - OS << "Value: " << LToString(Iter.LatticeElement) << "\n"; - } - } - } - -private: - DataflowAnalysisResults AnalysisResults{}; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h index 17cab3ef9..9432e9c92 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h @@ -19,6 +19,7 @@ #include "nlohmann/json.hpp" +#include #include // Forward declaration of types for which we only use its pointer or ref type @@ -39,6 +40,7 @@ namespace psr { [[nodiscard]] std::string getFunctionNameFromIR(const llvm::Value *V); [[nodiscard]] std::string getFilePathFromIR(const llvm::Value *V); +[[nodiscard]] std::string getFilePathFromIR(const llvm::DIFile *DIF); [[nodiscard]] std::string getDirectoryFromIR(const llvm::Value *V); @@ -85,6 +87,15 @@ void to_json(nlohmann::json &J, const SourceCodeInfo &Info); [[nodiscard]] SourceCodeInfo getSrcCodeInfoFromIR(const llvm::Value *V); +struct DebugLocation { + unsigned Line{}; + unsigned Column{}; + const llvm::DIFile *File{}; +}; + +[[nodiscard]] std::optional +getDebugLocation(const llvm::Value *V); + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/Utils/LLVMSourceManager.h b/include/phasar/PhasarLLVM/Utils/LLVMSourceManager.h new file mode 100644 index 000000000..1828c6e53 --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/LLVMSourceManager.h @@ -0,0 +1,36 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_LLVMSOURCEMANAGER_H +#define PHASAR_PHASARLLVM_UTILS_LLVMSOURCEMANAGER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/SourceMgr.h" + +#include + +namespace llvm { +class Value; +class DIFile; +} // namespace llvm + +namespace psr { +struct ManagedDebugLocation { + unsigned Line{}; + unsigned Column{}; + unsigned File{}; +}; + +class LLVMSourceManager { +public: + [[nodiscard]] std::optional + getDebugLocation(const llvm::Value *V); + + void print(llvm::raw_ostream &OS, ManagedDebugLocation Loc, + llvm::SourceMgr::DiagKind DiagKind, const llvm::Twine &Message); + +private: + llvm::DenseMap FileIdMap{}; + llvm::SourceMgr SrcMgr{}; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_LLVMSOURCEMANAGER_H diff --git a/include/phasar/PhasarLLVM/Utils/SourceMgrPrinter.h b/include/phasar/PhasarLLVM/Utils/SourceMgrPrinter.h new file mode 100644 index 000000000..58b00e9a9 --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/SourceMgrPrinter.h @@ -0,0 +1,71 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_SOURCEMGRPRINTER_H +#define PHASAR_PHASARLLVM_UTILS_SOURCEMGRPRINTER_H + +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMSourceManager.h" +#include "phasar/Utils/AnalysisPrinterBase.h" +#include "phasar/Utils/MaybeUniquePtr.h" + +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { + +namespace detail { +class SourceMgrPrinterBase { +public: + explicit SourceMgrPrinterBase( + llvm::unique_function &&PrintMessage, + llvm::raw_ostream &OS = llvm::errs(), + llvm::SourceMgr::DiagKind WKind = llvm::SourceMgr::DK_Warning); + + explicit SourceMgrPrinterBase( + llvm::unique_function &&PrintMessage, + const llvm::Twine &OutFileName, + llvm::SourceMgr::DiagKind WKind = llvm::SourceMgr::DK_Warning); + +protected: + LLVMSourceManager SrcMgr; + + llvm::unique_function GetPrintMessage; + MaybeUniquePtr OS = &llvm::errs(); + llvm::SourceMgr::DiagKind WarningKind; +}; +} // namespace detail + +template +class SourceMgrPrinter : public AnalysisPrinterBase, + private detail::SourceMgrPrinterBase { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using l_t = typename AnalysisDomainTy::l_t; + +public: + explicit SourceMgrPrinter( + llvm::unique_function &&PrintMessage, + llvm::raw_ostream &OS = llvm::errs(), + llvm::SourceMgr::DiagKind WKind = llvm::SourceMgr::DK_Warning) + : detail::SourceMgrPrinterBase(std::move(PrintMessage), OS, WKind) {} + +private: + void doOnResult(n_t Inst, d_t Fact, l_t /*Value*/, + DataFlowAnalysisType AnalysisType) override { + auto SrcLoc = SrcMgr.getDebugLocation(Inst); + if constexpr (std::is_convertible_v) { + if (!SrcLoc) { + SrcLoc = + SrcMgr.getDebugLocation(static_cast(Fact)); + } + } + + if (SrcLoc) { + SrcMgr.print(*OS, *SrcLoc, WarningKind, GetPrintMessage(AnalysisType)); + } + } +}; + +} // namespace psr +#endif diff --git a/include/phasar/Utils/AnalysisPrinterBase.h b/include/phasar/Utils/AnalysisPrinterBase.h new file mode 100644 index 000000000..a1ca6aee3 --- /dev/null +++ b/include/phasar/Utils/AnalysisPrinterBase.h @@ -0,0 +1,54 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H +#define PHASAR_PHASARLLVM_UTILS_ANALYSISPRINTERBASE_H + +#include "phasar/Domain/BinaryDomain.h" +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" + +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { + +template class AnalysisPrinterBase { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using l_t = typename AnalysisDomainTy::l_t; + +public: + template , psr::BinaryDomain>>> + void onResult(n_t Instr, d_t DfFact, l_t LatticeElement, + DataFlowAnalysisType AnalysisType) { + doOnResult(Instr, DfFact, LatticeElement, AnalysisType); + } + + template , psr::BinaryDomain>>> + void onResult(n_t Instr, d_t DfFact, DataFlowAnalysisType AnalysisType) { + doOnResult(Instr, DfFact, psr::BinaryDomain::BOTTOM, AnalysisType); + } + + void onInitialize() { doOnInitialize(); } + + void onFinalize() { doOnFinalize(); } + + AnalysisPrinterBase() = default; + virtual ~AnalysisPrinterBase() = default; + AnalysisPrinterBase(const AnalysisPrinterBase &) = delete; + AnalysisPrinterBase &operator=(const AnalysisPrinterBase &) = delete; + + AnalysisPrinterBase(AnalysisPrinterBase &&) = delete; + AnalysisPrinterBase &operator=(AnalysisPrinterBase &&) = delete; + +private: + virtual void doOnResult(n_t /*Instr*/, d_t /*DfFact*/, l_t /*LatticeElement*/, + DataFlowAnalysisType /*AnalysisType*/) = 0; + + virtual void doOnInitialize() {} + virtual void doOnFinalize() {} +}; + +} // namespace psr + +#endif diff --git a/include/phasar/Utils/DefaultAnalysisPrinter.h b/include/phasar/Utils/DefaultAnalysisPrinter.h new file mode 100644 index 000000000..f9008b946 --- /dev/null +++ b/include/phasar/Utils/DefaultAnalysisPrinter.h @@ -0,0 +1,73 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H +#define PHASAR_PHASARLLVM_UTILS_DEFAULTANALYSISPRINTER_H + +#include "phasar/Domain/BinaryDomain.h" +#include "phasar/Utils/AnalysisPrinterBase.h" +#include "phasar/Utils/IO.h" +#include "phasar/Utils/MaybeUniquePtr.h" +#include "phasar/Utils/Printer.h" + +#include +#include +#include + +namespace psr { + +template struct Warning { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using l_t = typename AnalysisDomainTy::l_t; + + n_t Instr; + d_t Fact; + l_t LatticeElement; + DataFlowAnalysisType AnalysisType; + + // Constructor + Warning(n_t Inst, d_t DfFact, l_t Lattice, + DataFlowAnalysisType DfAnalysisType) + : Instr(std::move(Inst)), Fact(std::move(DfFact)), + LatticeElement(std::move(Lattice)), AnalysisType(DfAnalysisType) {} +}; + +template +class DefaultAnalysisPrinter : public AnalysisPrinterBase { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using l_t = typename AnalysisDomainTy::l_t; + +public: + explicit DefaultAnalysisPrinter(llvm::raw_ostream &OS = llvm::outs()) + : OS(&OS) {} + + explicit DefaultAnalysisPrinter(const llvm::Twine &Filename) + : AnalysisPrinterBase(), OS(openFileStream(Filename)){}; + + ~DefaultAnalysisPrinter() override = default; + +private: + void doOnResult(n_t Instr, d_t DfFact, l_t Lattice, + DataFlowAnalysisType AnalysisType) override { + AnalysisResults.emplace_back(Instr, DfFact, Lattice, AnalysisType); + } + + void doOnFinalize() override { + for (const auto &Iter : AnalysisResults) { + + *OS << "\nAt IR statement: " << NToString(Iter.Instr) << "\n"; + + *OS << "\tFact: " << DToString(Iter.Fact) << "\n"; + + if constexpr (!std::is_same_v) { + *OS << "Value: " << LToString(Iter.LatticeElement) << "\n"; + } + } + } + + std::vector> AnalysisResults{}; + MaybeUniquePtr OS = &llvm::outs(); +}; + +} // namespace psr + +#endif diff --git a/include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h b/include/phasar/Utils/NullAnalysisPrinter.h similarity index 58% rename from include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h rename to include/phasar/Utils/NullAnalysisPrinter.h index 900767755..8527cc3c8 100644 --- a/include/phasar/PhasarLLVM/Utils/NullAnalysisPrinter.h +++ b/include/phasar/Utils/NullAnalysisPrinter.h @@ -1,23 +1,26 @@ #ifndef PHASAR_PHASARLLVM_UTILS_NULLANALYSISPRINTER_H #define PHASAR_PHASARLLVM_UTILS_NULLANALYSISPRINTER_H -#include "phasar/PhasarLLVM/Utils/AnalysisPrinterBase.h" +#include "phasar/Utils/AnalysisPrinterBase.h" namespace psr { template class NullAnalysisPrinter final : public AnalysisPrinterBase { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using l_t = typename AnalysisDomainTy::l_t; + public: static NullAnalysisPrinter *getInstance() { static auto Instance = NullAnalysisPrinter(); return &Instance; } - void onInitialize() override{}; - void onResult(Warning /*War*/) override{}; - void onFinalize(llvm::raw_ostream & /*OS*/) const override{}; - private: + void doOnResult(n_t /*Instr*/, d_t /*DfFact*/, l_t /*Lattice*/, + DataFlowAnalysisType /*AnalysisType*/) override{}; + NullAnalysisPrinter() = default; }; diff --git a/include/phasar/Utils/OnTheFlyAnalysisPrinter.h b/include/phasar/Utils/OnTheFlyAnalysisPrinter.h new file mode 100644 index 000000000..aa3e4ef23 --- /dev/null +++ b/include/phasar/Utils/OnTheFlyAnalysisPrinter.h @@ -0,0 +1,49 @@ +#ifndef PHASAR_PHASARLLVM_UTILS_ONTHEFLYANALYSISPRINTER_H +#define PHASAR_PHASARLLVM_UTILS_ONTHEFLYANALYSISPRINTER_H + +#include "phasar/Domain/BinaryDomain.h" +#include "phasar/Utils/AnalysisPrinterBase.h" +#include "phasar/Utils/IO.h" +#include "phasar/Utils/MaybeUniquePtr.h" +#include "phasar/Utils/Printer.h" + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +#include +namespace psr { + +template +class OnTheFlyAnalysisPrinter : public AnalysisPrinterBase { + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using l_t = typename AnalysisDomainTy::l_t; + +public: + explicit OnTheFlyAnalysisPrinter(llvm::raw_ostream &OS) + : AnalysisPrinterBase(), OS(&OS){}; + + explicit OnTheFlyAnalysisPrinter(const llvm::Twine &Filename) + : AnalysisPrinterBase(), OS(openFileStream(Filename)){}; + + OnTheFlyAnalysisPrinter() = default; + ~OnTheFlyAnalysisPrinter() = default; + + [[nodiscard]] bool isValid() const noexcept { return OS != nullptr; } + +private: + void doOnResult(n_t Instr, d_t DfFact, l_t LatticeElement, + DataFlowAnalysisType /*AnalysisType*/) override { + assert(isValid()); + *OS << "\nAt IR statement: " << NToString(Instr) << "\n"; + *OS << "\tFact: " << DToString(DfFact) << "\n"; + if constexpr (!std::is_same_v) { + *OS << "Value: " << LToString(LatticeElement) << "\n"; + } + } + + MaybeUniquePtr OS = nullptr; +}; +} // namespace psr + +#endif diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp index 6759ed4b9..f5b799d90 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @@ -19,6 +19,7 @@ #include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Pointer/PointsToInfo.h" #include "phasar/Utils/DebugOutput.h" @@ -227,9 +228,8 @@ void IDEExtendedTaintAnalysis::reportLeakIfNecessary( const llvm::Value *LeakCandidate) { if (isSink(SinkCandidate, Inst)) { Leaks[Inst].insert(LeakCandidate); - Warning Warn( - Inst, makeFlowFact(LeakCandidate), Top{}); - Printer->onResult(Warn); + Printer->onResult(Inst, makeFlowFact(LeakCandidate), Top{}, + DataFlowAnalysisType::IDEExtendedTaintAnalysis); } } @@ -754,13 +754,12 @@ void IDEExtendedTaintAnalysis::emitTextReport( for (auto &[Inst, LeakSet] : Leaks) { for (const auto &Leak : LeakSet) { - Warning Warn(Inst, makeFlowFact(Leak), - Top{}); - Printer->onResult(Warn); + Printer->onResult(Inst, makeFlowFact(Leak), Top{}, + DataFlowAnalysisType::IDEExtendedTaintAnalysis); } } - Printer->onFinalize(OS); + Printer->onFinalize(); } // Helpers: diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index a6ee4458b..a39fbee4b 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -19,6 +19,7 @@ #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h" +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" @@ -410,9 +411,8 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, CallSite](d_t Source) -> container_type { if (Leak.count(Source)) { if (Leaks[CallSite].insert(Source).second) { - Warning Warn(CallSite, Source, - topElement()); - Printer->onResult(Warn); + Printer->onResult(CallSite, Source, + DataFlowAnalysisType::IFDSTaintAnalysis); } } @@ -439,9 +439,8 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, if (Leak.count(Source)) { if (Leaks[CallSite].insert(Source).second) { - Warning Warn(CallSite, Source, - topElement()); - Printer->onResult(Warn); + Printer->onResult(CallSite, Source, + DataFlowAnalysisType::IFDSTaintAnalysis); } } @@ -487,7 +486,7 @@ void IFDSTaintAnalysis::emitTextReport( const SolverResults & /*SR*/, llvm::raw_ostream &OS) { OS << "\n----- Found the following leaks -----\n"; - Printer->onFinalize(OS); + Printer->onFinalize(); } } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp index 7dea9e963..68e360b35 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp @@ -13,6 +13,7 @@ #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" @@ -188,38 +189,29 @@ IFDSUninitializedVariables::getNormalFlowFunction( }); } // check if some instruction is using an undefined value (in)directly - struct UVFF : FlowFunction { - const llvm::Instruction *Inst; - std::map> &UndefValueUses; - UVFF(const llvm::Instruction *Inst, - std::map> &UVU) - : Inst(Inst), UndefValueUses(UVU) {} - std::set - computeTargets(IFDSUninitializedVariables::d_t Source) override { - for (const auto &Operand : Inst->operands()) { - const llvm::UndefValue *Undef = - llvm::dyn_cast(Operand); - if (Operand == Source || Operand == Undef) { - //---------------------------------------------------------------- - // It is not necessary and (from my point of view) not intended to - // report a leak on EVERY kind of instruction. - // For some of them (e.g. gep, bitcast, ...) propagating the dataflow - // facts may be enough - //---------------------------------------------------------------- - if (!llvm::isa(Inst) && - !llvm::isa(Inst) && - !llvm::isa(Inst)) { - UndefValueUses[Inst].insert(Operand); - } - return {Source, Inst}; + + return lambdaFlow([Curr, this](d_t Source) -> std::set { + for (const auto &Operand : Curr->operands()) { + const llvm::UndefValue *Undef = llvm::dyn_cast(Operand); + if (Operand == Source || Operand == Undef) { + //---------------------------------------------------------------- + // It is not necessary and (from my point of view) not intended to + // report a leak on EVERY kind of instruction. + // For some of them (e.g. gep, bitcast, ...) propagating the dataflow + // facts may be enough + //---------------------------------------------------------------- + if (!llvm::isa(Curr) && + !llvm::isa(Curr) && + !llvm::isa(Curr)) { + UndefValueUses[Curr].insert(Operand); + Printer->onResult(Curr, Operand, + DataFlowAnalysisType::IFDSUninitializedVariables); } + return {Source, Curr}; } - return {Source}; } - }; - return std::make_shared(Curr, UndefValueUses); + return {Source}; + }); } IFDSUninitializedVariables::FlowFunctionPtrType @@ -441,6 +433,7 @@ void IFDSUninitializedVariables::emitTextReport( Res.print(OS); } } + Printer->onFinalize(); } } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp index ba640d0ba..018ac4d93 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.cpp @@ -192,6 +192,11 @@ CSTDFILEIOState CSTDFILEIOTypeStateDescription::error() const { return CSTDFILEIOState::ERROR; } +[[nodiscard]] DataFlowAnalysisType +CSTDFILEIOTypeStateDescription::analysisType() const { + return DataFlowAnalysisType::IDECSTDIOTypeStateAnalysis; +} + template class IDETypeStateAnalysis; } // namespace psr diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp index df37f0bcb..38a4e22af 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.cpp @@ -194,6 +194,11 @@ OpenSSLEVPKDFCTXState OpenSSLEVPKDFCTXDescription::error() const { return OpenSSLEVPKDFCTXState::ERROR; } +[[nodiscard]] DataFlowAnalysisType +OpenSSLEVPKDFCTXDescription::analysisType() const { + return DataFlowAnalysisType::IDEOpenSSLTypeStateAnalysis; +} + OpenSSLEVPKDFCTXDescription::OpenSSLEVTKDFToken OpenSSLEVPKDFCTXDescription::funcNameToToken(llvm::StringRef F) { if (F == "EVP_KDF_CTX_new") { diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp index 4c0973cf7..d881af8ad 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.cpp @@ -130,6 +130,11 @@ OpenSSLEVPKDFState OpenSSLEVPKDFDescription::error() const { return OpenSSLEVPKDFState::ERROR; } +[[nodiscard]] DataFlowAnalysisType +OpenSSLEVPKDFDescription::analysisType() const { + return DataFlowAnalysisType::IDEOpenSSLTypeStateAnalysis; +} + OpenSSLEVPKDFDescription::OpenSSLEVTKDFToken OpenSSLEVPKDFDescription::funcNameToToken(llvm::StringRef FuncName) { if (FuncName == "EVP_KDF_fetch") { diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp index 3c0a90a67..716f682a4 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.cpp @@ -168,6 +168,11 @@ OpenSSLSecureHeapState OpenSSLSecureHeapDescription::error() const { return OpenSSLSecureHeapState::ERROR; } +[[nodiscard]] DataFlowAnalysisType +OpenSSLSecureHeapDescription::analysisType() const { + return DataFlowAnalysisType::IDEOpenSSLTypeStateAnalysis; +} + OpenSSLSecureHeapDescription::OpenSSLSecureHeapToken OpenSSLSecureHeapDescription::funcNameToToken(llvm::StringRef F) { return llvm::StringSwitch(F) diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp index 04d8eba6e..a67f17e42 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.cpp @@ -170,4 +170,9 @@ OpenSSLSecureMemoryState OpenSSLSecureMemoryDescription::error() const { return OpenSSLSecureMemoryState::ERROR; } +[[nodiscard]] DataFlowAnalysisType +OpenSSLSecureMemoryDescription::analysisType() const { + return DataFlowAnalysisType::IDEOpenSSLTypeStateAnalysis; +} + } // namespace psr diff --git a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp index d32c9a3ad..01dd07603 100644 --- a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp +++ b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp @@ -9,7 +9,7 @@ #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Demangle/Demangle.h" #include "llvm/IR/DebugInfoMetadata.h" @@ -20,19 +20,17 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Value.h" - -#include "boost/algorithm/string/trim.hpp" +#include "llvm/Support/Path.h" #include #include #include +#include #include using namespace psr; -namespace psr { - -llvm::DbgVariableIntrinsic *getDbgVarIntrinsic(const llvm::Value *V) { +static llvm::DbgVariableIntrinsic *getDbgVarIntrinsic(const llvm::Value *V) { if (auto *VAM = llvm::ValueAsMetadata::getIfExists( const_cast(V))) { // NOLINT FIXME when LLVM supports it if (auto *MDV = llvm::MetadataAsValue::getIfExists(V->getContext(), VAM)) { @@ -58,7 +56,7 @@ llvm::DbgVariableIntrinsic *getDbgVarIntrinsic(const llvm::Value *V) { return nullptr; } -llvm::DILocalVariable *getDILocalVariable(const llvm::Value *V) { +static llvm::DILocalVariable *getDILocalVariable(const llvm::Value *V) { if (auto *DbgIntr = getDbgVarIntrinsic(V)) { if (auto *DDI = llvm::dyn_cast(DbgIntr)) { return DDI->getVariable(); @@ -70,7 +68,7 @@ llvm::DILocalVariable *getDILocalVariable(const llvm::Value *V) { return nullptr; } -llvm::DIGlobalVariable *getDIGlobalVariable(const llvm::Value *V) { +static llvm::DIGlobalVariable *getDIGlobalVariable(const llvm::Value *V) { if (const auto *GV = llvm::dyn_cast(V)) { if (auto *MN = GV->getMetadata(llvm::LLVMContext::MD_dbg)) { if (auto *DIGVExp = @@ -82,14 +80,14 @@ llvm::DIGlobalVariable *getDIGlobalVariable(const llvm::Value *V) { return nullptr; } -llvm::DISubprogram *getDISubprogram(const llvm::Value *V) { +static llvm::DISubprogram *getDISubprogram(const llvm::Value *V) { if (const auto *F = llvm::dyn_cast(V)) { return F->getSubprogram(); } return nullptr; } -llvm::DILocation *getDILocation(const llvm::Value *V) { +static llvm::DILocation *getDILocation(const llvm::Value *V) { // Arguments and Instruction such as AllocaInst if (auto *DbgIntr = getDbgVarIntrinsic(V)) { if (auto *MN = DbgIntr->getMetadata(llvm::LLVMContext::MD_dbg)) { @@ -103,7 +101,7 @@ llvm::DILocation *getDILocation(const llvm::Value *V) { return nullptr; } -std::string getVarNameFromIR(const llvm::Value *V) { +std::string psr::getVarNameFromIR(const llvm::Value *V) { if (auto *LocVar = getDILocalVariable(V)) { return LocVar->getName().str(); } @@ -113,7 +111,7 @@ std::string getVarNameFromIR(const llvm::Value *V) { return ""; } -std::string getFunctionNameFromIR(const llvm::Value *V) { +std::string psr::getFunctionNameFromIR(const llvm::Value *V) { // We can return unmangled function names w/o checking debug info if (const auto *F = llvm::dyn_cast(V)) { return F->getName().str(); @@ -127,35 +125,47 @@ std::string getFunctionNameFromIR(const llvm::Value *V) { return ""; } -std::string getFilePathFromIR(const llvm::Value *V) { +std::string psr::getFilePathFromIR(const llvm::Value *V) { if (const auto *DIF = getDIFileFromIR(V)) { - std::filesystem::path File(DIF->getFilename().str()); - std::filesystem::path Dir(DIF->getDirectory().str()); - if (!File.empty()) { - // try to concatenate file path and dir to get absolut path - if (!File.has_root_directory() && !Dir.empty()) { - File = Dir / File; - } - return File.string(); - } - } else { - /* As a fallback solution, we will return 'source_filename' info from - * module. However, it is not guaranteed to contain the absoult path, and it - * will return 'llvm-link' for linked modules. */ - if (const auto *F = llvm::dyn_cast(V)) { - return F->getParent()->getSourceFileName(); - } - if (const auto *Arg = llvm::dyn_cast(V)) { - return Arg->getParent()->getParent()->getSourceFileName(); - } - if (const auto *I = llvm::dyn_cast(V)) { - return I->getFunction()->getParent()->getSourceFileName(); - } + return getFilePathFromIR(DIF); } - return ""; + /* As a fallback solution, we will return 'source_filename' info from + * module. However, it is not guaranteed to contain the absoult path, and it + * will return 'llvm-link' for linked modules. */ + if (const auto *F = llvm::dyn_cast(V)) { + return F->getParent()->getSourceFileName(); + } + if (const auto *Arg = llvm::dyn_cast(V)) { + return Arg->getParent()->getParent()->getSourceFileName(); + } + if (const auto *I = llvm::dyn_cast(V)) { + return I->getFunction()->getParent()->getSourceFileName(); + } + + return {}; +} + +std::string psr::getFilePathFromIR(const llvm::DIFile *DIF) { + auto FileName = DIF->getFilename(); + auto DirName = DIF->getDirectory(); + + if (FileName.empty()) { + return {}; + } + + // try to concatenate file path and dir to get absolute path + if (!DirName.empty() && + !llvm::sys::path::has_root_directory(DIF->getFilename())) { + llvm::SmallString<256> Buf; + llvm::sys::path::append(Buf, DirName, FileName); + + return Buf.str().str(); + } + + return FileName.str(); } -const llvm::DIFile *getDIFileFromIR(const llvm::Value *V) { +const llvm::DIFile *psr::getDIFileFromIR(const llvm::Value *V) { if (const auto *GO = llvm::dyn_cast(V)) { if (auto *MN = GO->getMetadata(llvm::LLVMContext::MD_dbg)) { if (auto *Subpr = llvm::dyn_cast(MN)) { @@ -181,7 +191,7 @@ const llvm::DIFile *getDIFileFromIR(const llvm::Value *V) { return nullptr; } -std::string getDirectoryFromIR(const llvm::Value *V) { +std::string psr::getDirectoryFromIR(const llvm::Value *V) { // Argument and Instruction if (auto *DILoc = getDILocation(V)) { return DILoc->getDirectory().str(); @@ -195,7 +205,7 @@ std::string getDirectoryFromIR(const llvm::Value *V) { return ""; } -unsigned int getLineFromIR(const llvm::Value *V) { +unsigned int psr::getLineFromIR(const llvm::Value *V) { // Argument and Instruction if (auto *DILoc = getDILocation(V)) { return DILoc->getLine(); @@ -209,7 +219,7 @@ unsigned int getLineFromIR(const llvm::Value *V) { return 0; } -unsigned int getColumnFromIR(const llvm::Value *V) { +unsigned int psr::getColumnFromIR(const llvm::Value *V) { // Globals and Function have no column info if (auto *DILoc = getDILocation(V)) { return DILoc->getColumn(); @@ -217,7 +227,7 @@ unsigned int getColumnFromIR(const llvm::Value *V) { return 0; } -std::pair getLineAndColFromIR(const llvm::Value *V) { +std::pair psr::getLineAndColFromIR(const llvm::Value *V) { // Argument and Instruction if (auto *DILoc = getDILocation(V)) { return {DILoc->getLine(), DILoc->getColumn()}; @@ -231,7 +241,7 @@ std::pair getLineAndColFromIR(const llvm::Value *V) { return {0, 0}; } -std::string getSrcCodeFromIR(const llvm::Value *V, bool Trim) { +std::string psr::getSrcCodeFromIR(const llvm::Value *V, bool Trim) { unsigned int LineNr = getLineFromIR(V); if (LineNr > 0) { std::filesystem::path Path(getFilePathFromIR(V)); @@ -251,7 +261,7 @@ std::string getSrcCodeFromIR(const llvm::Value *V, bool Trim) { return ""; } -std::string getModuleIDFromIR(const llvm::Value *V) { +std::string psr::getModuleIDFromIR(const llvm::Value *V) { if (const auto *GO = llvm::dyn_cast(V)) { return GO->getParent()->getModuleIdentifier(); } @@ -294,7 +304,7 @@ bool SourceCodeInfo::equivalentWith(const SourceCodeInfo &Other) const { .slice(Pos + 1, llvm::StringRef::npos)); } -void from_json(const nlohmann::json &J, SourceCodeInfo &Info) { +void psr::from_json(const nlohmann::json &J, SourceCodeInfo &Info) { J.at("sourceCodeLine").get_to(Info.SourceCodeLine); J.at("sourceCodeFileName").get_to(Info.SourceCodeFilename); if (auto Fn = J.find("sourceCode"); Fn != J.end()) { @@ -303,7 +313,7 @@ void from_json(const nlohmann::json &J, SourceCodeInfo &Info) { J.at("line").get_to(Info.Line); J.at("column").get_to(Info.Column); } -void to_json(nlohmann::json &J, const SourceCodeInfo &Info) { +void psr::to_json(nlohmann::json &J, const SourceCodeInfo &Info) { J = nlohmann::json{ {"sourceCodeLine", Info.SourceCodeLine}, {"sourceCodeFileName", Info.SourceCodeFilename}, @@ -313,7 +323,7 @@ void to_json(nlohmann::json &J, const SourceCodeInfo &Info) { }; } -SourceCodeInfo getSrcCodeInfoFromIR(const llvm::Value *V) { +SourceCodeInfo psr::getSrcCodeInfoFromIR(const llvm::Value *V) { return SourceCodeInfo{ getSrcCodeFromIR(V), getFilePathFromIR(V), @@ -323,4 +333,18 @@ SourceCodeInfo getSrcCodeInfoFromIR(const llvm::Value *V) { }; } -} // namespace psr +std::optional psr::getDebugLocation(const llvm::Value *V) { + // Argument and Instruction + if (auto *DILoc = getDILocation(V)) { + return DebugLocation{DILoc->getLine(), DILoc->getColumn(), + DILoc->getFile()}; + } + if (auto *DISubpr = getDISubprogram(V)) { // Function + return DebugLocation{DISubpr->getLine(), 0, DISubpr->getFile()}; + } + if (auto *DIGV = getDIGlobalVariable(V)) { // Globals + return DebugLocation{DIGV->getLine(), 0, DIGV->getFile()}; + } + + return std::nullopt; +} diff --git a/lib/PhasarLLVM/Utils/LLVMSourceManager.cpp b/lib/PhasarLLVM/Utils/LLVMSourceManager.cpp new file mode 100644 index 000000000..dba8f4809 --- /dev/null +++ b/lib/PhasarLLVM/Utils/LLVMSourceManager.cpp @@ -0,0 +1,54 @@ +#include "phasar/PhasarLLVM/Utils/LLVMSourceManager.h" + +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/Utils/Logger.h" + +#include "llvm/IR/DebugInfoMetadata.h" + +#include + +using namespace psr; + +static std::optional +getSourceBufId(const llvm::DIFile *File, + llvm::DenseMap &FileIdMap, + llvm::SourceMgr &SrcMgr) { + if (auto It = FileIdMap.find(File); It != FileIdMap.end()) { + return It->second; + } + + auto FileName = psr::getFilePathFromIR(File); + auto Buf = llvm::MemoryBuffer::getFile(FileName, true); + if (!Buf) { + PHASAR_LOG_LEVEL(WARNING, "Source File not accessible: " << FileName); + PHASAR_LOG_LEVEL(INFO, "> " << Buf.getError().message()); + return std::nullopt; + } + + auto Id = SrcMgr.AddNewSourceBuffer(std::move(Buf.get()), llvm::SMLoc{}); + FileIdMap.try_emplace(File, Id); + return Id; +} + +std::optional +LLVMSourceManager::getDebugLocation(const llvm::Value *V) { + auto Loc = psr::getDebugLocation(V); + if (!Loc) { + return std::nullopt; + } + + auto BufId = getSourceBufId(Loc->File, FileIdMap, SrcMgr); + if (!BufId) { + return std::nullopt; + } + + return ManagedDebugLocation{Loc->Line, Loc->Column, *BufId}; +} + +void LLVMSourceManager::print(llvm::raw_ostream &OS, ManagedDebugLocation Loc, + llvm::SourceMgr::DiagKind DiagKind, + const llvm::Twine &Message) { + auto SMLoc = SrcMgr.FindLocForLineAndColumn(Loc.File, Loc.Line, Loc.Column); + + SrcMgr.PrintMessage(OS, SMLoc, DiagKind, Message); +} diff --git a/lib/PhasarLLVM/Utils/SourceMgrPrinter.cpp b/lib/PhasarLLVM/Utils/SourceMgrPrinter.cpp new file mode 100644 index 000000000..01687a5dc --- /dev/null +++ b/lib/PhasarLLVM/Utils/SourceMgrPrinter.cpp @@ -0,0 +1,16 @@ +#include "phasar/PhasarLLVM/Utils/SourceMgrPrinter.h" + +#include "phasar/Utils/IO.h" + +using namespace psr; + +detail::SourceMgrPrinterBase::SourceMgrPrinterBase( + llvm::unique_function &&PrintMessage, + llvm::raw_ostream &OS, llvm::SourceMgr::DiagKind WKind) + : GetPrintMessage(std::move(PrintMessage)), OS(&OS), WarningKind(WKind) {} + +detail::SourceMgrPrinterBase::SourceMgrPrinterBase( + llvm::unique_function &&PrintMessage, + const llvm::Twine &OutFileName, llvm::SourceMgr::DiagKind WKind) + : GetPrintMessage(std::move(PrintMessage)), OS(openFileStream(OutFileName)), + WarningKind(WKind) {} diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGExportTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGExportTest.cpp index 9b4b18046..18f503fc3 100644 --- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGExportTest.cpp +++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFGExportTest.cpp @@ -152,20 +152,27 @@ class LLVMBasedICFGExportTest : public ::testing::Test { ASSERT_TRUE(ExportedICFG.is_array()); EXPECT_EQ(GroundTruth.size(), ExportedICFG.size()); - + bool HasError = false; for (const auto >Json : GroundTruth) { auto GTFrom = GTJson.at("from").get(); auto GTTo = GTJson.at("to").get(); - EXPECT_TRUE(std::any_of(ExportedICFG.begin(), ExportedICFG.end(), - [&](const nlohmann::json &ExportedInfoJson) { - return ExportedInfoJson.at("from") - .get() - .equivalentWith(GTFrom) && - ExportedInfoJson.at("to") - .get() - .equivalentWith(GTTo); - })) - << "No exported equivalent to " << GTJson.dump(4); + + bool HasMatch = std::any_of(ExportedICFG.begin(), ExportedICFG.end(), + [&](const nlohmann::json &ExportedInfoJson) { + return ExportedInfoJson.at("from") + .get() + .equivalentWith(GTFrom) && + ExportedInfoJson.at("to") + .get() + .equivalentWith(GTTo); + }); + + EXPECT_TRUE(HasMatch) << "No exported equivalent to " << GTJson.dump(4); + HasError |= !HasMatch; + } + + if (HasError) { + llvm::errs() << "Errorneous json: " << ExportedICFG.dump(4) << '\n'; } } diff --git a/unittests/Utils/AnalysisPrinterTest.cpp b/unittests/Utils/AnalysisPrinterTest.cpp index 8f1dfb70f..34a110d53 100644 --- a/unittests/Utils/AnalysisPrinterTest.cpp +++ b/unittests/Utils/AnalysisPrinterTest.cpp @@ -7,9 +7,9 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" #include "phasar/PhasarLLVM/TaintConfig/TaintConfigData.h" -#include "phasar/PhasarLLVM/Utils/DefaultAnalysisPrinter.h" #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/DefaultAnalysisPrinter.h" #include "llvm/ADT/DenseMap.h" @@ -22,6 +22,11 @@ using CallBackPairTy = std::pair::config_callback_t, // Use template to variate between Typesate and Taint analysis class GroundTruthCollector : public DefaultAnalysisPrinter { + + using n_t = IDEExtendedTaintAnalysisDomain::n_t; + using d_t = IDEExtendedTaintAnalysisDomain::d_t; + using l_t = IDEExtendedTaintAnalysisDomain::l_t; + public: // constructor init Groundtruth in each fixture GroundTruthCollector(llvm::DenseMap> &GroundTruth) @@ -38,20 +43,19 @@ class GroundTruthCollector } } - void onResult(Warning War) override { +private: + void doOnResult(n_t Instr, d_t DfFact, l_t /*LatticeElement*/, + DataFlowAnalysisType /*AnalysisType*/) override { llvm::DenseMap> FoundLeak; - int SinkId = stoi(getMetaDataID(War.Instr)); + int SinkId = stoi(getMetaDataID(Instr)); std::set LeakedValueIds; - LeakedValueIds.insert(getMetaDataID((War.Fact)->base())); + LeakedValueIds.insert(getMetaDataID((DfFact)->base())); FoundLeak.try_emplace(SinkId, LeakedValueIds); findAndRemove(FoundLeak, GroundTruth); } - void onFinalize(llvm::raw_ostream & /*OS*/ = llvm::outs()) const override { - EXPECT_TRUE(GroundTruth.empty()); - } + void doOnFinalize() override { EXPECT_TRUE(GroundTruth.empty()); } -private: llvm::DenseMap> GroundTruth{}; }; diff --git a/unittests/Utils/CMakeLists.txt b/unittests/Utils/CMakeLists.txt index 62831a3c1..73c042570 100644 --- a/unittests/Utils/CMakeLists.txt +++ b/unittests/Utils/CMakeLists.txt @@ -8,6 +8,8 @@ set(UtilsSources PAMMTest.cpp StableVectorTest.cpp AnalysisPrinterTest.cpp + OnTheFlyAnalysisPrinterTest.cpp + SourceMgrPrinterTest.cpp ) if(PHASAR_ENABLE_DYNAMIC_LOG) diff --git a/unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp b/unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp new file mode 100644 index 000000000..f3cd874d5 --- /dev/null +++ b/unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp @@ -0,0 +1,105 @@ +#include "phasar/Utils/OnTheFlyAnalysisPrinter.h" + +#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h" +#include "phasar/PhasarLLVM/HelperAnalyses.h" +#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +using namespace psr; + +class GroundTruthCollector + : public OnTheFlyAnalysisPrinter { + using n_t = LLVMIFDSAnalysisDomainDefault::n_t; + using d_t = LLVMIFDSAnalysisDomainDefault::d_t; + using l_t = LLVMIFDSAnalysisDomainDefault::l_t; + +public: + // constructor init Groundtruth in each fixture + GroundTruthCollector(llvm::DenseMap> &GroundTruth) + : GroundTruth(GroundTruth){}; + + void findAndRemove(int LeakId, const std::string &LeakedFactId) { + + auto It = GroundTruth.find(LeakId); + ASSERT_NE(It, GroundTruth.end()) + << "Found leak at unexpected location: " << LeakId << ": '" + << LeakedFactId << "'"; + + bool Erased = It->second.erase(LeakedFactId); + ASSERT_TRUE(Erased) << "Did not expect leak '" << LeakedFactId + << "' at instruction " << LeakId; + + if (It->second.empty()) { + GroundTruth.erase(It); + } + } + +private: + void doOnResult(n_t Instr, d_t DfFact, l_t /*LatticeElement*/, + DataFlowAnalysisType /*AnalysisType*/) override { + int LeakId = stoi(getMetaDataID(Instr)); + findAndRemove(LeakId, getMetaDataID(DfFact)); + } + + void doOnFinalize() override { EXPECT_TRUE(GroundTruth.empty()); } + + llvm::DenseMap> GroundTruth{}; +}; + +class OnTheFlyAnalysisPrinterTest : public ::testing::Test { +protected: + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("uninitialized_variables/"); + + const std::vector EntryPoints = {"main"}; + std::optional UnInitProblem; + std::optional HA; + + void initialize(const llvm::Twine &IRFile) { + HA.emplace(PathToLlFiles + IRFile, EntryPoints); + UnInitProblem = + createAnalysisProblem(*HA, EntryPoints); + } + + void doAnalysisTest(llvm::StringRef IRFile, GroundTruthCollector >Printer) { + initialize(IRFile); + UnInitProblem->setAnalysisPrinter(>Printer); + IFDSSolver Solver(*UnInitProblem, &HA->getICFG()); + Solver.solve(); + GTPrinter.onFinalize(); + } +}; + +/* ============== BASIC TESTS ============== */ + +TEST_F(OnTheFlyAnalysisPrinterTest, UninitTest_01_LEAK) { + + llvm::DenseMap> GroundTruth; + // %4 = load i32, i32* %2, ID: 6 ; %2 is the uninitialized variable i + GroundTruth[6] = {"1"}; + // %5 = add nsw i32 %4, 10 ; %4 is undef, since it is loaded from + // undefined alloca; not sure if it is necessary to report again + GroundTruth[7] = {"6"}; + + GroundTruthCollector GroundTruthPrinter = {GroundTruth}; + doAnalysisTest("binop_uninit_cpp_dbg.ll", GroundTruthPrinter); +} + +TEST_F(OnTheFlyAnalysisPrinterTest, UninitTest_02_NOLEAK) { + llvm::DenseMap> GroundTruth; + GroundTruthCollector GroundTruthPrinter = {GroundTruth}; + doAnalysisTest("ctor_default_cpp_dbg.ll", GroundTruthPrinter); +} + +// main function for the test case +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} diff --git a/unittests/Utils/SourceMgrPrinterTest.cpp b/unittests/Utils/SourceMgrPrinterTest.cpp new file mode 100644 index 000000000..59f4fc69a --- /dev/null +++ b/unittests/Utils/SourceMgrPrinterTest.cpp @@ -0,0 +1,95 @@ +#include "phasar/PhasarLLVM/Utils/SourceMgrPrinter.h" + +#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/HelperAnalyses.h" +#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" +#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" +#include "phasar/Utils/AnalysisPrinterBase.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +#include +#include + +using namespace psr; +namespace { +class GroundTruthCollector + : public SourceMgrPrinter { + using n_t = LLVMIFDSAnalysisDomainDefault::n_t; + using d_t = LLVMIFDSAnalysisDomainDefault::d_t; + using l_t = LLVMIFDSAnalysisDomainDefault::l_t; + +public: + // constructor init Groundtruth in each fixture + GroundTruthCollector(std::initializer_list GroundTruth, + bool Dump = false) + : SourceMgrPrinter( + [](DataFlowAnalysisType) { return ""; }, OS), + GroundTruth(GroundTruth), OS(Str), Dump(Dump){}; + +private: + void doOnFinalize() override { + for (auto It = GroundTruth.begin(); It != GroundTruth.end();) { + if (OS.str().find(*It)) { + GroundTruth.erase(It++); + } else { + ++It; + } + } + EXPECT_TRUE(GroundTruth.empty()); + + if (Dump) { + llvm::errs() << Str << '\n'; + } + } + + std::set GroundTruth{}; + std::string Str; + llvm::raw_string_ostream OS; + bool Dump{}; +}; + +class SourceMgrPrinterTest : public ::testing::Test { +protected: + static constexpr auto PathToLlFiles = + PHASAR_BUILD_SUBFOLDER("uninitialized_variables/"); + + const std::vector EntryPoints = {"main"}; + + void doAnalysisTest( + llvm::StringRef IRFile, + AnalysisPrinterBase >Printer) { + HelperAnalyses HA(PathToLlFiles + IRFile, EntryPoints); + auto UnInitProblem = + createAnalysisProblem(HA, EntryPoints); + + UnInitProblem.setAnalysisPrinter(>Printer); + GTPrinter.onInitialize(); + IFDSSolver Solver(UnInitProblem, &HA.getICFG()); + Solver.solve(); + GTPrinter.onFinalize(); + } +}; + +/* ============== BASIC TESTS ============== */ + +TEST_F(SourceMgrPrinterTest, UninitTest_01_LEAK) { + GroundTruthCollector GroundTruthPrinter( + {"/binop_uninit.cpp:3:11:", "/binop_uninit.cpp:3:13:"}); + + doAnalysisTest("binop_uninit_cpp_dbg.ll", GroundTruthPrinter); +} +} // namespace + +// main function for the test case +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} From 1d1be21313b5b8eee53b56034b2585642ab8fe99 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:59:22 +0100 Subject: [PATCH 55/59] IDE Statistics (#697) * Add some statistics to the edge functions in IDE * Make more of AnalysisController internal and reduce dependencies * More stats (WIP) * EF Stats object * More EF stats + add some JF stats * Apply some review comments * More review fixes --------- Co-authored-by: Martin Mory --- .../phasar/Controller/AnalysisController.h | 172 +---------- .../phasar/DataFlow/IfdsIde/EdgeFunction.h | 119 ++++++- .../DataFlow/IfdsIde/EdgeFunctionStats.h | 84 +++++ .../DataFlow/IfdsIde/EdgeFunctionUtils.h | 7 + .../IfdsIde/Solver/FlowEdgeFunctionCache.h | 30 ++ .../DataFlow/IfdsIde/Solver/IDESolver.h | 78 +++++ .../DataFlow/IfdsIde/Solver/JumpFunctions.h | 13 + include/phasar/Utils/Average.h | 33 ++ include/phasar/Utils/Timer.h | 43 +++ include/phasar/Utils/TypeTraits.h | 12 + lib/Controller/AnalysisController.cpp | 292 +++++++++--------- lib/Controller/AnalysisControllerInternal.h | 125 ++++++++ .../AnalysisControllerInternalIDE.h | 62 ++++ .../AnalysisControllerInternalMono.h | 45 +++ .../AnalysisControllerXIDECSTDIOTS.cpp | 11 +- lib/Controller/AnalysisControllerXIDEIIA.cpp | 12 +- .../AnalysisControllerXIDELinearConst.cpp | 12 +- .../AnalysisControllerXIDEOpenSSLTS.cpp | 11 +- .../AnalysisControllerXIDESolverTest.cpp | 12 +- .../AnalysisControllerXIDEXTaint.cpp | 14 +- .../AnalysisControllerXIFDSConst.cpp | 11 +- .../AnalysisControllerXIFDSFieldSensTaint.cpp | 15 +- .../AnalysisControllerXIFDSSolverTest.cpp | 12 +- .../AnalysisControllerXIFDSTaint.cpp | 13 +- .../AnalysisControllerXIFDSType.cpp | 11 +- .../AnalysisControllerXIFDSUninit.cpp | 12 +- ...AnalysisControllerXInterMonoSolverTest.cpp | 12 +- .../AnalysisControllerXInterMonoTaint.cpp | 15 +- ...alysisControllerXIntraMonoFullConstant.cpp | 13 +- ...AnalysisControllerXIntraMonoSolverTest.cpp | 12 +- .../Problems/IDELinearConstantAnalysis.cpp | 25 +- lib/Utils/EdgeFunctionStats.cpp | 49 +++ 32 files changed, 979 insertions(+), 408 deletions(-) create mode 100644 include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h create mode 100644 include/phasar/Utils/Average.h create mode 100644 include/phasar/Utils/Timer.h create mode 100644 lib/Controller/AnalysisControllerInternal.h create mode 100644 lib/Controller/AnalysisControllerInternalIDE.h create mode 100644 lib/Controller/AnalysisControllerInternalMono.h create mode 100644 lib/Utils/EdgeFunctionStats.cpp diff --git a/include/phasar/Controller/AnalysisController.h b/include/phasar/Controller/AnalysisController.h index 5ded47b64..7b9e132c4 100644 --- a/include/phasar/Controller/AnalysisController.h +++ b/include/phasar/Controller/AnalysisController.h @@ -13,159 +13,27 @@ #include "phasar/AnalysisStrategy/Strategies.h" #include "phasar/Controller/AnalysisControllerEmitterOptions.h" #include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h" -#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" -#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" -#include "phasar/DataFlow/IfdsIde/SolverResults.h" -#include "phasar/DataFlow/Mono/Solver/InterMonoSolver.h" -#include "phasar/DataFlow/Mono/Solver/IntraMonoSolver.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/HelperAnalyses.h" -#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" -#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" -#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" -#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" -#include "phasar/Utils/EnumFlags.h" -#include "phasar/Utils/IO.h" -#include "phasar/Utils/Soundness.h" - -#include -#include -#include +#include namespace psr { class AnalysisController { -private: - HelperAnalyses &HA; - std::vector DataFlowAnalyses; - std::vector AnalysisConfigs; - std::vector EntryPoints; - [[maybe_unused]] AnalysisStrategy Strategy; - AnalysisControllerEmitterOptions EmitterOptions = - AnalysisControllerEmitterOptions::None; - std::string ProjectID; - std::filesystem::path ResultDirectory; - IFDSIDESolverConfig SolverConfig; - - /// - /// \brief The maximum length of the CallStrings used in the InterMonoSolver - /// - static const unsigned K = 3; - - void executeDemandDriven(); - - void executeIncremental(); - - void executeModuleWise(); - - void executeVariational(); - - void executeWholeProgram(); - - void emitRequestedHelperAnalysisResults(); - - void executeIFDSUninitVar(); - void executeIFDSConst(); - void executeIFDSTaint(); - void executeIFDSType(); - void executeIFDSSolverTest(); - void executeIFDSFieldSensTaint(); - void executeIDEXTaint(); - void executeIDEOpenSSLTS(); - void executeIDECSTDIOTS(); - void executeIDELinearConst(); - void executeIDESolverTest(); - void executeIDEIIA(); - void executeIntraMonoFullConstant(); - void executeIntraMonoSolverTest(); - void executeInterMonoSolverTest(); - void executeInterMonoTaint(); - - template - void executeMonoAnalysis(ArgTys &&...Args) { - auto Problem = - createAnalysisProblem(HA, std::forward(Args)...); - SolverTy Solver(Problem); - Solver.solve(); - emitRequestedDataFlowResults(Solver); - } - - template - void executeIntraMonoAnalysis(ArgTys &&...Args) { - executeMonoAnalysis, ProblemTy>( - std::forward(Args)...); - } - - template - void executeInterMonoAnalysis(ArgTys &&...Args) { - executeMonoAnalysis, ProblemTy>( - std::forward(Args)...); - } - - template - void executeIfdsIdeAnalysis(ArgTys &&...Args) { - auto Problem = - createAnalysisProblem(HA, std::forward(Args)...); - SolverTy Solver(Problem, &HA.getICFG()); - Solver.solve(); - emitRequestedDataFlowResults(Solver); - } - - template - void executeIFDSAnalysis(ArgTys &&...Args) { - executeIfdsIdeAnalysis, ProblemTy>( - std::forward(Args)...); - } - - template - void executeIDEAnalysis(ArgTys &&...Args) { - executeIfdsIdeAnalysis, ProblemTy>( - std::forward(Args)...); - } - - LLVMTaintConfig makeTaintConfig(); - - template void emitRequestedDataFlowResults(T &Solver) { - if (EmitterOptions & AnalysisControllerEmitterOptions::EmitTextReport) { - if (!ResultDirectory.empty()) { - if (auto OFS = - openFileStream(ResultDirectory.string() + "/psr-report.txt")) { - Solver.emitTextReport(*OFS); - } - } else { - Solver.emitTextReport(llvm::outs()); - } - } - if (EmitterOptions & - AnalysisControllerEmitterOptions::EmitGraphicalReport) { - if (!ResultDirectory.empty()) { - if (auto OFS = - openFileStream(ResultDirectory.string() + "/psr-report.html")) { - Solver.emitGraphicalReport(*OFS); - } - } else { - Solver.emitGraphicalReport(llvm::outs()); - } - } - if (EmitterOptions & AnalysisControllerEmitterOptions::EmitRawResults) { - if (!ResultDirectory.empty()) { - if (auto OFS = openFileStream(ResultDirectory.string() + - "/psr-raw-results.txt")) { - Solver.dumpResults(*OFS); - } - } else { - Solver.dumpResults(llvm::outs()); - } - } - if (EmitterOptions & AnalysisControllerEmitterOptions::EmitESGAsDot) { - llvm::outs() - << "Front-end support for 'EmitESGAsDot' to be implemented\n"; - } - } - public: + struct ControllerData { + HelperAnalyses *HA{}; + std::vector DataFlowAnalyses; + std::vector AnalysisConfigs; + std::vector EntryPoints; + [[maybe_unused]] AnalysisStrategy Strategy; + AnalysisControllerEmitterOptions EmitterOptions = + AnalysisControllerEmitterOptions::None; + std::string ProjectID; + std::filesystem::path ResultDirectory; + IFDSIDESolverConfig SolverConfig{}; + }; + explicit AnalysisController( HelperAnalyses &HA, std::vector DataFlowAnalyses, std::vector AnalysisConfigs, @@ -175,21 +43,15 @@ class AnalysisController { std::string ProjectID = "default-phasar-project", std::string OutDirectory = ""); - ~AnalysisController() = default; - - AnalysisController(const AnalysisController &) = delete; - AnalysisController(AnalysisController &&) = delete; - AnalysisController &operator=(const AnalysisController &) = delete; - AnalysisController &operator=(const AnalysisController &&) = delete; - - void executeAs(AnalysisStrategy Strategy); - static constexpr bool needsToEmitPTA(AnalysisControllerEmitterOptions EmitterOptions) { return (EmitterOptions & AnalysisControllerEmitterOptions::EmitPTAAsDot) || (EmitterOptions & AnalysisControllerEmitterOptions::EmitPTAAsJson) || (EmitterOptions & AnalysisControllerEmitterOptions::EmitPTAAsText); } + +private: + ControllerData Data; }; } // namespace psr diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h index 72f33565a..7f8e98df8 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -14,6 +14,8 @@ #include "phasar/Utils/ByRef.h" #include "phasar/Utils/TypeTraits.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/Casting.h" #include "llvm/Support/TypeName.h" @@ -21,6 +23,7 @@ #include "llvm/Support/raw_ostream.h" #include +#include #include #include #include @@ -65,6 +68,12 @@ concept IsEdgeFunction = requires(const T &EF, const EdgeFunction @@ -73,12 +82,9 @@ class EdgeFunctionBase { alignof(ConcreteEF) <= alignof(void *) && std::is_trivially_copyable_v; + using AllocationPolicy = EdgeFunctionAllocationPolicy; + protected: - enum class AllocationPolicy { - SmallObjectOptimized, - DefaultHeapAllocated, - CustomHeapAllocated, - }; struct RefCountedBase { mutable std::atomic_size_t Rc = 0; }; @@ -326,7 +332,7 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// details. /// [[nodiscard]] l_t computeTarget(ByConstRef Source) const { - assert(!!*this && "computeTarget() called on nullptr!"); + assert(isValid() && "computeTarget() called on nullptr!"); return VTAndHeapAlloc.getPointer()->computeTarget(EF, Source); } @@ -357,8 +363,8 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// SecondEF.computeTarget(FirstEF.computeTarget(x)). [[nodiscard]] static EdgeFunction compose(const EdgeFunction &FirstEF, const EdgeFunction &SecondEF) { - assert(!!FirstEF && "compose() called on LHS nullptr!"); - assert(!!SecondEF && "compose() called on RHS nullptr!"); + assert(FirstEF.isValid() && "compose() called on LHS nullptr!"); + assert(SecondEF.isValid() && "compose() called on RHS nullptr!"); return FirstEF.VTAndHeapAlloc.getPointer()->compose( FirstEF.EF, SecondEF, FirstEF.VTAndHeapAlloc.getInt()); } @@ -398,12 +404,18 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// connected with the value-lattice on l_t [[nodiscard]] static EdgeFunction join(const EdgeFunction &FirstEF, const EdgeFunction &SecondEF) { - assert(!!FirstEF && "join() called on LHS nullptr!"); - assert(!!SecondEF && "join() called on RHS nullptr!"); + assert(FirstEF.isValid() && "join() called on LHS nullptr!"); + assert(SecondEF.isValid() && "join() called on RHS nullptr!"); return FirstEF.VTAndHeapAlloc.getPointer()->join( FirstEF.EF, SecondEF, FirstEF.VTAndHeapAlloc.getInt()); } + [[nodiscard]] bool + referenceEquals(const EdgeFunction &Other) const noexcept { + return VTAndHeapAlloc.getPointer() == Other.VTAndHeapAlloc.getPointer() && + EF == Other.EF; + } + /// Checks for equality of two edge functions. Equality requires exact /// type-equality and value-equality based on operator== of the concrete edge /// functions that are compared. @@ -546,15 +558,17 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { /// Allows for better optimizations in compose and join and should be /// provided, whehever this knowledge is available. [[nodiscard]] bool isConstant() const noexcept { - assert(!!*this && "isConstant() called on nullptr!"); + assert(isValid() && "isConstant() called on nullptr!"); return VTAndHeapAlloc.getPointer()->isConstant(EF); } - /// Performs a null-check. True, iff thie edge function is not null. - [[nodiscard]] explicit operator bool() const noexcept { + [[nodiscard]] bool isValid() const noexcept { return VTAndHeapAlloc.getOpaqueValue(); } + /// Performs a null-check. True, iff thie edge function is not null. + [[nodiscard]] explicit operator bool() const noexcept { return isValid(); } + /// Performs a runtime-typecheck. True, if the concrete type of the held edge /// function *exactly* equals ConcreteEF. /// @@ -609,6 +623,10 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { return VTAndHeapAlloc.getInt() == AllocationPolicy::CustomHeapAllocated; } + [[nodiscard]] auto getAllocationPolicy() const noexcept { + return VTAndHeapAlloc.getInt(); + } + /// Gets an opaque identifier for this edge function. Only meant for /// comparisons of object-identity. Do not dereference! [[nodiscard]] const void *getOpaqueValue() const noexcept { return EF; } @@ -630,6 +648,36 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { return static_cast *>(EF)->Cache; } + [[nodiscard]] size_t getHashCode() const noexcept { + if (!VTAndHeapAlloc.getOpaqueValue()) { + return 0; + } + + return VTAndHeapAlloc.getPointer()->getHashCode( + EF, VTAndHeapAlloc.getPointer()); + } + + [[nodiscard]] auto depth() const noexcept { + assert(isValid() && "depth() called on nullptr!"); + return VTAndHeapAlloc.getPointer()->depth(EF); + } + + friend size_t hash_value(const EdgeFunction &EF) noexcept { // NOLINT + return EF.getHashCode(); + } + + static EdgeFunction getEmptyKey() noexcept { + return EdgeFunction(nullptr, + {llvm::DenseMapInfo::getEmptyKey(), + AllocationPolicy::SmallObjectOptimized}); + } + + static EdgeFunction getTombstoneKey() noexcept { + return EdgeFunction(nullptr, + {llvm::DenseMapInfo::getTombstoneKey(), + AllocationPolicy::SmallObjectOptimized}); + } + private: struct VTable { // NOLINTBEGIN(readability-identifier-naming) @@ -641,6 +689,8 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { void (*print)(const void *, llvm::raw_ostream &); bool (*isConstant)(const void *) noexcept; void (*destroy)(const void *, AllocationPolicy) noexcept; + size_t (*getHashCode)(const void *, const void *) noexcept; + size_t (*depth)(const void *) noexcept; // NOLINTEND(readability-identifier-naming) }; @@ -704,6 +754,23 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { } } }, + [](const void *EF, const void *VT) noexcept -> size_t { + if constexpr (is_std_hashable_v) { + return std::hash{}(*getPtr(EF)); + } else if constexpr (is_llvm_hashable_v) { + using llvm::hash_value; + return hash_value(*getPtr(EF)); + } else { + return llvm::hash_combine(EF, VT); + } + }, + [](const void *EF) noexcept -> size_t { + if constexpr (HasDepth) { + return getPtr(EF)->depth(); + } else { + return 1; + } + }, }; // Utility ctor for (copy) construction. Increments the ref-count if @@ -729,6 +796,32 @@ class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { namespace llvm { +template struct DenseMapInfo> { + static inline auto getEmptyKey() noexcept { + return psr::EdgeFunction::getEmptyKey(); + } + static inline auto getTombstoneKey() noexcept { + return psr::EdgeFunction::getTombstoneKey(); + } + static inline auto getHashValue(const psr::EdgeFunction &EF) noexcept { + return EF.getHashCode(); + } + static inline auto isEqual(const psr::EdgeFunction &EF1, + const psr::EdgeFunction &EF2) noexcept { + if (EF1.referenceEquals(EF2)) { + return true; + } + auto Empty = getEmptyKey(); + auto Tombstone = getTombstoneKey(); + if (EF1.referenceEquals(Empty) || EF2.referenceEquals(Empty) || + EF1.referenceEquals(Tombstone) || EF2.referenceEquals(Tombstone)) { + return false; + } + + return EF1 == EF2; + } +}; + // LLVM is currently overhauling its casting system. Use the new variant once // possible! // Note: The new variant (With CastInfo) is not tested yet! diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h new file mode 100644 index 000000000..448188b48 --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionStats.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_DATAFLOW_IFDSIDE_EDGEFUNCTIONSTATS_H +#define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONSTATS_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +namespace psr { +enum class EdgeFunctionKind; +enum class EdgeFunctionAllocationPolicy; + +namespace detail { +struct EdgeFunctionStatsData { + static constexpr size_t NumEFKinds = 5; + static constexpr size_t NumAllocPolicies = 3; + + std::array UniqueEFCount{}; + std::array TotalEFCount{}; + std::array PerAllocCount{}; + size_t MaxDepth{}; + double AvgDepth{}; + double AvgUniqueDepth{}; + + size_t TotalNumJF{}; + size_t UniqueNumJF{}; + size_t NumJFObjects{}; + size_t MaxJFDepth{}; + double AvgJFDepth{}; + double AvgUniqueJFDepth{}; + double AvgJFObjDepth{}; + std::array PerAllocJFCount{}; +}; +} // namespace detail + +class EdgeFunctionStats : public detail::EdgeFunctionStatsData { +public: + [[nodiscard]] size_t getNumUniqueEFs() const noexcept { + return std::reduce(UniqueEFCount.begin(), UniqueEFCount.end()); + } + [[nodiscard]] size_t getNumUniqueEFs(EdgeFunctionKind Kind) const noexcept { + assert(size_t(Kind) < NumEFKinds); + return UniqueEFCount[size_t(Kind)]; // NOLINT + } + + [[nodiscard]] size_t getNumEFs() const noexcept { + return std::reduce(TotalEFCount.begin(), TotalEFCount.end()); + } + [[nodiscard]] size_t getNumEFs(EdgeFunctionKind Kind) const noexcept { + assert(size_t(Kind) < NumEFKinds); + return TotalEFCount[size_t(Kind)]; // NOLINT + } + + [[nodiscard]] size_t getNumEFsPerAllocationPolicy( + EdgeFunctionAllocationPolicy Policy) const noexcept { + assert(size_t(Policy) < NumAllocPolicies); + return PerAllocCount[size_t(Policy)]; // NOLINT + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const EdgeFunctionStats &S); + +private: + template + friend class IDESolver; + + constexpr EdgeFunctionStats( + const detail::EdgeFunctionStatsData &Data) noexcept + : detail::EdgeFunctionStatsData(Data) {} +}; +} // namespace psr + +#endif // PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONSTATS_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h index 018a7849f..de9db609a 100644 --- a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h @@ -13,6 +13,7 @@ #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" #include "phasar/Utils/ByRef.h" #include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/ArrayRef.h" @@ -265,12 +266,18 @@ template struct EdgeFunctionComposer { return LHS.First == RHS.First && LHS.Second == RHS.Second; } + [[nodiscard]] size_t depth() const noexcept { + return First.depth() + Second.depth(); + } + // -- data members EdgeFunction First{}; EdgeFunction Second{}; }; +static_assert(HasDepth>); + template struct JoinEdgeFunction { using l_t = L; using JLattice = JoinLatticeTraits; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h index b9d89a88e..637eaa083 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h @@ -32,6 +32,10 @@ class Value; } // namespace llvm namespace psr { + +enum class EdgeFunctionKind { Normal, Call, Return, CallToReturn, Summary }; +static constexpr size_t EdgeFunctionKindCount = 5; + template class DefaultMapKeyCompressor { public: using KeyType = KeyT; @@ -603,6 +607,32 @@ class FlowEdgeFunctionCache { } } + template void foreachCachedEdgeFunction(Handler Fn) const { + for (const auto &[Key, NormalFns] : NormalFunctionCache) { + for (const auto &[Set, EF] : NormalFns.EdgeFunctionMap) { + std::invoke(Fn, EF, EdgeFunctionKind::Normal); + } + } + + for (const auto &[Key, EF] : CallEdgeFunctionCache) { + std::invoke(Fn, EF, EdgeFunctionKind::Call); + } + + for (const auto &[Key, EF] : ReturnEdgeFunctionCache) { + std::invoke(Fn, EF, EdgeFunctionKind::Return); + } + + for (const auto &[Key, CTRFns] : CallToRetEdgeFunctionCache) { + for (const auto &[Set, EF] : CTRFns) { + std::invoke(Fn, EF, EdgeFunctionKind::CallToReturn); + } + } + + for (const auto &[Key, EF] : SummaryEdgeFunctionCache) { + std::invoke(Fn, EF, EdgeFunctionKind::Summary); + } + } + private: inline EdgeFuncInstKey createEdgeFunctionInstKey(n_t Lhs, n_t Rhs) { uint64_t Val = 0; diff --git a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index eb2c323c3..3274ced1a 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -20,6 +20,7 @@ #include "phasar/Config/Configuration.h" #include "phasar/DB/ProjectIRDBBase.h" #include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionStats.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" @@ -33,6 +34,7 @@ #include "phasar/DataFlow/IfdsIde/Solver/PathEdge.h" #include "phasar/DataFlow/IfdsIde/SolverResults.h" #include "phasar/Domain/AnalysisDomain.h" +#include "phasar/Utils/Average.h" #include "phasar/Utils/DOTGraph.h" #include "phasar/Utils/JoinLattice.h" #include "phasar/Utils/Logger.h" @@ -40,6 +42,7 @@ #include "phasar/Utils/Table.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" @@ -256,6 +259,81 @@ class IDESolver std::move(ZeroValue)); } + [[nodiscard]] EdgeFunctionStats getEdgeFunctionStatistics() const { + detail::EdgeFunctionStatsData Stats{}; + + // Cached Edge Functions + { + std::array>, EdgeFunctionKindCount> + UniqueEFs{}; + Sampler DepthSampler{}; + Sampler UniqueDepthSampler{}; + // TODO: Cache EFs + CachedFlowEdgeFunctions.foreachCachedEdgeFunction( + [&](EdgeFunction EF, EdgeFunctionKind Kind) { + auto Depth = EF.depth(); + DepthSampler.addSample(Depth); + if (Depth > Stats.MaxDepth) { + Stats.MaxDepth = Depth; + } + + if (UniqueEFs[size_t(Kind)].insert(std::move(EF)).second) { + UniqueDepthSampler.addSample(Depth); + } + Stats.TotalEFCount[size_t(Kind)]++; + Stats.PerAllocCount[size_t(EF.getAllocationPolicy())]++; + }); + + size_t TotalUniqueNumEF = 0; + for (size_t I = 0, End = UniqueEFs.size(); I != End; ++I) { + Stats.UniqueEFCount[I] = UniqueEFs[I].size(); // NOLINT + TotalUniqueNumEF += UniqueEFs[I].size(); + } + + Stats.AvgDepth = DepthSampler.getAverage(); + Stats.AvgUniqueDepth = UniqueDepthSampler.getAverage(); + } + + // Jump Functions + { + llvm::DenseSet> UniqueJumpFns; + llvm::DenseSet AllocatedJumpFns; + Sampler DepthSampler{}; + Sampler UniqueDepthSampler{}; + Sampler AllocDepthSampler{}; + + JumpFn->foreachEdgeFunction([&](EdgeFunction JF) { + ++Stats.TotalNumJF; + auto Depth = JF.depth(); + DepthSampler.addSample(Depth); + if (Depth > Stats.MaxJFDepth) { + Stats.MaxJFDepth = Depth; + } + + if (AllocatedJumpFns.insert(JF.getOpaqueValue()).second) { + AllocDepthSampler.addSample(Depth); + } + + Stats.PerAllocJFCount[size_t(JF.getAllocationPolicy())]++; + + if (UniqueJumpFns.insert(std::move(JF)).second) { + UniqueDepthSampler.addSample(Depth); + } + }); + + Stats.UniqueNumJF = UniqueJumpFns.size(); + Stats.NumJFObjects = AllocatedJumpFns.size(); + Stats.AvgJFDepth = DepthSampler.getAverage(); + Stats.AvgUniqueJFDepth = UniqueDepthSampler.getAverage(); + Stats.AvgJFObjDepth = AllocDepthSampler.getAverage(); + } + return Stats; + } + + void printEdgeFunctionStatistics(llvm::raw_ostream &OS = llvm::outs()) const { + OS << getEdgeFunctionStatistics() << '\n'; + } + protected: /// Lines 13-20 of the algorithm; processing a call site in the caller's /// context. diff --git a/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h index 0a9bcb327..85a80fe60 100644 --- a/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h @@ -18,6 +18,7 @@ #define PHASAR_DATAFLOW_IFDSIDE_SOLVER_JUMPFUNCTIONS_H #include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/Utils/ByRef.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/Table.h" @@ -157,6 +158,18 @@ template class JumpFunctions { return NonEmptyLookupByTargetNode[Target]; } + template + void foreachEdgeFunction(HandlerFn Handler) const { + NonEmptyForwardLookup.foreachCell( + [Handler = std::move(Handler)](ByConstRef /*Row*/, + ByConstRef /*Col*/, + const auto &TargetFactAndEF) { + for (const auto &[TargetFact, EF] : TargetFactAndEF) { + std::invoke(Handler, EF); + } + }); + } + /** * Removes a jump function. The source statement is implicit. * @see PathEdge diff --git a/include/phasar/Utils/Average.h b/include/phasar/Utils/Average.h new file mode 100644 index 000000000..c6e54f090 --- /dev/null +++ b/include/phasar/Utils/Average.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel + *****************************************************************************/ + +#ifndef PHASAR_UTILS_AVERAGE_H +#define PHASAR_UTILS_AVERAGE_H + +#include + +namespace psr { + +struct Sampler { + size_t Count{}; + double Curr{}; + + constexpr void addSample(size_t Sample) noexcept { + Curr += (double(Sample) - Curr) / double(++Count); + } + + [[nodiscard]] constexpr double getAverage() const noexcept { return Curr; } + [[nodiscard]] constexpr size_t getNumSamples() const noexcept { + return Count; + } +}; + +} // namespace psr + +#endif // PHASAR_UTILS_AVERAGE_H diff --git a/include/phasar/Utils/Timer.h b/include/phasar/Utils/Timer.h new file mode 100644 index 000000000..f485aa0cb --- /dev/null +++ b/include/phasar/Utils/Timer.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_TIMER_H +#define PHASAR_UTILS_TIMER_H + +#include "llvm/ADT/FunctionExtras.h" + +#include + +namespace psr { +class Timer { +public: + Timer(llvm::unique_function + WithElapsed) noexcept + : WithElapsed(std::move(WithElapsed)), + Start(std::chrono::steady_clock::now()) {} + + Timer(Timer &&) noexcept = default; + Timer &operator=(Timer &&) noexcept = default; + Timer(const Timer &) = delete; + Timer &operator=(const Timer &) = delete; + + ~Timer() { + if (WithElapsed) { + auto End = std::chrono::steady_clock::now(); + WithElapsed(End - Start); + } + } + +private: + llvm::unique_function WithElapsed; + std::chrono::steady_clock::time_point Start; +}; +} // namespace psr + +#endif // PHASAR_UTILS_TIMER_H diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index e954dd14e..f4c6736f2 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -112,6 +112,10 @@ struct is_llvm_hashable : std::false_type {}; // NOLINT template struct is_llvm_hashable()))> // NOLINT : std::true_type {}; +template +struct is_llvm_hashable()))> // NOLINT + : std::true_type {}; template