diff --git a/.clang-tidy b/.clang-tidy index ad126f0017..6b27213543 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -15,6 +15,7 @@ Checks: '-*, -readability-function-cognitive-complexity, -readability-convert-member-functions-to-static, -readability-isolate-declaration, + -readability-identifier-length, cppcoreguidelines-*, -cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, @@ -28,7 +29,6 @@ Checks: '-*, -bugprone-easily-swappable-parameters, modernize-*, -modernize-use-trailing-return-type, - -modernize-pass-by-value, performance-*, clang-analyzer-*, ' diff --git a/config/DOTGraphConfig.json b/config/DOTGraphConfig.json index 1e0621b9f9..4d2fd4c58a 100644 --- a/config/DOTGraphConfig.json +++ b/config/DOTGraphConfig.json @@ -1,49 +1,48 @@ { - "CFNode": { - "style": "filled", - "shape": "record" - }, - "CFIntraEdge": { - }, - "CFInterEdge": { - "weight": "1" - }, - "FactNode": { - "style": "rounded" - }, - "FactIDEdge": { - "style": "dotted", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "FactCrossEdge": { + "CFNode": { + "style": "filled", + "shape": "record" + }, + "CFIntraEdge": {}, + "CFInterEdge": { + "weight": "1" + }, + "FactNode": { + "style": "rounded" + }, + "FactIDEdge": { "style": "dotted", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "FactInterEdge": { + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "FactCrossEdge": { + "style": "dotted", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "FactInterEdge": { "weight": "0.1", - "style": "dashed", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "LambdaNode": { - "style": "rounded" - }, - "LambdaIDEdge": { - "style": "dotted", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "LambdaInterEdge": { + "style": "dashed", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "LambdaNode": { + "style": "rounded" + }, + "LambdaIDEdge": { + "style": "dotted", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "LambdaInterEdge": { "weight": "0.1", - "style": "dashed", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - } + "style": "dashed", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + } } diff --git a/config/phasar-source-sink-function.json b/config/phasar-source-sink-function.json index 573d667e30..711d8d5714 100644 --- a/config/phasar-source-sink-function.json +++ b/config/phasar-source-sink-function.json @@ -1,20 +1,28 @@ { - "Source Functions": { - "source()": { - "Args": [], - "Return": true - }, - "read": { - "Args": [0, 1, 3], - "Return": false - } - }, - "Sink Functions": { - "sink(int)": { - "Args": [0] - }, - "write": { - "Args": [1] - } - } + "Source Functions": { + "source()": { + "Args": [], + "Return": true + }, + "read": { + "Args": [ + 0, + 1, + 3 + ], + "Return": false + } + }, + "Sink Functions": { + "sink(int)": { + "Args": [ + 0 + ] + }, + "write": { + "Args": [ + 1 + ] + } + } } diff --git a/include/phasar/Controller/AnalysisController.h b/include/phasar/Controller/AnalysisController.h index 7c8d248cd9..6f09dd4a76 100644 --- a/include/phasar/Controller/AnalysisController.h +++ b/include/phasar/Controller/AnalysisController.h @@ -43,9 +43,9 @@ enum class AnalysisControllerEmitterOptions : uint32_t { EmitTHAsText = (1 << 5), EmitTHAsDot = (1 << 6), EmitTHAsJson = (1 << 7), - EmitCGAsText = (1 << 8), + // EmitCGAsText = (1 << 8), EmitCGAsDot = (1 << 9), - EmitCGAsJson = (1 << 10), + // EmitCGAsJson = (1 << 10), EmitPTAAsText = (1 << 11), EmitPTAAsDot = (1 << 12), EmitPTAAsJson = (1 << 13), @@ -60,7 +60,7 @@ class AnalysisController { LLVMBasedICFG ICF; std::vector DataFlowAnalyses; std::vector AnalysisConfigs; - std::set EntryPoints; + std::vector EntryPoints; [[maybe_unused]] AnalysisStrategy Strategy; AnalysisControllerEmitterOptions EmitterOptions = AnalysisControllerEmitterOptions::None; @@ -193,7 +193,7 @@ class AnalysisController { std::vector AnalysisConfigs, PointerAnalysisType PTATy, CallGraphAnalysisType CGTy, Soundness SoundnessLevel, bool AutoGlobalSupport, - const std::set &EntryPoints, + std::vector EntryPoints, AnalysisStrategy Strategy, AnalysisControllerEmitterOptions EmitterOptions, IFDSIDESolverConfig SolverConfig, diff --git a/include/phasar/DB/ProjectIRDB.h b/include/phasar/DB/ProjectIRDB.h index 67958d216f..f369fcd423 100644 --- a/include/phasar/DB/ProjectIRDB.h +++ b/include/phasar/DB/ProjectIRDB.h @@ -61,7 +61,8 @@ class ProjectIRDB { std::map> Modules; // Maps an id to its corresponding instruction std::map IDInstructionMapping; - size_t NumberCallsites; + size_t NumGlobals = 0; + size_t NumberCallsites = 0; nlohmann::json StatsJson; void buildIDModuleMapping(llvm::Module *M); @@ -97,6 +98,7 @@ class ProjectIRDB { ~ProjectIRDB(); void insertModule(llvm::Module *M); + void insertFunction(llvm::Function *F); // add WPA support by providing a fat completely linked module void linkForWPA(); @@ -180,6 +182,8 @@ class ProjectIRDB { [[nodiscard]] std::size_t getNumGlobals() const; + [[nodiscard]] std::size_t getNumFunctions() const; + [[nodiscard]] llvm::Instruction *getInstruction(std::size_t Id) const; [[nodiscard]] static std::size_t getInstructionID(const llvm::Instruction *I); diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h b/include/phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h index 4abfc97c2f..65de594ee9 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h +++ b/include/phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h @@ -19,6 +19,7 @@ #include "phasar/DB/ProjectIRDB.h" #include "phasar/PhasarLLVM/AnalysisStrategy/AnalysisSetup.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" @@ -54,7 +55,7 @@ class WholeProgramAnalysis { public: WholeProgramAnalysis(IFDSIDESolverConfig SolverConfig, ProjectIRDB &IRDB, - std::set EntryPoints = {}, + llvm::ArrayRef EntryPoints = {}, PointerAnalysisTy *PointerInfo = nullptr, CallGraphAnalysisTy *CallGraph = nullptr, TypeHierarchyTy *TypeHierarchy = nullptr) @@ -67,11 +68,12 @@ class WholeProgramAnalysis { : std::unique_ptr(PointerInfo)), CallGraph(CallGraph == nullptr ? std::make_unique( - IRDB, CallGraphAnalysisType::OTF, EntryPoints, + &IRDB, CallGraphAnalysisType::OTF, EntryPoints, this->TypeHierarchy.get(), this->PointerInfo.get()) : std::unique_ptr(CallGraph)), - EntryPoints(EntryPoints), - ProblemDesc(&IRDB, TypeHierarchy, CallGraph, PointerInfo, EntryPoints), + EntryPoints(EntryPoints.begin(), EntryPoints.end()), + ProblemDesc(&IRDB, TypeHierarchy, CallGraph, PointerInfo, + this->EntryPoints), DataFlowSolver(ProblemDesc) { if constexpr (has_setIFDSIDESolverConfig_v) { ProblemDesc.setIFDSIDESolverConfig(SolverConfig); @@ -83,7 +85,7 @@ class WholeProgramAnalysis { typename T::ConfigurationTy, HasNoConfigurationType>>> WholeProgramAnalysis(IFDSIDESolverConfig SolverConfig, ProjectIRDB &IRDB, ConfigurationTy *Config, - std::set EntryPoints = {}, + llvm::ArrayRef EntryPoints = {}, PointerAnalysisTy *PointerInfo = nullptr, CallGraphAnalysisTy *CallGraph = nullptr, TypeHierarchyTy *TypeHierarchy = nullptr) @@ -96,12 +98,12 @@ class WholeProgramAnalysis { : std::unique_ptr(PointerInfo)), CallGraph(CallGraph == nullptr ? std::make_unique( - IRDB, CallGraphAnalysisType::OTF, EntryPoints, + &IRDB, CallGraphAnalysisType::OTF, EntryPoints, this->TypeHierarchy.get(), this->PointerInfo.get()) : std::unique_ptr(CallGraph)), - EntryPoints(EntryPoints), Config(Config), + EntryPoints(EntryPoints.begin(), EntryPoints.end()), Config(Config), ProblemDesc(&IRDB, TypeHierarchy, CallGraph, PointerInfo, *Config, - EntryPoints), + this->EntryPoints), DataFlowSolver(ProblemDesc) { if constexpr (has_setIFDSIDESolverConfig_v) { ProblemDesc.setIFDSIDESolverConfig(SolverConfig); @@ -113,7 +115,7 @@ class WholeProgramAnalysis { typename T::ConfigurationTy, HasNoConfigurationType>>> WholeProgramAnalysis(IFDSIDESolverConfig SolverConfig, ProjectIRDB &IRDB, std::string ConfigPath, - std::set EntryPoints = {}, + llvm::ArrayRef EntryPoints = {}, PointerAnalysisTy *PointerInfo = nullptr, CallGraphAnalysisTy *CallGraph = nullptr, TypeHierarchyTy *TypeHierarchy = nullptr) @@ -126,13 +128,14 @@ class WholeProgramAnalysis { : std::unique_ptr(PointerInfo)), CallGraph(CallGraph == nullptr ? std::make_unique( - IRDB, CallGraphAnalysisType::OTF, EntryPoints, + &IRDB, CallGraphAnalysisType::OTF, EntryPoints, this->TypeHierarchy.get(), this->PointerInfo.get()) : std::unique_ptr(CallGraph)), - EntryPoints(EntryPoints), Config(new ConfigurationTy(ConfigPath)), - OwnsConfig(true), ConfigPath(ConfigPath), + EntryPoints(EntryPoints.begin(), EntryPoints.end()), + Config(new ConfigurationTy(ConfigPath)), OwnsConfig(true), + ConfigPath(ConfigPath), ProblemDesc(&IRDB, TypeHierarchy, CallGraph, PointerInfo, *Config, - EntryPoints), + this->EntryPoints), DataFlowSolver(ProblemDesc) { if constexpr (has_setIFDSIDESolverConfig_v) { ProblemDesc.setIFDSIDESolverConfig(SolverConfig); diff --git a/include/phasar/PhasarLLVM/ControlFlow/BiDiICFG.h b/include/phasar/PhasarLLVM/ControlFlow/BiDiICFG.h deleted file mode 100644 index e3af7a661b..0000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/BiDiICFG.h +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** - * 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 and others - *****************************************************************************/ - -/* - * BiDiICFG.h - * - * Created on: 15.09.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_BIDIICFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_BIDIICFG_H_ - -#include - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" - -namespace psr { - -template class BiDiICFG : public ICFG { -public: - virtual ~BiDiICFG() = default; - - virtual std::vector getPredsOf(N U) = 0; - - virtual std::set getEndPointsOf(F Func) = 0; - - virtual std::vector getPredsOfCallAt(N U) = 0; - - virtual std::set allNonCallEndNodes() = 0; - - // also exposed to some clients who need it - // virtual DirectedGraph getOrCreateUnitGraph(F body) = 0; - - virtual std::vector getParameterRefs(F Func) = 0; - - /** - * Gets whether the given statement is a return site of at least one call - * @param n The statement to check - * @return True if the given statement is a return site, otherwise false - */ - virtual bool isReturnSite(N U) = 0; - - /** - * Checks whether the given statement is reachable from the entry point - * @param u The statement to check - * @return True if there is a control flow path from the entry point of the - * program to the given statement, otherwise false - */ - virtual bool isReachable(N U) = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/CFG.h b/include/phasar/PhasarLLVM/ControlFlow/CFG.h deleted file mode 100644 index dfe42fb2a4..0000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/CFG.h +++ /dev/null @@ -1,97 +0,0 @@ -/****************************************************************************** - * 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 and others - *****************************************************************************/ - -/* - * CFG.h - * - * Created on: 07.06.2017 - * Author: philipp - */ - -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_CFG_H_ - -#include -#include -#include -#include - -#include "nlohmann/json.hpp" - -namespace llvm { -class raw_ostream; -} - -namespace psr { - -enum class SpecialMemberFunctionType { -#define SPECIAL_MEMBER_FUNCTION_TYPES(NAME, TYPE) TYPE, -#include "phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def" -}; - -std::string toString(const SpecialMemberFunctionType &SMFT); - -SpecialMemberFunctionType toSpecialMemberFunctionType(const std::string &SMFT); - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const SpecialMemberFunctionType &SMFT); - -template class CFG { -public: - virtual ~CFG() = default; - - virtual F getFunctionOf(N Inst) const = 0; - - virtual std::vector getPredsOf(N Inst) const = 0; - - virtual std::vector getSuccsOf(N Inst) const = 0; - - virtual std::vector> getAllControlFlowEdges(F Fun) const = 0; - - virtual std::vector getAllInstructionsOf(F Fun) const = 0; - - virtual std::set getStartPointsOf(F Fun) const = 0; - - virtual std::set getExitPointsOf(F Fun) const = 0; - - virtual bool isCallSite(N Inst) const = 0; - - virtual bool isExitInst(N Inst) const = 0; - - virtual bool isStartPoint(N Inst) const = 0; - - virtual bool isFieldLoad(N Inst) const = 0; - - virtual bool isFieldStore(N Inst) const = 0; - - virtual bool isFallThroughSuccessor(N Inst, N Succ) const = 0; - - virtual bool isBranchTarget(N Inst, N Succ) const = 0; - - virtual bool isHeapAllocatingFunction(F Fun) const = 0; - - virtual bool isSpecialMemberFunction(F Fun) const = 0; - - virtual SpecialMemberFunctionType - getSpecialMemberFunctionType(F Fun) const = 0; - - virtual std::string getStatementId(N Inst) const = 0; - - virtual std::string getFunctionName(F Fun) const = 0; - - virtual std::string getDemangledFunctionName(F Fun) const = 0; - - virtual void print(F Fun, llvm::raw_ostream &OS) const = 0; - - virtual nlohmann::json getAsJson(F Fun) const = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h b/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h new file mode 100644 index 0000000000..a3e707e3be --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h @@ -0,0 +1,153 @@ +/****************************************************************************** + * 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_CONTROLFLOW_CFGBASE_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H + +#include "phasar/PhasarLLVM/Utils/ByRef.h" +#include "phasar/Utils/TypeTraits.h" + +#include "nlohmann/json.hpp" + +namespace psr { + +enum class SpecialMemberFunctionType; + +template struct CFGTraits { + // using n_t + // using f_t +}; + +template class CFGBase { +public: + using n_t = typename CFGTraits::n_t; + using f_t = typename CFGTraits::f_t; + + /// Returns the function where the given instruction is defined + [[nodiscard]] f_t getFunctionOf(ByConstRef Inst) const noexcept { + return self().getFunctionOfImpl(Inst); + } + /// Returns an iterable range of all predecessor instructions of Inst in the + /// CFG + [[nodiscard]] decltype(auto) getPredsOf(ByConstRef Inst) const { + static_assert( + is_iterable_over_v); + return self().getPredsOfImpl(Inst); + } + /// Returns an iterable range of all successor instructions of Inst in the + /// CFG. NOTE: This function is typically being called in a hot part of the + /// analysis and should therefore be highly optimized for performance + [[nodiscard]] decltype(auto) getSuccsOf(ByConstRef Inst) const { + static_assert( + is_iterable_over_v); + return self().getSuccsOfImpl(Inst); + } + /// Returns an iterable range of all edges in the CFG of the given function + [[nodiscard]] decltype(auto) + getAllControlFlowEdges(ByConstRef Fun) const { + static_assert( + is_iterable_over_v>); + return self().getAllControlFlowEdgesImpl(Fun); + } + /// Returns an iterable range of all instructions of the given function. NOTE: + /// even if the CFG is initialized to ignore debugging instructions, they may + /// be contained here. + [[nodiscard]] decltype(auto) getAllInstructionsOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getAllInstructionsOfImpl(Fun); + } + /// Returns an iterable range of all starting instructions of the given + /// function. For a forward-CFG, this is typically a singleton range + [[nodiscard]] decltype(auto) getStartPointsOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getStartPointsOfImpl(Fun); + } + /// Returns an iterable range of all exit instructions (often return + /// instructions) of the given function. For a backward-CFG, this is typically + /// a singleton range + [[nodiscard]] decltype(auto) getExitPointsOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getExitPointsOfImpl(Fun); + } + [[nodiscard]] bool isCallSite(ByConstRef Inst) const noexcept { + return self().isCallSiteImpl(Inst); + } + [[nodiscard]] bool isExitInst(ByConstRef Inst) const noexcept { + return self().isExitInstImpl(Inst); + } + [[nodiscard]] bool isStartPoint(ByConstRef Inst) const noexcept { + return self().isStartPointImpl(Inst); + } + [[nodiscard]] bool isFieldLoad(ByConstRef Inst) const noexcept { + return self().isFieldLoadImpl(Inst); + } + [[nodiscard]] bool isFieldStore(ByConstRef Inst) const noexcept { + return self().isFieldStoreImpl(Inst); + } + [[nodiscard]] bool + isFallThroughSuccessor(ByConstRef Inst, + ByConstRef Succ) const noexcept { + return self().isFallThroughSuccessorImpl(Inst, Succ); + } + [[nodiscard]] bool isBranchTarget(ByConstRef Inst, + ByConstRef Succ) const noexcept { + return self().isBranchTargetImpl(Inst, Succ); + } + [[nodiscard]] bool isHeapAllocatingFunction(ByConstRef Fun) const { + return self().isHeapAllocatingFunctionImpl(Fun); + } + [[nodiscard]] bool isSpecialMemberFunction(ByConstRef Fun) const { + return self().isSpecialMemberFunctionImpl(Fun); + } + [[nodiscard]] SpecialMemberFunctionType + getSpecialMemberFunctionType(ByConstRef Fun) const { + return self().getSpecialMemberFunctionTypeImpl(Fun); + } + [[nodiscard]] decltype(auto) getStatementId(ByConstRef Inst) const { + static_assert(is_string_like_v); + return self().getStatementIdImpl(Inst); + } + [[nodiscard]] decltype(auto) getFunctionName(ByConstRef Fun) const { + static_assert(is_string_like_v); + return self().getFunctionNameImpl(Fun); + } + [[nodiscard]] decltype(auto) + getDemangledFunctionName(ByConstRef Fun) const { + static_assert( + is_string_like_v); + return self().getDemangledFunctionNameImpl(Fun); + } + void print(ByConstRef Fun, llvm::raw_ostream &OS) const { + self().printImpl(Fun, OS); + } + [[nodiscard]] nlohmann::json getAsJson(ByConstRef Fun) const { + return self().getAsJsonImpl(Fun); + } + +private: + Derived &self() noexcept { return static_cast(*this); } + const Derived &self() const noexcept { + return static_cast(*this); + } +}; + +template +// NOLINTNEXTLINE(readability-identifier-naming) +constexpr bool is_cfg_v = is_crtp_base_of_v + &&std::is_same_v + &&std::is_same_v; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H diff --git a/include/phasar/PhasarLLVM/ControlFlow/ICFG.h b/include/phasar/PhasarLLVM/ControlFlow/ICFG.h deleted file mode 100644 index c5dc3b01bd..0000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/ICFG.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * 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 and others - *****************************************************************************/ - -/* - * ICFG.h - * - * Created on: 17.08.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_ICFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_ICFG_H_ - -#include -#include -#include -#include - -#include "llvm/ADT/DenseMap.h" -#include "llvm/Support/raw_ostream.h" - -#include "nlohmann/json.hpp" - -#include "phasar/PhasarLLVM/ControlFlow/CFG.h" - -namespace psr { - -enum class CallGraphAnalysisType { -#define ANALYSIS_SETUP_CALLGRAPH_TYPE(NAME, CMDFLAG, TYPE) TYPE, -#include "phasar/PhasarLLVM/Utils/AnalysisSetups.def" - Invalid -}; - -std::string toString(const CallGraphAnalysisType &CGA); - -CallGraphAnalysisType toCallGraphAnalysisType(const std::string &S); - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const CallGraphAnalysisType &CGA); - -template class ICFG : public virtual CFG { - -protected: - std::vector GlobalInitializers; - - virtual void collectGlobalCtors() = 0; - - virtual void collectGlobalDtors() = 0; - - virtual void collectGlobalInitializers() = 0; - - virtual void collectRegisteredDtors() = 0; - -public: - ~ICFG() override = default; - - [[nodiscard]] virtual std::set getAllFunctions() const = 0; - - [[nodiscard]] virtual F getFunction(const std::string &Fun) const = 0; - - [[nodiscard]] virtual bool isIndirectFunctionCall(N Stmt) const = 0; - - [[nodiscard]] virtual bool isVirtualFunctionCall(N Stmt) const = 0; - - [[nodiscard]] virtual std::set allNonCallStartNodes() const = 0; - - [[nodiscard]] virtual std::set getCalleesOfCallAt(N Stmt) const = 0; - - [[nodiscard]] virtual std::set getCallersOf(F Fun) const = 0; - - [[nodiscard]] virtual std::set getCallsFromWithin(F Fun) const = 0; - - [[nodiscard]] virtual std::set getReturnSitesOfCallAt(N Stmt) const = 0; - - [[nodiscard]] const std::vector &getGlobalInitializers() const { - return GlobalInitializers; - } - - using CFG::print; // tell the compiler we wish to have both prints - virtual void print(llvm::raw_ostream &OS = llvm::outs()) const = 0; - - using CFG::getAsJson; // tell the compiler we wish to have both prints - [[nodiscard]] virtual nlohmann::json getAsJson() const = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h b/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h new file mode 100644 index 0000000000..680a4e3932 --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h @@ -0,0 +1,133 @@ +/****************************************************************************** + * 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_CONTROLFLOW_ICFGBASE_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H + +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" +#include "phasar/Utils/TypeTraits.h" + +#include "nlohmann/json.hpp" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +template class ICFGBase { +public: + using n_t = typename CFGTraits::n_t; + using f_t = typename CFGTraits::f_t; + + ICFGBase() noexcept { + static_assert(is_crtp_base_of_v, + "An ICFG must also be a CFG"); + } + + /// Returns an iterable range of all function definitions or declarations in + /// the ICFG + [[nodiscard]] decltype(auto) getAllFunctions() const { + return self().getAllFunctionsImpl(); + } + + /// returns the function definition or declaration with the given name. If + /// ther eis no such function, returns a default constructed f_t (nullptr for + /// pointers). + [[nodiscard]] f_t getFunction(llvm::StringRef Fun) const { + return self().getFunctionImpl(Fun); + } + + /// Returns true, iff the given instruction is a call-site where the callee is + /// called via a function-pointer or another kind of virtual call. + /// NOTE: Trivial cases where a bitcast of a function is called may still + /// count as indirect call. + [[nodiscard]] bool isIndirectFunctionCall(ByConstRef Inst) const { + return self().isIndirectFunctionCallImpl(Inst); + } + /// Returns true, iff the given instruction is a call-site where the callee is + /// called via virtual dispatch. NOTE: Here, a class-hierarchy is required and + /// a simple function-pointer is not sufficient. + [[nodiscard]] bool isVirtualFunctionCall(ByConstRef Inst) const { + return self().isVirtualFunctionCallImpl(Inst); + } + /// Returns an iterable range of all instructions in all functions of the ICFG + /// that are neither call-sites nor start-points of a function + [[nodiscard]] decltype(auto) allNonCallStartNodes() const { + static_assert( + is_iterable_over_v); + return self().allNonCallStartNodesImpl(); + } + /// 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 { + 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); + } + /// Returns an iterable range of all call-instruction in the given function + [[nodiscard]] decltype(auto) getCallsFromWithin(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getCallsFromWithinImpl(Fun); + } + /// Returns an iterable range of all return-sites of the given + /// call-instruction. Often the same as getSuccsOf. NOTE: This function is + /// typically called in a hot part of the analysis and should therefore be + /// very fast + [[nodiscard]] decltype(auto) + getReturnSitesOfCallAt(ByConstRef Inst) const { + static_assert( + is_iterable_over_v); + 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); + } + /// Returns the underlying call-graph as JSON + [[nodiscard]] nlohmann::json getAsJson() const { + return self().getAsJsonImpl(); + } + +private: + Derived &self() noexcept { return static_cast(*this); } + const Derived &self() const noexcept { + return static_cast(*this); + } +}; + +/// True, iff ICF is a proper instantiation of ICFGBase with n_t and f_t taken +/// from the given analysis-Domain +template +// NOLINTNEXTLINE(readability-identifier-naming) +constexpr bool is_icfg_v = is_crtp_base_of_v + &&std::is_same_v + &&std::is_same_v; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h index b106413515..6d9b9c6b6b 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h @@ -1,26 +1,16 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 Philipp Schubert. * All rights reserved. This program and the accompanying materials are made * available under the terms of LICENSE.txt. * * Contributors: - * Philipp Schubert and others + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -/* - * LLVMBasedBackwardCFG.h - * - * Created on: 07.06.2017 - * Author: philipp - */ - #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDCFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDCFG_H_ -#include -#include -#include - +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" namespace llvm { @@ -30,36 +20,43 @@ class Instruction; namespace psr { -class LLVMBasedBackwardCFG : public LLVMBasedCFG { -public: - LLVMBasedBackwardCFG() = default; - - ~LLVMBasedBackwardCFG() override = default; - - [[nodiscard]] std::vector - getPredsOf(const llvm::Instruction *Inst) const override; +class ProjectIRDB; +class LLVMBasedBackwardCFG; - [[nodiscard]] std::vector - getSuccsOf(const llvm::Instruction *Inst) const override; +class LLVMBasedBackwardCFG + : public detail::LLVMBasedCFGImpl { + friend CFGBase; - [[nodiscard]] std::set - getStartPointsOf(const llvm::Function *Fun) const override; + using base_t = detail::LLVMBasedCFGImpl; - [[nodiscard]] std::set - getExitPointsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] bool isExitInst(const llvm::Instruction *Inst) const override; - - [[nodiscard]] bool isStartPoint(const llvm::Instruction *Inst) const override; - - [[nodiscard]] bool - isFallThroughSuccessor(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; - - [[nodiscard]] bool - isBranchTarget(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; +public: + LLVMBasedBackwardCFG(bool IgnoreDbgInstructions = true) noexcept; + LLVMBasedBackwardCFG(const ProjectIRDB &IRDB, + bool IgnoreDbgInstructions = true); + +private: + [[nodiscard]] f_t getFunctionOfImpl(n_t Inst) const noexcept; + [[nodiscard]] llvm::SmallVector getPredsOfImpl(n_t Inst) const; + [[nodiscard]] llvm::SmallVector getSuccsOfImpl(n_t Inst) const; + [[nodiscard]] std::vector> + getAllControlFlowEdgesImpl(f_t Fun) const; + + [[nodiscard]] llvm::SmallVector getStartPointsOfImpl(f_t Fun) const; + [[nodiscard]] llvm::SmallVector getExitPointsOfImpl(f_t Fun) const; + + [[nodiscard]] bool isExitInstImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isStartPointImpl(n_t Inst) const noexcept; + + [[nodiscard]] bool isFallThroughSuccessorImpl(n_t Inst, + n_t Succ) const noexcept; + [[nodiscard]] bool isBranchTargetImpl(n_t Inst, n_t Succ) const noexcept; + + llvm::DenseMap + BackwardRets; + llvm::DenseMap + BackwardRetToFunction; }; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h index 2fc0f81582..61571a8d1a 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h @@ -1,140 +1,73 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 Philipp Schubert. * All rights reserved. This program and the accompanying materials are made * available under the terms of LICENSE.txt. * * Contributors: - * Philipp Schubert and others + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDICFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDICFG_H_ -#include -#include -#include -#include -#include -#include -#include - -#include "llvm/IR/LLVMContext.h" - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/Utils/Soundness.h" +#include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" -namespace llvm { -class Instruction; -class Function; -class Module; -class Instruction; -class BitCastInst; -} // namespace llvm +#include "llvm/IR/LLVMContext.h" namespace psr { -class Resolver; -class ProjectIRDB; -class LLVMTypeHierarchy; -class LLVMPointsToGraph; +class LLVMBasedICFG; -class LLVMBasedBackwardsICFG - : public ICFG, - public virtual LLVMBasedBackwardCFG { -private: - LLVMBasedICFG &ForwardICFG; - static inline const std::unique_ptr LLVMBackwardRetCTX = - std::make_unique(); +class LLVMBasedBackwardICFG : public LLVMBasedBackwardCFG, + public ICFGBase { + friend ICFGBase; class LLVMBackwardRet { private: - const llvm::ReturnInst *Instance; + const llvm::ReturnInst *Instance = nullptr; public: - LLVMBackwardRet() - : Instance(llvm::ReturnInst::Create(*LLVMBackwardRetCTX)){}; - [[nodiscard]] const llvm::ReturnInst *getInstance() const { + LLVMBackwardRet(llvm::LLVMContext &Ctx) + : Instance(llvm::ReturnInst::Create(Ctx)){}; + [[nodiscard]] const llvm::ReturnInst *getInstance() const noexcept { return Instance; } }; - std::unordered_map BackwardRets; - llvm::DenseMap - BackwardRetToFunction; - -public: - LLVMBasedBackwardsICFG(LLVMBasedICFG &ICFG); - - ~LLVMBasedBackwardsICFG() override = default; - - std::set getAllFunctions() const override; - - bool isIndirectFunctionCall(const llvm::Instruction *Stmt) const override; - - bool isVirtualFunctionCall(const llvm::Instruction *Stmt) const override; - - const llvm::Function *getFunction(const std::string &Fun) const override; - - std::set - getCalleesOfCallAt(const llvm::Instruction *N) const override; - - std::set - getCallersOf(const llvm::Function *M) const override; - - std::set - getCallsFromWithin(const llvm::Function *M) const override; - - std::set - getReturnSitesOfCallAt(const llvm::Instruction *N) const override; - std::set allNonCallStartNodes() const override; + using CFGBase::print; + using ICFGBase::print; - [[nodiscard]] const llvm::Function * - getFunctionOf(const llvm::Instruction *Stmt) const override; + using CFGBase::getAsJson; + using ICFGBase::getAsJson; - [[nodiscard]] std::vector - getPredsOf(const llvm::Instruction *Stmt) const override; - - [[nodiscard]] std::vector - getSuccsOf(const llvm::Instruction *Stmt) const override; - - [[nodiscard]] std::set - getExitPointsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] bool isExitInst(const llvm::Instruction *Stmt) const override; - - void mergeWith(const LLVMBasedBackwardsICFG &Other); - - using LLVMBasedBackwardCFG::print; // tell the compiler we wish to have both - // prints - void print(llvm::raw_ostream &OS) const override; - - void printAsDot(llvm::raw_ostream &OS) const; - - using LLVMBasedBackwardCFG::getAsJson; // tell the compiler we wish to have - // both prints - nlohmann::json getAsJson() const override; - - unsigned getNumOfVertices(); - - unsigned getNumOfEdges(); - - std::vector getDependencyOrderedFunctions(); +public: + LLVMBasedBackwardICFG(LLVMBasedICFG *ForwardICFG); private: - void createBackwardRets(); - -protected: - void collectGlobalCtors() override; - - void collectGlobalDtors() override; - - void collectGlobalInitializers() override; + [[nodiscard]] FunctionRange getAllFunctionsImpl() const; + [[nodiscard]] f_t getFunctionImpl(llvm::StringRef Fun) const; + + [[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; + + llvm::LLVMContext BackwardRetsCtx; + llvm::DenseMap BackwardRets; + llvm::DenseMap + BackwardRetToFunction; - void collectRegisteredDtors() override; + LLVMBasedICFG *ForwardICFG{}; }; - } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBiDiICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBiDiICFG.h deleted file mode 100644 index f9ff3b7295..0000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBiDiICFG.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBIDIICFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBIDIICFG_H_ - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h index a26c694aa0..d1d1954336 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h @@ -1,133 +1,115 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 Philipp Schubert. * All rights reserved. This program and the accompanying materials are made * available under the terms of LICENSE.txt. * * Contributors: - * Philipp Schubert and others + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -/* - * LLVMBasedCFG.h - * - * Created on: 07.06.2017 - * Author: philipp - */ - #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDCFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDCFG_H_ -#include -#include -#include - -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Function.h" - -#include "phasar/PhasarLLVM/ControlFlow/CFG.h" -#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" #include "nlohmann/json.hpp" -namespace psr { - -class LLVMBasedCFG - : public virtual CFG { -public: - LLVMBasedCFG(bool IgnoreDbgInstructions = true) - : IgnoreDbgInstructions(IgnoreDbgInstructions) {} - - ~LLVMBasedCFG() override = default; - - [[nodiscard]] const llvm::Function * - getFunctionOf(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::vector - getPredsOf(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::vector - getSuccsOf(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::vector< - std::pair> - getAllControlFlowEdges(const llvm::Function *Fun) const override; - - [[nodiscard]] std::vector - getAllInstructionsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] std::set - getStartPointsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] std::set - getExitPointsOf(const llvm::Function *Fun) const override; +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instructions.h" - [[nodiscard]] bool isCallSite(const llvm::Instruction *Inst) const override; +namespace llvm { +class Function; +} // namespace llvm - [[nodiscard]] bool isExitInst(const llvm::Instruction *Inst) const override; - - [[nodiscard]] bool isStartPoint(const llvm::Instruction *Inst) const override; +namespace psr { +class LLVMBasedCFG; +class LLVMBasedBackwardCFG; - [[nodiscard]] bool isFieldLoad(const llvm::Instruction *Inst) const override; +template <> struct CFGTraits { + using n_t = const llvm::Instruction *; + using f_t = const llvm::Function *; +}; - [[nodiscard]] bool isFieldStore(const llvm::Instruction *Inst) const override; +template <> struct CFGTraits : CFGTraits {}; - [[nodiscard]] bool - isFallThroughSuccessor(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; +namespace detail { +template class LLVMBasedCFGImpl : public CFGBase { + friend CFGBase; + friend class LLVMBasedBackwardCFG; - [[nodiscard]] bool - isBranchTarget(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; +public: + using typename CFGBase::n_t; + using typename CFGBase::f_t; - [[nodiscard]] bool - isHeapAllocatingFunction(const llvm::Function *Fun) const override; + [[nodiscard]] bool getIgnoreDbgInstructions() const noexcept { + return IgnoreDbgInstructions; + } - [[nodiscard]] bool - isSpecialMemberFunction(const llvm::Function *Fun) const override; +protected: + LLVMBasedCFGImpl(bool IgnoreDbgInstructions = true) noexcept + : IgnoreDbgInstructions(IgnoreDbgInstructions) {} + bool IgnoreDbgInstructions = false; + + [[nodiscard]] f_t getFunctionOfImpl(n_t Inst) const noexcept; + [[nodiscard]] llvm::SmallVector getPredsOfImpl(n_t Inst) const; + [[nodiscard]] llvm::SmallVector getSuccsOfImpl(n_t Inst) const; + [[nodiscard]] std::vector> + getAllControlFlowEdgesImpl(f_t Fun) const; + [[nodiscard]] auto getAllInstructionsOfImpl(f_t Fun) const { + return llvm::map_range(llvm::instructions(Fun), + [](const llvm::Instruction &Inst) { return &Inst; }); + } + [[nodiscard]] llvm::SmallVector getStartPointsOfImpl(f_t Fun) const; + [[nodiscard]] llvm::SmallVector getExitPointsOfImpl(f_t Fun) const; + [[nodiscard]] bool isCallSiteImpl(n_t Inst) const noexcept { + return llvm::isa(Inst); + } + [[nodiscard]] bool isExitInstImpl(n_t Inst) const noexcept { + return llvm::isa(Inst); + } + [[nodiscard]] bool isStartPointImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isFieldLoadImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isFieldStoreImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isFallThroughSuccessorImpl(n_t Inst, + n_t Succ) const noexcept; + [[nodiscard]] bool isBranchTargetImpl(n_t Inst, n_t Succ) const noexcept; + [[nodiscard]] bool isHeapAllocatingFunctionImpl(f_t Fun) const; + [[nodiscard]] bool isSpecialMemberFunctionImpl(f_t Fun) const { + return this->getSpecialMemberFunctionType(Fun) != + SpecialMemberFunctionType{}; + } [[nodiscard]] SpecialMemberFunctionType - getSpecialMemberFunctionType(const llvm::Function *Fun) const override; - - [[nodiscard]] std::string - getStatementId(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::string - getFunctionName(const llvm::Function *Fun) const override; - - [[nodiscard]] std::string - getDemangledFunctionName(const llvm::Function *Fun) const override; + getSpecialMemberFunctionTypeImpl(f_t Fun) const; + [[nodiscard]] std::string getStatementIdImpl(n_t Inst) const; + [[nodiscard]] auto getFunctionNameImpl(f_t Fun) const { + return Fun->getName(); + } + [[nodiscard]] std::string getDemangledFunctionNameImpl(f_t Fun) const; + void printImpl(f_t Fun, llvm::raw_ostream &OS) const { OS << *Fun; } + [[nodiscard]] nlohmann::json getAsJsonImpl(f_t /*Fun*/) const { return ""; } +}; +} // namespace detail - void print(const llvm::Function *Fun, - llvm::raw_ostream &OS = llvm::outs()) const override; +class LLVMBasedCFG : public detail::LLVMBasedCFGImpl { + friend CFGBase; + friend class LLVMBasedBackwardCFG; - [[nodiscard]] nlohmann::json - getAsJson(const llvm::Function *Fun) const override; +public: + LLVMBasedCFG(bool IgnoreDbgInstructions = true) noexcept + : detail::LLVMBasedCFGImpl(IgnoreDbgInstructions) {} [[nodiscard]] nlohmann::json exportCFGAsJson(const llvm::Function *F) const; - [[nodiscard]] nlohmann::json exportCFGAsSourceCodeJson(const llvm::Function *F) const; - -protected: - // Ignores debug instructions in control flow if set to true. - const bool IgnoreDbgInstructions; - - struct SourceCodeInfoWithIR : public SourceCodeInfo { - std::string IR; - }; - - friend void from_json(const nlohmann::json &J, // NOLINT - SourceCodeInfoWithIR &Info); - friend void to_json(nlohmann::json &J, // NOLINT - const SourceCodeInfoWithIR &Info); - - /// Used by export(I)CFGAsJson - static SourceCodeInfoWithIR - getFirstNonEmpty(llvm::BasicBlock::const_iterator &It, - llvm::BasicBlock::const_iterator End); - static SourceCodeInfoWithIR getFirstNonEmpty(const llvm::BasicBlock *BB); }; +extern template class detail::LLVMBasedCFGImpl; +extern template class detail::LLVMBasedCFGImpl; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 784fd3d264..fab1dffb30 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -17,329 +17,165 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "boost/container/flat_set.hpp" -#include "boost/graph/adjacency_list.hpp" - -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Module.h" - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" +#include "phasar/Utils/MaybeUniquePtr.h" #include "phasar/Utils/Soundness.h" -namespace llvm { -class Instruction; -class Function; -class Module; -class Instruction; -class BitCastInst; -} // namespace llvm +#include "nlohmann/json.hpp" -namespace psr { +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/raw_ostream.h" + +#include -class Resolver; +#include "phasar/Utils/MemoryResource.h" + +/// On some MAC systems, is still not fully implemented, so do +/// a workaround here + +#if HAS_MEMORY_RESOURCE +#include +#else +#include "llvm/Support/Allocator.h" +#endif + +namespace psr { +class ProjectIRDB; +class LLVMPointsToInfo; class ProjectIRDB; class LLVMTypeHierarchy; -class LLVMBasedICFG - : public ICFG, - public virtual LLVMBasedCFG { - friend class LLVMBasedBackwardsICFG; +class LLVMBasedICFG; +template <> struct CFGTraits : CFGTraits {}; - using GlobalCtorTy = std::multimap; - using GlobalDtorTy = std::multimap>; +class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { + friend ICFGBase; -private: - ProjectIRDB &IRDB; - CallGraphAnalysisType CGType; - Soundness S; - bool UserTHInfos = true; - bool UserPTInfos = true; - LLVMTypeHierarchy *TH; - LLVMPointsToInfo *PT; - std::unique_ptr Res; - llvm::DenseSet VisitedFunctions; - std::unordered_set UserEntryPoints; - - GlobalCtorTy GlobalCtors; - GlobalDtorTy GlobalDtors; - - llvm::Function *GlobalCleanupFn = nullptr; - - llvm::SmallDenseMap - GlobalRegisteredDtorsCaller; - - // The worklist for direct callee resolution. - std::vector FunctionWL; - - // Map indirect calls to the number of possible targets found for it. Fixpoint - // is not reached when more targets are found. - llvm::DenseMap IndirectCalls; - // The VertexProperties for our call-graph. - struct VertexProperties { - const llvm::Function *F = nullptr; - VertexProperties() = default; - VertexProperties(const llvm::Function *F); - [[nodiscard]] std::string getFunctionName() const; - }; + struct Builder; - // The EdgeProperties for our call-graph. - struct EdgeProperties { - const llvm::Instruction *CS = nullptr; - size_t ID = 0; - EdgeProperties() = default; - EdgeProperties(const llvm::Instruction *I); - [[nodiscard]] std::string getCallSiteAsString() const; + struct OnlyDestroyDeleter { + template void operator()(T *Data) { std::destroy_at(Data); } }; - /// Specify the type of graph to be used. - using bidigraph_t = - boost::adjacency_list; - - // Let us have some handy typedefs. - using vertex_t = boost::graph_traits::vertex_descriptor; - using vertex_iterator = boost::graph_traits::vertex_iterator; - using edge_t = boost::graph_traits::edge_descriptor; - using out_edge_iterator = boost::graph_traits::out_edge_iterator; - using in_edge_iterator = boost::graph_traits::in_edge_iterator; - - /// The call graph. - bidigraph_t CallGraph; - - /// Maps functions to the corresponding vertex id. - std::unordered_map FunctionVertexMap; - - void processFunction(const llvm::Function *F, Resolver &Resolver, - bool &FixpointReached); - - bool constructDynamicCall(const llvm::Instruction *I, Resolver &Resolver); - - std::unique_ptr - makeResolver(ProjectIRDB &IRDB, LLVMTypeHierarchy &TH, LLVMPointsToInfo &PT); - - template - static void insertGlobalCtorsDtorsImpl(MapTy &Into, const llvm::Module *M, - llvm::StringRef Fun) { - const auto *Gtors = M->getGlobalVariable(Fun); - if (Gtors == nullptr) { - return; - } - - if (const auto *FunArray = llvm::dyn_cast( - Gtors->getType()->getPointerElementType())) { - if (const auto *ConstFunArray = - llvm::dyn_cast(Gtors->getInitializer())) { - for (const auto &Op : ConstFunArray->operands()) { - if (const auto *FunDesc = llvm::dyn_cast(Op)) { - auto *Fun = llvm::dyn_cast(FunDesc->getOperand(1)); - const auto *Prio = - llvm::dyn_cast(FunDesc->getOperand(0)); - if (Fun && Prio) { - auto PrioInt = size_t(Prio->getLimitedValue(SIZE_MAX)); - Into.emplace(PrioInt, Fun); - } - } - } - } - } - } - - llvm::Function *buildCRuntimeGlobalDtorsModel(llvm::Module &M); - const llvm::Function *buildCRuntimeGlobalCtorsDtorsModel(llvm::Module &M); - - struct dependency_visitor; - public: static constexpr llvm::StringLiteral GlobalCRuntimeModelName = "__psrCRuntimeGlobalCtorsModel"; - /** - * Why a multimap? A given instruction might have multiple target functions. - * For example, if the points-to analysis indicates that a pointer could - * be for multiple different types. - */ - using OutEdgesAndTargets = std::unordered_multimap; - - LLVMBasedICFG(ProjectIRDB &IRDB, CallGraphAnalysisType CGType, - const std::set &EntryPoints = {}, - LLVMTypeHierarchy *TH = nullptr, LLVMPointsToInfo *PT = nullptr, - Soundness S = Soundness::Soundy, bool IncludeGlobals = true); - - LLVMBasedICFG(const LLVMBasedICFG &ICF); - - LLVMBasedICFG &operator=(const LLVMBasedICFG &) = delete; - - ~LLVMBasedICFG() override; - - [[nodiscard]] const llvm::Function *getFirstGlobalCtorOrNull() const; - - [[nodiscard]] const llvm::Function *getLastGlobalDtorOrNull() const; - - /** - * \return all of the functions in the IRDB, this may include some not in the - * callgraph - */ - [[nodiscard]] std::set - getAllFunctions() const override; - - /** - * A boost flat_set is used here because we already have the functions in - * order, so building it is fast since we can always add to the end. We get - * the performance and space benefits of array-backed storage and all the - * functionality of a set. - * - * \return all of the functions which are represented by a vertex in the - * callgraph. - */ - [[nodiscard]] boost::container::flat_set - getAllVertexFunctions() const; - - bool isIndirectFunctionCall(const llvm::Instruction *N) const override; - - bool isVirtualFunctionCall(const llvm::Instruction *N) const override; - - [[nodiscard]] const llvm::Function * - getFunction(const std::string &Fun) const override; - - /** - * Essentially the same as `getCallsFromWithin`, but uses the callgraph - * data directly. - * \return all call sites within a given method. - */ - std::vector - getOutEdges(const llvm::Function *Fun) const; - - /** - * For the supplied function, get all the output edge Instructions and - * the corresponding Function. This pulls data directly from the callgraph. - * - * \return the edges and the target function for each edge. - */ - OutEdgesAndTargets getOutEdgeAndTarget(const llvm::Function *Fun) const; - - /** - * Removes all edges found for the given instruction within the - * sourceFunction. \return number of edges removed - */ - size_t removeEdges(const llvm::Function *F, const llvm::Instruction *Inst); - - /** - * Removes the vertex for the given function. - * CAUTION: does not remove edges, invoking this on a function with - * IN or OUT edges is a bad idea. - * \return true iff the vertex was found and removed. - */ - bool removeVertex(const llvm::Function *Fun); - - /** - * \return the total number of in edges to the vertex representing this - * Function. - */ - size_t getCallerCount(const llvm::Function *Fun) const; - - /** - * \return all callee methods for a given call that might be called. - */ - [[nodiscard]] std::set - getCalleesOfCallAt(const llvm::Instruction *N) const override; - - void forEachCalleeOfCallAt( - const llvm::Instruction *I, - llvm::function_ref Callback) const; - - /** - * \return all caller statements/nodes of a given method. - */ - [[nodiscard]] std::set - getCallersOf(const llvm::Function *Fun) const override; - - /** - * \return all call sites within a given method. - */ - [[nodiscard]] std::set - getCallsFromWithin(const llvm::Function *Fun) const override; - - [[nodiscard]] std::set - getReturnSitesOfCallAt(const llvm::Instruction *N) const override; - - [[nodiscard]] std::set - allNonCallStartNodes() const override; - - void mergeWith(const LLVMBasedICFG &Other); - - [[nodiscard]] CallGraphAnalysisType getCallGraphAnalysisType() const; - - using LLVMBasedCFG::print; // tell the compiler we wish to have both prints - void print(llvm::raw_ostream &OS = llvm::outs()) const override; - - void printAsDot(llvm::raw_ostream &OS = llvm::outs(), - bool PrintEdgeLabels = true) const; - - void printInternalPTGAsDot(llvm::raw_ostream &OS = llvm::outs()) const; - - using LLVMBasedCFG::getAsJson; // tell the compiler we wish to have both - // prints - [[nodiscard]] nlohmann::json getAsJson() const override; - - void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; - - /// Create an IR based JSON export of the whole ICFG. + /// Constructs the ICFG based on the given IRDB and the entry-points using a + /// fixpoint iteration. This may take a long time. /// - /// Note: The exported JSON contains a list of all edges in this ICFG - [[nodiscard]] nlohmann::json exportICFGAsJson() const; - - /// Create a JSON export of the whole ICFG similar to exportICFGAsJson() - /// enriched with source-code information on every edge and ignoring debug - /// instructions - [[nodiscard]] nlohmann::json exportICFGAsSourceCodeJson() const; + /// \param IRDB The IR code where the ICFG should be based on. Must not be + /// nullptr. + /// \param CGType The analysis kind to use for call-graph resolution + /// \param EntryPoints The names of the functions to start with when + /// incrementally building up the ICFG. For whole-program analysis of an + /// executable use {"main"}. + /// \param TH The type-hierarchy implementation to use. Will be constructed + /// on-the-fly if nullptr, but required + /// \param PT The points-to implementation to use. Will be constructed + /// on-the-fly if nullptr, but required + /// \param S The soundness level to expect from the analysis. Currently unused + /// \param IncludeGlobals Properly include global constructors/destructors + /// into the ICFG, if true. Requires to generate artificial functions into the + /// IRDB. True by default + explicit LLVMBasedICFG(ProjectIRDB *IRDB, CallGraphAnalysisType CGType, + llvm::ArrayRef EntryPoints = {}, + LLVMTypeHierarchy *TH = nullptr, + LLVMPointsToInfo *PT = nullptr, + Soundness S = Soundness::Soundy, + bool IncludeGlobals = true); + + ~LLVMBasedICFG(); + + LLVMBasedICFG(const LLVMBasedICFG &) = delete; + LLVMBasedICFG &operator=(const LLVMBasedICFG &) = delete; - [[nodiscard]] unsigned getNumOfVertices() const; + LLVMBasedICFG(LLVMBasedICFG &&) noexcept = delete; + LLVMBasedICFG &operator=(LLVMBasedICFG &&) noexcept = delete; - [[nodiscard]] unsigned getNumOfEdges() const; + /// Exports the whole ICFG (not only the call-graph) as DOT. + /// + /// \param WithSourceCodeInfo If true, not only contains the LLVM instructions + /// as labels, but source-code information as well (e.g. function name, line + /// no, col no, src-line). + [[nodiscard]] std::string + exportICFGAsDot(bool WithSourceCodeInfo = true) const; + /// Similar to exportICFGAsDot, but exports the ICFG as JSON instead + [[nodiscard]] nlohmann::json + exportICFGAsJson(bool WithSourceCodeInfo = true) const; - std::vector getDependencyOrderedFunctions(); + /// 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]] const llvm::Function * - getRegisteredDtorsCallerOrNull(const llvm::Module *Mod); + /// Gets the underlying IRDB + [[nodiscard]] ProjectIRDB *getIRDB() const noexcept { return IRDB; } - template void forEachGlobalCtor(Fn &&F) const { - for (auto [Prio, Fun] : GlobalCtors) { - std::invoke(F, static_cast(Fun)); - } - } + using CFGBase::print; + using ICFGBase::print; - template void forEachGlobalDtor(Fn &&F) const { - for (auto [Prio, Fun] : GlobalDtors) { - std::invoke(F, static_cast(Fun)); - } - } + using CFGBase::getAsJson; + using ICFGBase::getAsJson; -protected: - void collectGlobalCtors() final; +private: + [[nodiscard]] FunctionRange getAllFunctionsImpl() const; + [[nodiscard]] f_t getFunctionImpl(llvm::StringRef Fun) const; + + [[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]] 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 - void collectGlobalDtors() final; + llvm::DenseMap, + OnlyDestroyDeleter>> + CalleesAt; + llvm::DenseMap, + OnlyDestroyDeleter>> + CallersOf; - void collectGlobalInitializers() final; + llvm::SmallVector VertexFunctions; - void collectRegisteredDtors() final; + ProjectIRDB *IRDB = nullptr; + MaybeUniquePtr TH; }; - } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h index 9f5b69ee20..439374baf7 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h @@ -17,8 +17,6 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_CHARESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_CHARESOLVER_H_ -#include - #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" namespace llvm { @@ -34,6 +32,8 @@ class CHAResolver : public Resolver { ~CHAResolver() override = default; FunctionSetTy resolveVirtualCall(const llvm::CallBase *CallSite) override; + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h new file mode 100644 index 0000000000..0c73cc3a9d --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2022 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_CALLGRAPHANALYSISTYPE_H +#define PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H + +#include "llvm/ADT/StringRef.h" + +#include + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace psr { +enum class CallGraphAnalysisType { +#define ANALYSIS_SETUP_CALLGRAPH_TYPE(NAME, CMDFLAG, TYPE) TYPE, +#include "phasar/PhasarLLVM/Utils/AnalysisSetups.def" + Invalid +}; + +std::string toString(CallGraphAnalysisType CGA); + +CallGraphAnalysisType toCallGraphAnalysisType(llvm::StringRef S); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, CallGraphAnalysisType CGA); + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h index af354e37d0..8928ae04f1 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h @@ -17,20 +17,18 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_DTARESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_DTARESOLVER_H_ -#include -#include - -#include "llvm/IR/Instructions.h" - #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" #include "phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h" // To switch the TypeGraph //#include "phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h" +#include + namespace llvm { class Instruction; class CallBase; class Function; +class BitCastInst; } // namespace llvm namespace psr { @@ -64,6 +62,8 @@ class DTAResolver : public CHAResolver { FunctionSetTy resolveVirtualCall(const llvm::CallBase *CallSite) override; void otherInst(const llvm::Instruction *Inst) override; + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h index c6756c4120..dae05f3c6c 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h @@ -10,8 +10,6 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_NORESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_NORESOLVER_H_ -#include - #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" namespace llvm { @@ -46,6 +44,8 @@ class NOResolver final : public Resolver { FunctionSetTy resolveFunctionPointer(const llvm::CallBase *CallSite) override; void otherInst(const llvm::Instruction *Inst) override; + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h index 31e9300b5d..b2154ec66b 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h @@ -17,18 +17,14 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_OTFRESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_OTFRESOLVER_H_ +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" + #include #include -#include -#include #include #include -#include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/TinyPtrVector.h" - namespace llvm { class Instruction; class CallBase; @@ -71,6 +67,8 @@ class OTFResolver : public CHAResolver { static std::vector> getActualFormalPointerPairs(const llvm::CallBase *CallSite, const llvm::Function *CalleeTarget); + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h index 27bc8a1bf6..da1faeb7a6 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h @@ -17,8 +17,6 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RTARESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RTARESOLVER_H_ -#include - #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" namespace llvm { @@ -35,6 +33,8 @@ class RTAResolver : public CHAResolver { ~RTAResolver() override = default; FunctionSetTy resolveVirtualCall(const llvm::CallBase *CallSite) override; + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h index 6f51d3dc58..c2b25d2370 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h @@ -17,12 +17,12 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RESOLVER_H_ +#include "llvm/ADT/DenseSet.h" + +#include #include -#include #include -#include "llvm/ADT/DenseSet.h" - namespace llvm { class Instruction; class CallBase; @@ -33,6 +33,9 @@ class StructType; namespace psr { class ProjectIRDB; class LLVMTypeHierarchy; +class LLVMPointsToInfo; +enum class CallGraphAnalysisType; +class LLVMBasedICFG; std::optional getVFTIndex(const llvm::CallBase *CallSite); @@ -70,6 +73,12 @@ class Resolver { virtual FunctionSetTy resolveFunctionPointer(const llvm::CallBase *CallSite); virtual void otherInst(const llvm::Instruction *Inst); + + [[nodiscard]] virtual std::string str() const = 0; + + static std::unique_ptr + create(CallGraphAnalysisType Ty, ProjectIRDB *IRDB, LLVMTypeHierarchy *TH, + LLVMBasedICFG *ICF = nullptr, LLVMPointsToInfo *PT = nullptr); }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def index 917e777f22..51aa044b4f 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def +++ b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def @@ -11,12 +11,13 @@ #define SPECIAL_MEMBER_FUNCTION_TYPES(NAME, TYPE) #endif +SPECIAL_MEMBER_FUNCTION_TYPES("None", None) SPECIAL_MEMBER_FUNCTION_TYPES("Constructor", Constructor) SPECIAL_MEMBER_FUNCTION_TYPES("Destructor", Destructor) SPECIAL_MEMBER_FUNCTION_TYPES("CopyConstructor", CopyConstructor) SPECIAL_MEMBER_FUNCTION_TYPES("MoveConstructor", MoveConstructor) SPECIAL_MEMBER_FUNCTION_TYPES("CopyAssignment", CopyAssignment) SPECIAL_MEMBER_FUNCTION_TYPES("MoveAssignment", MoveAssignment) -SPECIAL_MEMBER_FUNCTION_TYPES("None", None) + #undef SPECIAL_MEMBER_FUNCTION_TYPES diff --git a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h new file mode 100644 index 0000000000..9f6e488b01 --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * 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 and others + *****************************************************************************/ + +/* + * CFG.h + * + * Created on: 07.06.2017 + * Author: philipp + */ + +#ifndef PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H +#define PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H + +#include "llvm/ADT/StringRef.h" + +#include + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace psr { + +enum class SpecialMemberFunctionType { +#define SPECIAL_MEMBER_FUNCTION_TYPES(NAME, TYPE) TYPE, +#include "phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def" +}; + +std::string toString(SpecialMemberFunctionType SMFT); + +SpecialMemberFunctionType toSpecialMemberFunctionType(llvm::StringRef SMFT); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + SpecialMemberFunctionType SMFT); +} // namespace psr + +#endif // PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h index 13cdc405b5..4fcc0a884b 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h @@ -17,6 +17,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" @@ -461,7 +462,7 @@ template class EdgeFunctions { // virtual EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) = 0; + d_t RetSiteNode, llvm::ArrayRef Callees) = 0; // // Also refer to FlowFunction::getSummaryFlowFunction() diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h index f6d4f69b9e..19ffc97be9 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h @@ -120,7 +120,7 @@ class FlowEdgeFunctionCache { std::map, FlowFunctionPtrType> CallFlowFunctionCache; std::map, FlowFunctionPtrType> ReturnFlowFunctionCache; - std::map>, FlowFunctionPtrType> + std::map, FlowFunctionPtrType> CallToRetFlowFunctionCache; // Caches for the edge functions std::map, EdgeFunctionPtrType> @@ -271,7 +271,7 @@ class FlowEdgeFunctionCache { } FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - const std::set Callees) { + llvm::ArrayRef Callees) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return flow function factory call"); @@ -283,8 +283,8 @@ class FlowEdgeFunctionCache { PHASAR_LOG_LEVEL(DEBUG, "(F) Callee's : "); for (auto callee : Callees) { PHASAR_LOG_LEVEL(DEBUG, " " << Problem.FtoString(callee)); - }); - auto Key = std::tie(CallSite, RetSite, Callees); + };) + auto Key = std::tie(CallSite, RetSite); auto SearchCallToRetFlowFunction = CallToRetFlowFunctionCache.find(Key); if (SearchCallToRetFlowFunction != CallToRetFlowFunctionCache.end()) { PHASAR_LOG_LEVEL(DEBUG, "Flow function fetched from cache"); @@ -435,7 +435,7 @@ class FlowEdgeFunctionCache { EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, - const std::set &Callees) { + llvm::ArrayRef Callees) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return edge function factory call"); diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h index 45cfdd8d12..298fca9ea5 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h @@ -17,6 +17,8 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFUNCTIONS_H_ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFUNCTIONS_H_ +#include "llvm/ADT/ArrayRef.h" + #include #include #include @@ -657,7 +659,7 @@ class FlowFunctions { // virtual FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) = 0; + llvm::ArrayRef Callees) = 0; // // May be used to encode special sementics of a given callee target (whose diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h index 2bc2da1722..d8433f49c2 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h @@ -20,11 +20,13 @@ #include #include #include +#include -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h" +#include "phasar/Utils/TypeTraits.h" namespace psr { @@ -48,7 +50,7 @@ class IDETabulationProblem using l_t = typename AnalysisDomainTy::l_t; using i_t = typename AnalysisDomainTy::i_t; - static_assert(std::is_base_of_v, i_t>, + static_assert(is_icfg_v, "Type parameter i_t must implement the ICFG interface!"); using typename EdgeFunctions::EdgeFunctionPtrType; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h index cc4920d792..6484834c26 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h @@ -17,11 +17,6 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H -#include -#include -#include - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" @@ -30,6 +25,9 @@ #include "phasar/PhasarLLVM/Utils/Printer.h" #include "phasar/Utils/Soundness.h" +#include +#include + namespace psr { struct HasNoConfigurationType; @@ -56,8 +54,8 @@ class IFDSTabulationProblem using l_t = typename AnalysisDomainTy::l_t; using i_t = typename AnalysisDomainTy::i_t; - static_assert(std::is_base_of_v, i_t>, - "I must implement the ICFG interface!"); + static_assert(is_icfg_v, + "Type parameter i_t must implement the ICFG interface!"); protected: IFDSIDESolverConfig SolverConfig; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index 157d2cca6d..1575161d71 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -219,8 +219,9 @@ class IDEExtendedTaintAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallStmt, f_t DestFun) override; @@ -237,9 +238,10 @@ class IDEExtendedTaintAnalysis n_t ExitInst, d_t ExitNode, n_t RetSite, d_t RetNode) override; - EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, - n_t RetSite, d_t RetSiteNode, - std::set Callees) override; + EdgeFunctionPtrType + getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, + d_t RetSiteNode, + llvm::ArrayRef Callees) override; EdgeFunctionPtrType getSummaryEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h index e9ccca09c6..04bf14e178 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h @@ -79,7 +79,7 @@ class IDEGeneralizedLCA : public IDETabulationProblem { std::shared_ptr> getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryFlowFunction(n_t CallStmt, f_t DestMthd) override; @@ -107,7 +107,8 @@ class IDEGeneralizedLCA : public IDETabulationProblem { std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallStmt, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h index f488cfecc2..bec22ddd5a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -794,7 +794,7 @@ class IDEInstInteractionAnalysisT inline FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t /* RetSite */, - std::set Callees) override { + llvm::ArrayRef Callees) override { // Model call to heap allocating functions (new, new[], malloc, etc.) -- // only model direct calls, though. if (Callees.size() == 1) { @@ -825,37 +825,33 @@ class IDEInstInteractionAnalysisT // behavior that is intended. In that case, we must propagate all data-flow // facts alongside the call site. bool OnlyDecls = true; + bool AllVoidRetTys = true; for (auto Callee : Callees) { if (!Callee->isDeclaration()) { OnlyDecls = false; } + if (!Callee->getReturnType()->isVoidTy()) { + AllVoidRetTys = false; + } } + struct MapFactsAlongsideCallSite : public FlowFunction { bool OnlyDecls; + bool AllVoidRetTys; const llvm::CallBase *CallSite; d_t ZeroValue; - std::set Callees; - MapFactsAlongsideCallSite(bool OnlyDecls, const llvm::CallBase *CallSite, - d_t ZeroValue, std::set Callees) - : OnlyDecls(OnlyDecls), CallSite(CallSite), ZeroValue(ZeroValue), - Callees(Callees) {} + MapFactsAlongsideCallSite(bool OnlyDecls, bool AllVoidRetTys, + const llvm::CallBase *CallSite, d_t ZeroValue) + : OnlyDecls(OnlyDecls), AllVoidRetTys(AllVoidRetTys), + CallSite(CallSite), ZeroValue(ZeroValue) {} std::set computeTargets(IDEIIAFlowFact Source) override { // There are a few things to consider, in case only declarations of // callee targets are available. if (OnlyDecls) { - auto AllVoidRetTys = [](const std::set &Callees) { - // Check if one of the callee targets returns a value. - bool AllVoidRetTys = true; - for (const auto *Callee : Callees) { - if (!Callee->getReturnType()->isVoidTy()) { - AllVoidRetTys = false; - } - } - return AllVoidRetTys; - }; - if (!AllVoidRetTys(Callees)) { + + if (!AllVoidRetTys) { // If one or more of the declaration-only targets return a value, it // must be generated from zero! if (Source == ZeroValue) { @@ -881,8 +877,8 @@ class IDEInstInteractionAnalysisT } }; return std::make_shared( - OnlyDecls, llvm::dyn_cast(CallSite), - this->getZeroValue(), Callees); + OnlyDecls, AllVoidRetTys, llvm::dyn_cast(CallSite), + this->getZeroValue()); } inline FlowFunctionPtrType @@ -1318,7 +1314,8 @@ class IDEInstInteractionAnalysisT inline std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t /* RetSite */, - d_t RetSiteNode, std::set Callees) override { + d_t RetSiteNode, + llvm::ArrayRef Callees) override { // Check if the user has registered a fact generator function l_t UserEdgeFacts = BitVectorSet(); std::set EdgeFacts; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h index a46a6e6b2c..99003782c1 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -118,8 +118,9 @@ class IDELinearConstantAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; @@ -146,7 +147,8 @@ class IDELinearConstantAnalysis std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h index 1cdd8080b8..e7917e7e85 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h @@ -62,8 +62,9 @@ class IDEProtoAnalysis : public IDETabulationProblem { FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; @@ -90,7 +91,8 @@ class IDEProtoAnalysis : public IDETabulationProblem { std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h index a25a215ae7..598d67927f 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h @@ -65,8 +65,9 @@ class IDESecureHeapPropagation FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeMthd, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestMthd) override; @@ -100,7 +101,8 @@ class IDESecureHeapPropagation std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h index 1c10581352..f2ac8c21a1 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h @@ -65,8 +65,9 @@ class IDESolverTest : public IDETabulationProblem { FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; @@ -93,7 +94,8 @@ class IDESolverTest : public IDETabulationProblem { std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETaintAnalysis.h index fd4c8a6e4f..7d2db68928 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETaintAnalysis.h @@ -68,8 +68,9 @@ class IDETaintAnalysis : public IDETabulationProblem { FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; @@ -96,7 +97,8 @@ class IDETaintAnalysis : public IDETabulationProblem { std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h index dd8a8a4269..35a8ef4d2d 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -10,19 +10,20 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" +#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" + +#include "llvm/IR/InstrTypes.h" + #include #include #include #include #include -#include "llvm/IR/InstrTypes.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace llvm { class CallBase; class Instruction; @@ -117,8 +118,9 @@ class IDETypeStateAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; @@ -145,7 +147,8 @@ class IDETypeStateAnalysis std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h index 5527342677..40cf8515dd 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h @@ -126,8 +126,9 @@ class IFDSConstAnalysis * @param CallSite Call site. * @param retSite Return site. */ - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; /** * @brief Not used for this analysis, i.e. always returning nullptr. diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h index 44271e1e21..6a732cfdf4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h @@ -68,7 +68,7 @@ class IFDSFieldSensTaintAnalysis FlowFunctionPtrType getCallToRetFlowFunction(const llvm::Instruction *CallSite, const llvm::Instruction *RetSite, - std::set Callees) override; + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(const llvm::Instruction *CallSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h index 1bb64b7523..fce9689758 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h @@ -76,9 +76,9 @@ class IFDSLinearConstantAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction( - n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h index 63d1e6ea7c..aefd3feade 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h @@ -48,8 +48,9 @@ class IFDSProtoAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h index c474ba9d00..fcaae35349 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h @@ -48,8 +48,9 @@ class IFDSSignAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h index 3a78ec309a..51b385537f 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h @@ -48,8 +48,9 @@ class IFDSSolverTest FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h index 37d14ac0b8..8f0700ba05 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -84,8 +84,9 @@ class IFDSTaintAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h index 1e4f707d92..9b1621a7c8 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h @@ -47,8 +47,9 @@ class IFDSTypeAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h index 38c835b462..803f1d641e 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h @@ -64,8 +64,9 @@ class IFDSUninitializedVariables FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h index ed670cfc7d..99096328c7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h @@ -466,8 +466,8 @@ class IDESolver // a call node; line 14... d_t d2 = Edge.factAtTarget(); EdgeFunctionPtrType f = jumpFunction(Edge); - const std::set ReturnSiteNs = ICF->getReturnSitesOfCallAt(n); - const std::set Callees = ICF->getCalleesOfCallAt(n); + const auto &ReturnSiteNs = ICF->getReturnSitesOfCallAt(n); + const auto &Callees = ICF->getCalleesOfCallAt(n); IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Possible callees:"); for (auto Callee @@ -518,7 +518,7 @@ class IDESolver ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, PAMM_SEVERITY_LEVEL::Full); // for each callee's start point(s) - std::set StartPointsOf = ICF->getStartPointsOf(SCalledProcN); + auto StartPointsOf = ICF->getStartPointsOf(SCalledProcN); if (StartPointsOf.empty()) { PHASAR_LOG_LEVEL(DEBUG, "Start points of '" + ICF->getFunctionName(SCalledProcN) + @@ -921,9 +921,8 @@ class IDESolver // Phase II(ii) // we create an array of all nodes and then dispatch fractions of this // array to multiple threads - const std::set AllNonCallStartNodes = ICF->allNonCallStartNodes(); - valueComputationTask( - {AllNonCallStartNodes.begin(), AllNonCallStartNodes.end()}); + const auto AllNonCallStartNodes = ICF->allNonCallStartNodes(); + valueComputationTask(AllNonCallStartNodes); } /// Schedules the processing of initial seeds, initiating the analysis. @@ -993,8 +992,7 @@ class IDESolver d_t d1 = Edge.factAtSource(); d_t d2 = Edge.factAtTarget(); // for each of the method's start points, determine incoming calls - const std::set StartPointsOf = - ICF->getStartPointsOf(FunctionThatNeedsSummary); + const auto StartPointsOf = ICF->getStartPointsOf(FunctionThatNeedsSummary); std::map Inc; for (n_t SP : StartPointsOf) { // line 21.1 of Naeem/Lhotak/Rodriguez @@ -1086,7 +1084,7 @@ class IDESolver // condition if (SolverConfig.followReturnsPastSeeds() && Inc.empty() && IDEProblem.isZeroValue(d1)) { - const std::set Callers = ICF->getCallersOf(FunctionThatNeedsSummary); + const auto &Callers = ICF->getCallersOf(FunctionThatNeedsSummary); for (n_t Caller : Callers) { for (n_t RetSiteC : ICF->getReturnSitesOfCallAt(Caller)) { FlowFunctionPtrType RetFunction = diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h index 1e7c58cde3..4f20e80801 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h @@ -88,8 +88,9 @@ class IFDSToIDETabulationProblem return Problem.getRetFlowFunction(CallSite, CalleeFun, ExitInst, RetSite); } - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override { + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override { return Problem.getCallToRetFlowFunction(CallSite, RetSite, Callees); } @@ -156,7 +157,7 @@ class IFDSToIDETabulationProblem std::shared_ptr> getCallToRetEdgeFunction(n_t /*CallSite*/, d_t CallNode, n_t /*ReturnSite*/, d_t /*ReturnSideNode*/, - std::set /*Callees*/) override { + llvm::ArrayRef /*Callees*/) override { if (Problem.isZeroValue(CallNode)) { return ALLBOTTOM; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h index 1cf3ed6a13..00cbfa3a37 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h @@ -21,6 +21,7 @@ #include #include +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" #include "phasar/Utils/BitVectorSet.h" @@ -42,8 +43,8 @@ class InterMonoProblem : public IntraMonoProblem { using i_t = typename AnalysisDomainTy::i_t; using mono_container_t = typename AnalysisDomainTy::mono_container_t; - static_assert(std::is_base_of_v, i_t>, - "I must implement the ICFG interface!"); + static_assert(is_icfg_v, + "Type parameter i_t must implement the ICFG interface!"); protected: const i_t *ICF; @@ -69,7 +70,7 @@ class InterMonoProblem : public IntraMonoProblem { const mono_container_t &In) = 0; virtual mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) = 0; [[nodiscard]] const i_t *getICFG() const { return ICF; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h index 40177c2d49..06863a3d66 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h @@ -22,6 +22,7 @@ #include #include +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" #include "phasar/PhasarLLVM/Utils/Printer.h" #include "phasar/Utils/BitVectorSet.h" #include "phasar/Utils/Soundness.h" @@ -49,7 +50,7 @@ class IntraMonoProblem : public NodePrinter, using c_t = typename AnalysisDomainTy::c_t; using mono_container_t = typename AnalysisDomainTy::mono_container_t; - static_assert(std::is_base_of_v, c_t>, + static_assert(is_cfg_v, "c_t must implement the CFG interface!"); using ProblemAnalysisDomain = AnalysisDomainTy; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h index 8ae4bcc976..a769b154a5 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h @@ -65,7 +65,7 @@ class InterMonoFullConstantPropagation n_t RetSite, const mono_container_t &In) override; mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) override; mono_container_t merge(const mono_container_t &Lhs, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h index 035754b30d..ba9cc39d8c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h @@ -74,7 +74,7 @@ class InterMonoSolverTest : public InterMonoProblem { n_t RetSite, const mono_container_t &In) override; mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) override; std::unordered_map initialSeeds() override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h index 80462b2f7b..0ef5b37fbd 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h @@ -77,7 +77,7 @@ class InterMonoTaintAnalysis n_t RetSite, const mono_container_t &In) override; mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) override; std::unordered_map initialSeeds() override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h index 441373c420..254ee7eec5 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h @@ -295,15 +295,18 @@ template class InterMonoSolver { auto CTXRm(Ctx); llvm::outs() << "CTXRm: " << CTXRm << '\n'; // we need to use several call- and retsites if the context is empty - std::set CallSites; - std::set RetSites; + llvm::SmallVector CallSites; + // handle empty context if (Ctx.empty()) { - CallSites = ICF->getCallersOf(ICF->getFunctionOf(Src)); + const auto &Callers = ICF->getCallersOf(ICF->getFunctionOf(Src)); + CallSites.append(Callers.begin(), Callers.end()); } else { // handle context containing at least one element - CallSites.insert(CTXRm.pop_back()); + CallSites.push_back(CTXRm.pop_back()); } + + std::set RetSites; // retrieve the possible return sites for each call for (auto CallSite : CallSites) { auto RetSitesPerCall = ICF->getReturnSitesOfCallAt(CallSite); diff --git a/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h b/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h index 2e9b276780..bce6d47d34 100644 --- a/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h +++ b/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h @@ -23,17 +23,16 @@ #include #include +#include "phasar/Utils/MemoryResource.h" + /// On some MAC systems, is still not fully implemented, so do /// a workaround here -#if !defined(__has_include) || __has_include() -#define HAS_MEMORY_RESOURCE 1 +#if HAS_MEMORY_RESOURCE #include #else -#define HAS_MEMORY_RESOURCE 0 #include "llvm/Support/RecyclingAllocator.h" #endif - namespace llvm { class Value; } // namespace llvm diff --git a/include/phasar/PhasarLLVM/Utils/ByRef.h b/include/phasar/PhasarLLVM/Utils/ByRef.h new file mode 100644 index 0000000000..4573956b93 --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/ByRef.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * 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_UTILS_BYREF_H +#define PHASAR_PHASARLLVM_UTILS_BYREF_H + +#include + +namespace psr { +template +using ByConstRef = std::conditional_t, + T, const T &>; +template +using ByMoveRef = std::conditional_t, + T, T &&>; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_BYREF_H diff --git a/include/phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h b/include/phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h new file mode 100644 index 0000000000..abdc5b70fd --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * 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_UTILS_LLVMBASEDCONTAINERCONFIG_H +#define PHASAR_PHASARLLVM_UTILS_LLVMBASEDCONTAINERCONFIG_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/Module.h" + +#include + +namespace psr { + +template struct Ref2PointerConverter { + T *operator()(T &Ref) const noexcept { return std::addressof(Ref); } + const T *operator()(const T &Ref) const noexcept { + return std::addressof(Ref); + } +}; + +using FunctionRange = llvm::iterator_range>>; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_LLVMBASEDCONTAINERCONFIG_H diff --git a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h index ccca02e273..6f59fbc1d4 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h @@ -164,10 +164,11 @@ const llvm::Instruction *getNthTermInstruction(const llvm::Function *F, const llvm::StoreInst *getNthStoreInstruction(const llvm::Function *F, unsigned StoNo); -std::vector +llvm::SmallVector getAllExitPoints(const llvm::Function *F); -void appendAllExitPoints(const llvm::Function *F, - std::vector &ExitPoints); +void appendAllExitPoints( + const llvm::Function *F, + llvm::SmallVectorImpl &ExitPoints); /** * @brief Returns the LLVM Module to which the given LLVM Value belongs to. diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index 4aea2812b9..9515fe4ca0 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -17,6 +17,7 @@ #include #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" @@ -29,6 +30,8 @@ enum SeverityLevel { INVALID }; +SeverityLevel parseSeverityLevel(llvm::StringRef Str); + class Logger final { public: /** diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h new file mode 100644 index 0000000000..a755c31b44 --- /dev/null +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -0,0 +1,178 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_UTILS_MAYBEUNIQUEPTR_H_ +#define PHASAR_UTILS_MAYBEUNIQUEPTR_H_ + +#include "llvm/ADT/PointerIntPair.h" + +#include +#include +#include + +namespace psr { + +namespace detail { +template class MaybeUniquePtrBase { +protected: + struct PointerBoolPairFallback { + T *Pointer = nullptr; + bool Flag = false; + + /// Compatibility with llvm::PointerIntPair: + [[nodiscard]] T *getPointer() const noexcept { return Pointer; } + [[nodiscard]] bool getInt() const noexcept { return Flag; } + void setInt(bool Flag) noexcept { this->Flag = Flag; } + }; + + std::conditional_t<(alignof(T) > 1), llvm::PointerIntPair, + PointerBoolPairFallback> + Data{}; + + MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + MaybeUniquePtrBase() noexcept = default; +}; + +template class MaybeUniquePtrBase { +protected: + llvm::PointerIntPair Data{}; + + MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + MaybeUniquePtrBase() noexcept = default; +}; +} // namespace detail + +/// A smart-pointer, similar to std::unique_ptr that can be used as both, +/// owning and non-owning pointer. +/// +/// \tparam T The pointee type +/// \tparam RequireAlignment If true, the datastructure only works if alignof(T) +/// > 1 holds. Enables incomplete T types +template +class MaybeUniquePtr : detail::MaybeUniquePtrBase { + using detail::MaybeUniquePtrBase::Data; + +public: + MaybeUniquePtr() noexcept = default; + + MaybeUniquePtr(T *Pointer, bool Owns = false) noexcept + : detail::MaybeUniquePtrBase( + Pointer, Owns && Pointer != nullptr) {} + + MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + : MaybeUniquePtr(Owner.release(), true) {} + + template + MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + : MaybeUniquePtr(Owner.release(), true) {} + + MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept + : detail::MaybeUniquePtrBase( + std::exchange(Other.Data, {})) {} + + void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other, Data); } + + friend void swap(MaybeUniquePtr &LHS, MaybeUniquePtr &RHS) noexcept { + LHS.swap(RHS); + } + + MaybeUniquePtr &operator=(MaybeUniquePtr &&Other) noexcept { + swap(Other); + return *this; + } + + MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {Owner.release(), true}; + return *this; + } + + template + MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {Owner.release(), true}; + return *this; + } + + MaybeUniquePtr(const MaybeUniquePtr &) = delete; + MaybeUniquePtr &operator=(const MaybeUniquePtr &) = delete; + + ~MaybeUniquePtr() { + if (owns()) { + delete Data.getPointer(); + Data = {}; + } + } + + [[nodiscard]] T *get() noexcept { return Data.getPointer(); } + [[nodiscard]] const T *get() const noexcept { return Data.getPointer(); } + + [[nodiscard]] T *operator->() noexcept { return get(); } + [[nodiscard]] const T *operator->() const noexcept { return get(); } + + [[nodiscard]] T &operator*() noexcept { + assert(get() != nullptr); + return *get(); + } + [[nodiscard]] const T &operator*() const noexcept { + assert(get() != nullptr); + return *get(); + } + + T *release() noexcept { + Data.setInt(false); + return Data.getPointer(); + } + + void reset() noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {}; + } + + [[nodiscard]] bool owns() const noexcept { + return Data.getInt() && Data.getPointer(); + } + + 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 { + return !(LHS == RHS); + } + + 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 { + return !(LHS == RHS); + } + + 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 { + return !(LHS == RHS); + } + + explicit operator bool() const noexcept { + return Data.getPointer() != nullptr; + } +}; + +} // namespace psr + +#endif // PHASAR_UTILS_MAYBEUNIQUEPTR_H_ diff --git a/include/phasar/Utils/MemoryResource.h b/include/phasar/Utils/MemoryResource.h new file mode 100644 index 0000000000..886e373d89 --- /dev/null +++ b/include/phasar/Utils/MemoryResource.h @@ -0,0 +1,10 @@ +/// On some MAC systems, is still not fully implemented, so do +/// a workaround here + +#ifndef HAS_MEMORY_RESOURCE +#if !defined(__has_include) || __has_include() +#define HAS_MEMORY_RESOURCE 1 +#else +#define HAS_MEMORY_RESOURCE 0 +#endif +#endif diff --git a/include/phasar/Utils/Soundness.h b/include/phasar/Utils/Soundness.h index 9a1357dfd6..914f79fb14 100644 --- a/include/phasar/Utils/Soundness.h +++ b/include/phasar/Utils/Soundness.h @@ -10,8 +10,14 @@ #ifndef PHASAR_UTILS_SOUNDNESS_H_ #define PHASAR_UTILS_SOUNDNESS_H_ +#include "llvm/ADT/StringRef.h" + #include +namespace llvm { +class raw_ostream; +} // namespace llvm + namespace psr { enum class Soundness { @@ -20,11 +26,11 @@ enum class Soundness { Invalid }; -std::string toString(const Soundness &S); +std::string toString(Soundness S); -Soundness toSoundness(const std::string &S); +Soundness toSoundness(llvm::StringRef S); -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Soundness &S); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Soundness S); } // namespace psr diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 6f1ee8281f..7edecd282c 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 #include #include #include @@ -25,9 +26,9 @@ namespace detail { template struct is_iterable : public std::false_type {}; // NOLINT template -struct is_iterable().begin()), - decltype(std::declval().end())>> +struct is_iterable().begin()), + decltype(std::declval().end())>> : public std::true_type {}; template struct is_pair : public std::false_type {}; // NOLINT @@ -83,11 +84,37 @@ struct has_setIFDSIDESolverConfig< T, decltype(std::declval().setIFDSIDESolverConfig( std::declval()))> : std::true_type {}; +template