From 8914e0e5fb2eb872b0fd9ec32881a815c2d7de47 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 10 Feb 2025 18:47:20 +0100 Subject: [PATCH 01/17] Add SVF dependency + make the LLVMBasedAliasAnalysis polymorphic to allow injecting the SVF analysis --- .clang-tidy | 2 + CMakeLists.txt | 12 ++ config.h.in | 2 + include/phasar/PhasarLLVM/Pointer.h | 2 +- .../PhasarLLVM/Pointer/AliasAnalysisView.h | 83 +++++++++++ .../PhasarLLVM/Pointer/LLVMAliasGraph.h | 6 +- .../phasar/PhasarLLVM/Pointer/LLVMAliasSet.h | 9 +- include/phasar/Pointer/AliasAnalysisType.def | 2 + lib/CMakeLists.txt | 3 + lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp | 22 +++ lib/PhasarLLVM/Pointer/CMakeLists.txt | 9 +- lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp | 36 ++--- lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp | 43 ++---- .../Pointer/LLVMBasedAliasAnalysis.cpp | 67 ++++++--- .../Pointer/LLVMBasedAliasAnalysis.h | 44 +++--- lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt | 24 +++ lib/PhasarLLVM/Pointer/SVF/InitSVF.h | 5 + .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 140 ++++++++++++++++++ .../Pointer/SVF/SVFBasedAliasAnalysis.h | 25 ++++ .../Pointer/external/CMakeLists.txt | 2 + unittests/PhasarLLVM/Pointer/CMakeLists.txt | 12 +- .../PhasarLLVM/Pointer/SVFAliasSetTest.cpp | 36 +++++ 22 files changed, 480 insertions(+), 106 deletions(-) create mode 100644 include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h create mode 100644 lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp rename {include/phasar => lib}/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h (56%) create mode 100644 lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt create mode 100644 lib/PhasarLLVM/Pointer/SVF/InitSVF.h create mode 100644 lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp create mode 100644 lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.h create mode 100644 lib/PhasarLLVM/Pointer/external/CMakeLists.txt create mode 100644 unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp diff --git a/.clang-tidy b/.clang-tidy index 54f04105c..e7611438e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -27,10 +27,12 @@ Checks: '-*, -cppcoreguidelines-init-variables, -cppcoreguidelines-macro-usage, -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-avoid-c-arrays, bugprone-*, -bugprone-easily-swappable-parameters, modernize-*, -modernize-use-trailing-return-type, + -modernize-avoid-c-arrays, performance-*, clang-analyzer-* ' diff --git a/CMakeLists.txt b/CMakeLists.txt index c9d6409c9..40f41f8fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,6 +315,18 @@ endif() include(add_llvm) add_llvm() +# SVF +option(PHASAR_USE_SVF "Use SVF for more options in alias analysis (default is OFF)" OFF) +if(PHASAR_USE_SVF) + find_package(SVF REQUIRED CONFIG) + message(STATUS "Found SVF ${SVF_VERSION}") + + if (NOT PHASAR_USE_Z3) + message(WARNING "SVF requires Z3. Set PHASAR_USE_Z3=ON") + set(PHASAR_USE_Z3 ON) + endif() +endif() + # Z3 Solver if(PHASAR_IN_TREE) set (PHASAR_USE_Z3 OFF) diff --git a/config.h.in b/config.h.in index 253f05f86..ba6fec474 100644 --- a/config.h.in +++ b/config.h.in @@ -11,4 +11,6 @@ #cmakedefine PHASAR_HAS_SQLITE +#cmakedefine PHASAR_USE_SVF + #endif /* PHASAR_CONFIG_CONFIG_H */ diff --git a/include/phasar/PhasarLLVM/Pointer.h b/include/phasar/PhasarLLVM/Pointer.h index 220567251..75b932a82 100644 --- a/include/phasar/PhasarLLVM/Pointer.h +++ b/include/phasar/PhasarLLVM/Pointer.h @@ -10,10 +10,10 @@ #ifndef PHASAR_PHASARLLVM_POINTER_H #define PHASAR_PHASARLLVM_POINTER_H +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" -#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" #include "phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h" #include "phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h" diff --git a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h new file mode 100644 index 000000000..6e14bde3c --- /dev/null +++ b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h @@ -0,0 +1,83 @@ +/****************************************************************************** + * Copyright (c) 2025 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_POINTER_ALIASANALYSISVIEW_H +#define PHASAR_PHASARLLVM_POINTER_ALIASANALYSISVIEW_H + +#include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/AliasResult.h" + +#include + +namespace llvm { +class Value; +class DataLayout; +class Function; +} // namespace llvm + +namespace psr { +class LLVMProjectIRDB; + +class FunctionAliasView { +public: + using AliasCallbackTy = AliasResult (*)(void *, const llvm::Value *, + const llvm::Value *, + const llvm::DataLayout &); + + [[nodiscard]] inline AliasResult alias(const llvm::Value *V, + const llvm::Value *Rep, + const llvm::DataLayout &DL) { + return Alias(Context, V, Rep, DL); + } + + constexpr FunctionAliasView(void *Context, AliasCallbackTy Alias) noexcept + : Context(Context), Alias(Alias) {} + +private: + void *Context{}; + AliasCallbackTy Alias{}; +}; + +class AliasAnalysisView { +public: + constexpr AliasAnalysisView(AliasAnalysisType PATy) noexcept : PATy(PATy) {} + + virtual ~AliasAnalysisView() = default; + + [[nodiscard]] FunctionAliasView getAAResults(const llvm::Function *F) { + assert(F != nullptr); + return doGetAAResults(F); + } + + void erase(llvm::Function *F) noexcept { + assert(F != nullptr); + doErase(F); + } + + void clear() noexcept { doClear(); } + + [[nodiscard]] constexpr AliasAnalysisType + getPointerAnalysisType() const noexcept { + return PATy; + }; + + [[nodiscard]] static std::unique_ptr + create(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy); + +private: + virtual FunctionAliasView doGetAAResults(const llvm::Function *F) = 0; + virtual void doErase(llvm::Function *F) noexcept = 0; + virtual void doClear() noexcept = 0; + + AliasAnalysisType PATy{}; +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_ALIASANALYSISVIEW_H diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h index 83c22dbef..a38a0feec 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h @@ -11,8 +11,9 @@ #define PHASAR_PHASARLLVM_POINTER_LLVMALIASGRAPH_H_ #include "phasar/Config/Configuration.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" -#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" #include "phasar/Pointer/AliasInfoBase.h" #include "phasar/Pointer/AliasInfoTraits.h" #include "phasar/Pointer/AliasSetOwner.h" @@ -23,6 +24,7 @@ #include "boost/graph/adjacency_list.hpp" #include "nlohmann/json.hpp" +#include #include #include #include @@ -263,7 +265,7 @@ class [[deprecated("Use LLVMAliasSet Instead")]] LLVMAliasGraph ValueVertexMapT ValueVertexMap; /// Keep track of what has already been merged into this points-to graph. std::unordered_set AnalyzedFunctions; - LLVMBasedAliasAnalysis PTA; + std::unique_ptr PTA; AliasSetOwner::memory_resource_type MRes; AliasSetOwner Owner{&MRes}; diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h index 92644c828..5b6190021 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h @@ -10,8 +10,8 @@ #ifndef PHASAR_PHASARLLVM_POINTER_LLVMALIASSET_H #define PHASAR_PHASARLLVM_POINTER_LLVMALIASSET_H +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasSetData.h" -#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" #include "phasar/Pointer/AliasInfoBase.h" #include "phasar/Pointer/AliasInfoTraits.h" #include "phasar/Pointer/AliasResult.h" @@ -24,6 +24,7 @@ #include "nlohmann/json.hpp" +#include #include namespace llvm { @@ -72,7 +73,7 @@ class LLVMAliasSet : public AnalysisPropertiesMixin, }; [[nodiscard]] inline AliasAnalysisType getAliasAnalysisType() const noexcept { - return PTA.getPointerAnalysisType(); + return PTA->getPointerAnalysisType(); }; [[nodiscard]] AliasResult alias(const llvm::Value *V1, const llvm::Value *V2, @@ -150,12 +151,12 @@ class LLVMAliasSet : public AnalysisPropertiesMixin, const llvm::GlobalObject *VG) const; /// Utility function used by computeFunctionsAliasSet(...) - void addPointer(llvm::AAResults &AA, const llvm::DataLayout &DL, + void addPointer(FunctionAliasView AA, const llvm::DataLayout &DL, const llvm::Value *V, std::vector &Reps); [[nodiscard]] static BoxedPtr getEmptyAliasSet(); - LLVMBasedAliasAnalysis PTA; + std::unique_ptr PTA; llvm::DenseSet AnalyzedFunctions; AliasSetOwner::memory_resource_type MRes; diff --git a/include/phasar/Pointer/AliasAnalysisType.def b/include/phasar/Pointer/AliasAnalysisType.def index 93c3599d7..9664e49ac 100644 --- a/include/phasar/Pointer/AliasAnalysisType.def +++ b/include/phasar/Pointer/AliasAnalysisType.def @@ -15,5 +15,7 @@ ALIAS_ANALYSIS_TYPE(Basic, "basic", "Basic LLVM alias resolving based on simple, ALIAS_ANALYSIS_TYPE(CFLSteens, "cflsteens", "Steensgaard-style alias analysis (equality-based)") ALIAS_ANALYSIS_TYPE(CFLAnders, "cflanders", "Andersen-style alias analysis (subset-based) (default)") ALIAS_ANALYSIS_TYPE(PointsTo, "points-to", "Alias-information based on (external) points-to information") +ALIAS_ANALYSIS_TYPE(SVFDDA, "svf-dda", "Alias-information based on AVF's ContextDDA analysis. Requires SVF.") +ALIAS_ANALYSIS_TYPE(SVFVFS, "svf-vfs", "Alias-information based on AVF's VersionedFlowSensitive analysis. Requires SVF.") #undef ALIAS_ANALYSIS_TYPE diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 5cb0b04e8..ffe1291f3 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -42,6 +42,9 @@ endif() if(SQLite3_FOUND) list(APPEND PHASAR_LINK_LIBS phasar_db) endif() +if(PHASAR_USE_SVF) + list(APPEND PHASAR_LINK_LIBS phasar_llvm_pointer_svf) +endif() add_phasar_library(phasar ${PHASAR_DYNLIB_KIND} FILES diff --git a/lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp b/lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp new file mode 100644 index 000000000..8c97e491b --- /dev/null +++ b/lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp @@ -0,0 +1,22 @@ +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" + +#include "LLVMBasedAliasAnalysis.h" +#include "SVF/SVFBasedAliasAnalysis.h" + +#include + +using namespace psr; + +std::unique_ptr +AliasAnalysisView::create(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, + AliasAnalysisType PATy) { + switch (PATy) { + case AliasAnalysisType::SVFDDA: + return createSVFDDAAnalysis(IRDB); + case AliasAnalysisType::SVFVFS: + return createSVFVFSAnalysis(IRDB); + default: + return std::make_unique(IRDB, UseLazyEvaluation, + PATy); + } +} diff --git a/lib/PhasarLLVM/Pointer/CMakeLists.txt b/lib/PhasarLLVM/Pointer/CMakeLists.txt index 35cabf8af..f9cb819b0 100644 --- a/lib/PhasarLLVM/Pointer/CMakeLists.txt +++ b/lib/PhasarLLVM/Pointer/CMakeLists.txt @@ -1,4 +1,4 @@ -file(GLOB_RECURSE POINTER_SRC *.h *.cpp) +file(GLOB POINTER_SRC *.cpp TypeGraphs/*.cpp) add_phasar_library(phasar_llvm_pointer ${POINTER_SRC} @@ -19,3 +19,10 @@ add_phasar_library(phasar_llvm_pointer LINK_PRIVATE ${Boost_LIBRARIES} ) + +add_subdirectory(external) + +if(PHASAR_USE_SVF) + add_subdirectory(SVF) + target_link_libraries(phasar_llvm_pointer PRIVATE phasar_llvm_pointer_svf) +endif() diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp index 26a0acac8..c52f85c80 100644 --- a/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMAliasGraph.cpp @@ -10,9 +10,10 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" -#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Pointer/AliasAnalysisType.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/NlohmannLogging.h" #include "phasar/Utils/PAMMMacros.h" @@ -20,16 +21,15 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/IR/Constants.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" +#include "LLVMBasedAliasAnalysis.h" #include "boost/graph/copy.hpp" #include "boost/graph/depth_first_search.hpp" -#include "boost/graph/graph_utility.hpp" #include "boost/graph/graphviz.hpp" using namespace std; @@ -136,7 +136,8 @@ std::string LLVMAliasGraph::EdgeProperties::getValueAsString() const { LLVMAliasGraph::LLVMAliasGraph(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType /*PATy*/) - : PTA(IRDB, UseLazyEvaluation) {} + : PTA(AliasAnalysisView::create(IRDB, UseLazyEvaluation, + AliasAnalysisType::Basic)) {} void LLVMAliasGraph::computeAliasGraph(const llvm::Value *V) { // FIXME when fixed in LLVM @@ -152,7 +153,7 @@ void LLVMAliasGraph::computeAliasGraph(llvm::Function *F) { PAMM_GET_INSTANCE; PHASAR_LOG_LEVEL(DEBUG, "Analyzing function: " << F->getName()); AnalyzedFunctions.insert(F); - llvm::AAResults &AA = *PTA.getAAResults(F); + auto AA = PTA->getAAResults(F); bool EvalAAMD = true; // taken from llvm/Analysis/AliasAnalysisEvaluator.cpp @@ -214,29 +215,16 @@ void LLVMAliasGraph::computeAliasGraph(llvm::Function *F) { // iterate over the worklist, and run the full (n^2)/2 disambiguations const auto MapEnd = ValueVertexMap.end(); for (auto I1 = ValueVertexMap.begin(); I1 != MapEnd; ++I1) { - llvm::Type *I1ElTy = - !I1->first->getType()->isOpaquePointerTy() - ? I1->first->getType()->getNonOpaquePointerElementType() - : nullptr; - const uint64_t I1Size = I1ElTy && I1ElTy->isSized() - ? DL.getTypeStoreSize(I1ElTy) - : llvm::MemoryLocation::UnknownSize; for (auto I2 = std::next(I1); I2 != MapEnd; ++I2) { - llvm::Type *I2ElTy = - !I2->first->getType()->isOpaquePointerTy() - ? I2->first->getType()->getNonOpaquePointerElementType() - : nullptr; - const uint64_t I2Size = I2ElTy && I2ElTy->isSized() - ? DL.getTypeStoreSize(I2ElTy) - : llvm::MemoryLocation::UnknownSize; - switch (AA.alias(I1->first, I1Size, I2->first, I2Size)) { - case llvm::AliasResult::NoAlias: + + switch (AA.alias(I1->first, I2->first, DL)) { + case AliasResult::NoAlias: break; - case llvm::AliasResult::MayAlias: // no break + case AliasResult::MayAlias: // no break [[fallthrough]]; - case llvm::AliasResult::PartialAlias: // no break + case AliasResult::PartialAlias: // no break [[fallthrough]]; - case llvm::AliasResult::MustAlias: + case AliasResult::MustAlias: boost::add_edge(I1->second, I2->second, PAG); break; default: diff --git a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp index 40b95feaa..b544e295f 100644 --- a/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMAliasSet.cpp @@ -10,10 +10,12 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/AliasResult.h" #include "phasar/Utils/BoxedPointer.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/NlohmannLogging.h" @@ -43,10 +45,7 @@ #include #include #include -#include -#include #include -#include #include namespace psr { @@ -57,7 +56,7 @@ template class AliasSetOwner; LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy) - : PTA(*IRDB, UseLazyEvaluation, PATy) { + : PTA(AliasAnalysisView::create(*IRDB, UseLazyEvaluation, PATy)) { assert(IRDB != nullptr); auto NumGlobals = IRDB->getNumGlobals(); @@ -97,7 +96,7 @@ LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB, bool UseLazyEvaluation, LLVMAliasSet::LLVMAliasSet(LLVMProjectIRDB *IRDB, const nlohmann::json &SerializedPTS) - : PTA(*IRDB, true) { + : PTA(AliasAnalysisView::create(*IRDB, true, AliasAnalysisType::Basic)) { assert(IRDB != nullptr); // Assume, we already have validated the json schema @@ -315,33 +314,13 @@ bool LLVMAliasSet::intraIsReachableAllocationSiteTy( return false; } -static bool mayAlias(llvm::AAResults &AA, const llvm::DataLayout &DL, +static bool mayAlias(FunctionAliasView AA, const llvm::DataLayout &DL, const llvm::Value *V, const llvm::Value *Rep) { - assert(V->getType()->isPointerTy()); - assert(Rep->getType()->isPointerTy()); - auto *ElTy = !V->getType()->isOpaquePointerTy() - ? V->getType()->getNonOpaquePointerElementType() - : nullptr; - auto *RepElTy = !Rep->getType()->isOpaquePointerTy() - ? Rep->getType()->getNonOpaquePointerElementType() - : nullptr; - - auto VSize = ElTy && ElTy->isSized() ? DL.getTypeStoreSize(ElTy) - : llvm::MemoryLocation::UnknownSize; - - auto RepSize = RepElTy && RepElTy->isSized() - ? DL.getTypeStoreSize(RepElTy) - : llvm::MemoryLocation::UnknownSize; - - if (AA.alias(V, VSize, Rep, RepSize) != llvm::AliasResult::NoAlias) { - return true; - } - - return false; + return AA.alias(V, Rep, DL) != AliasResult::NoAlias; } -void LLVMAliasSet::addPointer(llvm::AAResults &AA, const llvm::DataLayout &DL, +void LLVMAliasSet::addPointer(FunctionAliasView AA, const llvm::DataLayout &DL, const llvm::Value *V, std::vector &Reps) { llvm::SmallVector ToMerge; @@ -454,13 +433,13 @@ void LLVMAliasSet::computeFunctionsAliasSet(llvm::Function *F) { PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMAliasSet", "Analyzing function: " << F->getName()); - llvm::AAResults &AA = *PTA.getAAResults(F); + auto AA = PTA->getAAResults(F); bool EvalAAMD = true; const llvm::DataLayout &DL = F->getParent()->getDataLayout(); - auto addPointer = [this, &AA, &DL](const llvm::Value *V, // NOLINT - std::vector &Reps) { + auto addPointer = [this, AA, &DL](const llvm::Value *V, // NOLINT + std::vector &Reps) { return this->addPointer(AA, DL, V, Reps); }; @@ -547,7 +526,7 @@ void LLVMAliasSet::computeFunctionsAliasSet(llvm::Function *F) { } // we no longer need the LLVM representation - PTA.erase(F); + PTA->erase(F); } AliasResult LLVMAliasSet::alias(const llvm::Value *V1, const llvm::Value *V2, diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp index 4473b19fe..27330b200 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp @@ -7,11 +7,13 @@ * Philipp Schubert and others *****************************************************************************/ -#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" +#include "LLVMBasedAliasAnalysis.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" #include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/AliasResult.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" @@ -38,41 +40,34 @@ using namespace psr; namespace psr { -struct LLVMBasedAliasAnalysis::Impl { - llvm::PassBuilder PB{}; - llvm::FunctionAnalysisManager FAM{}; - llvm::FunctionPassManager FPM{}; -}; - bool LLVMBasedAliasAnalysis::hasAliasInfo(const llvm::Function &Fun) const { return AAInfos.find(&Fun) != AAInfos.end(); } void LLVMBasedAliasAnalysis::computeAliasInfo(llvm::Function &Fun) { - assert(PImpl != nullptr); - llvm::PreservedAnalyses PA = PImpl->FPM.run(Fun, PImpl->FAM); - llvm::AAResults &AAR = PImpl->FAM.getResult(Fun); + llvm::PreservedAnalyses PA = FPM.run(Fun, FAM); + llvm::AAResults &AAR = FAM.getResult(Fun); AAInfos.insert(std::make_pair(&Fun, &AAR)); } -void LLVMBasedAliasAnalysis::erase(llvm::Function *F) noexcept { +void LLVMBasedAliasAnalysis::doErase(llvm::Function *F) noexcept { // after we clear all stuff, we need to set it up for the next function-wise // analysis AAInfos.erase(F); - PImpl->FAM.clear(*F, F->getName()); + FAM.clear(*F, F->getName()); } -void LLVMBasedAliasAnalysis::clear() noexcept { +void LLVMBasedAliasAnalysis::doClear() noexcept { AAInfos.clear(); - PImpl->FAM.clear(); + FAM.clear(); } LLVMBasedAliasAnalysis::LLVMBasedAliasAnalysis(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy) - : PImpl(new Impl{}), PATy(PATy) { + : AliasAnalysisView(PATy) { - PImpl->FAM.registerPass([&] { + FAM.registerPass([&] { llvm::AAManager AA; switch (PATy) { case AliasAnalysisType::CFLAnders: @@ -95,7 +90,7 @@ LLVMBasedAliasAnalysis::LLVMBasedAliasAnalysis(LLVMProjectIRDB &IRDB, AA.registerFunctionAnalysis(); return AA; }); - PImpl->PB.registerFunctionAnalyses(PImpl->FAM); + PB.registerFunctionAnalyses(FAM); if (!UseLazyEvaluation) { for (auto &F : *IRDB.getModule()) { @@ -108,4 +103,42 @@ LLVMBasedAliasAnalysis::LLVMBasedAliasAnalysis(LLVMProjectIRDB &IRDB, LLVMBasedAliasAnalysis::~LLVMBasedAliasAnalysis() = default; +static AliasResult translateAAResult(llvm::AliasResult Res) noexcept { + switch (Res) { + case llvm::AliasResult::NoAlias: + return AliasResult::NoAlias; + case llvm::AliasResult::MayAlias: + return AliasResult::MayAlias; + case llvm::AliasResult::PartialAlias: + return AliasResult::PartialAlias; + case llvm::AliasResult::MustAlias: + return AliasResult::MustAlias; + } +} + +AliasResult LLVMBasedAliasAnalysis::aliasImpl(void *AACtx, const llvm::Value *V, + const llvm::Value *Rep, + const llvm::DataLayout &DL) { + + assert(V->getType()->isPointerTy()); + assert(Rep->getType()->isPointerTy()); + + auto *AA = static_cast(AACtx); + auto *ElTy = !V->getType()->isOpaquePointerTy() + ? V->getType()->getNonOpaquePointerElementType() + : nullptr; + auto *RepElTy = !Rep->getType()->isOpaquePointerTy() + ? Rep->getType()->getNonOpaquePointerElementType() + : nullptr; + + auto VSize = ElTy && ElTy->isSized() ? DL.getTypeStoreSize(ElTy) + : llvm::MemoryLocation::UnknownSize; + + auto RepSize = RepElTy && RepElTy->isSized() + ? DL.getTypeStoreSize(RepElTy) + : llvm::MemoryLocation::UnknownSize; + + return translateAAResult(AA->alias(V, VSize, Rep, RepSize)); +} + } // namespace psr diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h similarity index 56% rename from include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h rename to lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h index 1195da6c8..f6aed7805 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h @@ -10,9 +10,12 @@ #ifndef PHASAR_PHASARLLVM_POINTER_LLVMBASEDALIASANALYSIS_H_ #define PHASAR_PHASARLLVM_POINTER_LLVMBASEDALIASANALYSIS_H_ +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/AliasResult.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Passes/PassBuilder.h" namespace llvm { class Value; @@ -25,47 +28,42 @@ namespace psr { class LLVMProjectIRDB; -class LLVMBasedAliasAnalysis { - +class LLVMBasedAliasAnalysis : public AliasAnalysisView { public: explicit LLVMBasedAliasAnalysis( LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy = AliasAnalysisType::Basic); - LLVMBasedAliasAnalysis(LLVMBasedAliasAnalysis &&) noexcept = default; - LLVMBasedAliasAnalysis & - operator=(LLVMBasedAliasAnalysis &&) noexcept = default; - - LLVMBasedAliasAnalysis(const LLVMBasedAliasAnalysis &) = delete; - LLVMBasedAliasAnalysis &operator=(const LLVMBasedAliasAnalysis &) = delete; - ~LLVMBasedAliasAnalysis(); + ~LLVMBasedAliasAnalysis() override; - [[nodiscard]] inline llvm::AAResults *getAAResults(llvm::Function *F) { +private: + FunctionAliasView doGetAAResults(const llvm::Function *F) override { if (!hasAliasInfo(*F)) { - computeAliasInfo(*F); + // NOLINTNEXTLINE - FIXME when it is fixed in LLVM + computeAliasInfo(const_cast(*F)); } - return AAInfos.lookup(F); + return createFAView(AAInfos.lookup(F)); }; - void erase(llvm::Function *F) noexcept; + void doErase(llvm::Function *F) noexcept override; - void clear() noexcept; + void doClear() noexcept override; - [[nodiscard]] inline AliasAnalysisType - getPointerAnalysisType() const noexcept { - return PATy; - }; + static AliasResult aliasImpl(void *, const llvm::Value *, const llvm::Value *, + const llvm::DataLayout &); + [[nodiscard]] constexpr FunctionAliasView + createFAView(llvm::AAResults *AAR) noexcept { + return {AAR, &aliasImpl}; + } -private: [[nodiscard]] bool hasAliasInfo(const llvm::Function &Fun) const; void computeAliasInfo(llvm::Function &Fun); // -- data members - - struct Impl; - std::unique_ptr PImpl; - AliasAnalysisType PATy; + llvm::PassBuilder PB; + llvm::FunctionAnalysisManager FAM; + llvm::FunctionPassManager FPM; llvm::DenseMap AAInfos; }; diff --git a/lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt b/lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt new file mode 100644 index 000000000..ec59ba7f2 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt @@ -0,0 +1,24 @@ +file(GLOB_RECURSE SVF_AA_SRC *.h *.cpp) + +add_phasar_library(phasar_llvm_pointer_svf + ${SVF_AA_SRC} + + LINKS + phasar_utils + phasar_pointer + phasar_llvm_utils + phasar_llvm_db + + LLVM_LINK_COMPONENTS + Core + Support + Analysis + Passes + Demangle + + LINK_PRIVATE + SvfLLVM SvfCore ${Z3_LIBRARIES} +) + +target_include_directories(phasar_llvm_pointer_svf SYSTEM PRIVATE ${SVF_INSTALL_INCLUDE_DIR}) +target_link_directories(phasar_llvm_pointer_svf PUBLIC ${SVF_INSTALL_LIB_DIR}) diff --git a/lib/PhasarLLVM/Pointer/SVF/InitSVF.h b/lib/PhasarLLVM/Pointer/SVF/InitSVF.h new file mode 100644 index 000000000..112b1627b --- /dev/null +++ b/lib/PhasarLLVM/Pointer/SVF/InitSVF.h @@ -0,0 +1,5 @@ +#pragma once + +namespace psr { +void initializeSVF(); +} // namespace psr diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp new file mode 100644 index 000000000..72681b4d7 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -0,0 +1,140 @@ +#include "SVFBasedAliasAnalysis.h" + +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" +#include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/AliasResult.h" + +#include "DDA/ContextDDA.h" +#include "DDA/DDAClient.h" +#include "SVF-LLVM/SVFIRBuilder.h" +#include "SVFIR/SVFIR.h" +#include "SVFIR/SVFModule.h" +#include "SVFIR/SVFType.h" +#include "WPA/Andersen.h" +#include "WPA/VersionedFlowSensitive.h" + +#include +#include +#include + +namespace psr { +static constexpr psr::AliasResult +translateSVFAliasResult(SVF::AliasResult AR) noexcept { + switch (AR) { + case SVF::NoAlias: + return AliasResult::NoAlias; + case SVF::MayAlias: + return AliasResult::MayAlias; + case SVF::MustAlias: + return AliasResult::MustAlias; + case SVF::PartialAlias: + return AliasResult::PartialAlias; + } +} +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) +class SVFAliasAnalysisBase : public AliasAnalysisView { +public: + SVFAliasAnalysisBase(SVF::SVFModule *Mod, AliasAnalysisType PATy) + : AliasAnalysisView(PATy), IRBuilder(Mod), PAG(IRBuilder.build()) {} + + ~SVFAliasAnalysisBase() override { + SVF::SVFIR::releaseSVFIR(); + SVF::AndersenWaveDiff::releaseAndersenWaveDiff(); + SVF::SymbolTableInfo::releaseSymbolInfo(); + SVF::LLVMModuleSet::releaseLLVMModuleSet(); + } + +private: + void doErase(llvm::Function *F) noexcept override {} + void doClear() noexcept override {} + +protected: + SVF::SVFIRBuilder IRBuilder; + SVF::SVFIR *PAG; +}; + +class SVFVFSAnalysis : public SVFAliasAnalysisBase { +public: + SVFVFSAnalysis(SVF::SVFModule *Mod) + : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), VFS(PAG) {} + +private: + static psr::AliasResult aliasImpl(void *AACtx, const llvm::Value *V, + const llvm::Value *Rep, + const llvm::DataLayout & /*DL*/) { + auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); + auto *Nod1 = ModSet->getSVFValue(V); + auto *Nod2 = ModSet->getSVFValue(Rep); + + if (!Nod1 || !Nod2) { + return AliasResult::MayAlias; + } + + auto *AA = static_cast(AACtx); + return translateSVFAliasResult(AA->VFS.alias(Nod1, Nod2)); + } + + FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { + return {this, &aliasImpl}; + } + + SVF::VersionedFlowSensitive VFS; +}; + +class SVFDDAAnalysis : public SVFAliasAnalysisBase { +public: + SVFDDAAnalysis(SVF::SVFModule *Mod) + : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), Client(Mod) { + Client.initialise(Mod); + DDA.emplace(PAG, &Client); + DDA->initialize(); + Client.answerQueries(&*DDA); + DDA->finalize(); + } + +private: + static psr::AliasResult aliasImpl(void *AACtx, const llvm::Value *V, + const llvm::Value *Rep, + const llvm::DataLayout & /*DL*/) { + auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); + auto *Nod1 = ModSet->getSVFValue(V); + auto *Nod2 = ModSet->getSVFValue(Rep); + + if (!Nod1 || !Nod2) { + return AliasResult::MayAlias; + } + + auto *AA = static_cast(AACtx); + return translateSVFAliasResult(AA->DDA->alias(Nod1, Nod2)); + } + + FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { + return {this, &aliasImpl}; + } + + SVF::DDAClient Client; + std::optional DDA; +}; + +} // namespace psr + +static SVF::SVFModule *initSVFModule(psr::LLVMProjectIRDB &IRDB) { + auto *Mod = SVF::LLVMModuleSet::buildSVFModule(*IRDB.getModule()); + if (!Mod) { + throw std::runtime_error( + "SVF failed to create an SVFModule from an llvm::Module!"); + } + + return Mod; +} + +[[nodiscard]] auto psr::createSVFVFSAnalysis(LLVMProjectIRDB &IRDB) + -> std::unique_ptr { + return std::make_unique(initSVFModule(IRDB)); +} + +[[nodiscard]] auto psr::createSVFDDAAnalysis(LLVMProjectIRDB &IRDB) + -> std::unique_ptr { + return std::make_unique(initSVFModule(IRDB)); +} diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.h b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.h new file mode 100644 index 000000000..ec5955a0d --- /dev/null +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2025 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_POINTER_SVFBASEDALIASANALYSIS_H +#define PHASAR_PHASARLLVM_POINTER_SVFBASEDALIASANALYSIS_H + +#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" + +#include + +namespace psr { +[[nodiscard]] std::unique_ptr +createSVFVFSAnalysis(LLVMProjectIRDB &IRDB); + +[[nodiscard]] std::unique_ptr +createSVFDDAAnalysis(LLVMProjectIRDB &IRDB); +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_SVFBASEDALIASANALYSIS_H diff --git a/lib/PhasarLLVM/Pointer/external/CMakeLists.txt b/lib/PhasarLLVM/Pointer/external/CMakeLists.txt new file mode 100644 index 000000000..185b5103e --- /dev/null +++ b/lib/PhasarLLVM/Pointer/external/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GLOB_RECURSE LLVM_AA_SRC *.h *.cpp) +target_sources(phasar_llvm_pointer PRIVATE ${LLVM_AA_SRC}) diff --git a/unittests/PhasarLLVM/Pointer/CMakeLists.txt b/unittests/PhasarLLVM/Pointer/CMakeLists.txt index a8745bbbc..e120d71ca 100644 --- a/unittests/PhasarLLVM/Pointer/CMakeLists.txt +++ b/unittests/PhasarLLVM/Pointer/CMakeLists.txt @@ -1,8 +1,16 @@ -set(ControlFlowSources +set(PointerFlowSources LLVMAliasSetTest.cpp LLVMAliasSetSerializationTest.cpp ) -foreach(TEST_SRC ${ControlFlowSources}) +if (PHASAR_USE_SVF) + list(APPEND PointerFlowSources SVFAliasSetTest.cpp) +endif() + +foreach(TEST_SRC ${PointerFlowSources}) add_phasar_unittest(${TEST_SRC}) endforeach(TEST_SRC) + +if(PHASAR_USE_SVF) + target_link_libraries(SVFAliasSetTest PRIVATE phasar_llvm_pointer_svf) +endif() diff --git a/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp new file mode 100644 index 000000000..6049ab328 --- /dev/null +++ b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp @@ -0,0 +1,36 @@ + +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +using namespace psr; + +// TEST(SVFAliasSetTest, Intra_01) { +// LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + +// "pointers/basic_01_cpp_dbg.ll"); + +// SVFAliasSet AS(&IRDB); + +// const auto *V = IRDB.getInstruction(5); +// ASSERT_TRUE(V && V->getType()->isPointerTy()); + +// // auto Pts = AS.getAliasSet(V); +// } + +// TEST(SVFAliasSetTest, Call_01) { +// LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + +// "pointers/call_01_cpp_dbg.ll"); + +// SVFAliasSet AS(&IRDB); + +// const auto *V = IRDB.getInstruction(15); +// ASSERT_TRUE(V && V->getType()->isPointerTy()); + +// auto Pts = AS.getAliasSet(V); +// } + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} From 3a37d485beaa1865f9e9e7bc495dd72103fc8f61 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 10 Feb 2025 19:14:54 +0100 Subject: [PATCH 02/17] Add public interface for SVFPointsToSet --- .../PhasarLLVM/Pointer/AliasAnalysisView.h | 4 ++ .../PhasarLLVM/Pointer/SVF/SVFPointsToSet.h | 66 +++++++++++++++++++ lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp | 18 ++++- .../Pointer/LLVMBasedAliasAnalysis.cpp | 6 ++ .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 6 ++ lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp | 4 ++ 6 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h create mode 100644 lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp diff --git a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h index 6e14bde3c..b865980d7 100644 --- a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h +++ b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h @@ -71,6 +71,10 @@ class AliasAnalysisView { create(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy); private: + static std::unique_ptr + createLLVMBasedAnalysis(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, + AliasAnalysisType PATy); + virtual FunctionAliasView doGetAAResults(const llvm::Function *F) = 0; virtual void doErase(llvm::Function *F) noexcept = 0; virtual void doClear() noexcept = 0; diff --git a/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h new file mode 100644 index 000000000..8b8816ce4 --- /dev/null +++ b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * Copyright (c) 2025 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ +#ifndef PHASAR_PHASARLLVM_POINTER_SVF_SVFPOINTSTOSET_H +#define PHASAR_PHASARLLVM_POINTER_SVF_SVFPOINTSTOSET_H + +#include "phasar/Config/phasar-config.h" +#include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/PointsToInfoBase.h" + +#include "llvm/ADT/DenseSet.h" +#include "llvm/IR/Value.h" + +#ifndef PHASAR_USE_SVF +#error \ + "Don't include SVFPointsToSet.h when PhASAR is not configured to include SVF. Set the cmake variable PHASAR_USE_SVF and retry." +#endif + +namespace psr { +class LLVMProjectIRDB; +class SVFPointsToSet; + +template <> struct PointsToTraits { + using v_t = const llvm::Value *; + using n_t = const llvm::Instruction *; + using o_t = uint32_t; + + // TODO: Use a more efficient representation; maybe even one that does not + // require an expensive transformation from SVF::PointsTo + using PointsToSetTy = llvm::SmallDenseSet; + + // Not special pointer type + using PointsToSetPtrTy = PointsToSetTy; +}; + +class SVFPointsToSet : public PointsToInfoBase { + friend PointsToInfoBase; + +public: + explicit SVFPointsToSet(const LLVMProjectIRDB *IRDB, + AliasAnalysisType PAType = AliasAnalysisType::SVFVFS); + +private: + [[nodiscard]] o_t + asAbstractObjectImpl(ByConstRef Pointer) const noexcept; + + [[nodiscard]] std::optional asPointerOrNullImpl(o_t Obj) const noexcept; + + bool mayPointsToImpl(o_t Pointer, o_t Obj, n_t AtInstruction) const; + bool mayPointsToImpl(v_t Pointer, o_t Obj, n_t AtInstruction) const; + + PointsToSetPtrTy getPointsToSetImpl(o_t Pointer, n_t AtInstruction) const; + PointsToSetPtrTy getPointsToSetImpl(v_t Pointer, n_t AtInstruction) const; + + llvm::SmallVector + getInterestingPointersAtImpl(ByConstRef AtInstruction) const; +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_SVF_SVFPOINTSTOSET_H diff --git a/lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp b/lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp index 8c97e491b..d4833b8c1 100644 --- a/lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp +++ b/lib/PhasarLLVM/Pointer/AliasAnalysisView.cpp @@ -1,7 +1,10 @@ #include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" -#include "LLVMBasedAliasAnalysis.h" +#include "phasar/Config/phasar-config.h" + +#ifdef PHASAR_USE_SVF #include "SVF/SVFBasedAliasAnalysis.h" +#endif #include @@ -12,11 +15,20 @@ AliasAnalysisView::create(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy) { switch (PATy) { case AliasAnalysisType::SVFDDA: +#ifndef PHASAR_USE_SVF + throw std::runtime_error("AliasAnalysisType::SVFVFS requires SVF, which is " + "not included in your PhASAR build!"); +#else return createSVFDDAAnalysis(IRDB); +#endif case AliasAnalysisType::SVFVFS: +#ifndef PHASAR_USE_SVF + throw std::runtime_error("AliasAnalysisType::SVFDDA requires SVF, which is " + "not included in your PhASAR build!"); +#else return createSVFVFSAnalysis(IRDB); +#endif default: - return std::make_unique(IRDB, UseLazyEvaluation, - PATy); + return createLLVMBasedAnalysis(IRDB, UseLazyEvaluation, PATy); } } diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp index 27330b200..019199f71 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp @@ -141,4 +141,10 @@ AliasResult LLVMBasedAliasAnalysis::aliasImpl(void *AACtx, const llvm::Value *V, return translateAAResult(AA->alias(V, VSize, Rep, RepSize)); } +std::unique_ptr AliasAnalysisView::createLLVMBasedAnalysis( + LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy) { + return std::make_unique(IRDB, UseLazyEvaluation, + PATy); +} + } // namespace psr diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index 72681b4d7..099b9aa45 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -7,6 +7,7 @@ #include "DDA/ContextDDA.h" #include "DDA/DDAClient.h" +#include "InitSVF.h" #include "SVF-LLVM/SVFIRBuilder.h" #include "SVFIR/SVFIR.h" #include "SVFIR/SVFModule.h" @@ -32,6 +33,7 @@ translateSVFAliasResult(SVF::AliasResult AR) noexcept { return AliasResult::PartialAlias; } } + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) class SVFAliasAnalysisBase : public AliasAnalysisView { public: @@ -120,6 +122,8 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { } // namespace psr static SVF::SVFModule *initSVFModule(psr::LLVMProjectIRDB &IRDB) { + psr::initializeSVF(); + auto *Mod = SVF::LLVMModuleSet::buildSVFModule(*IRDB.getModule()); if (!Mod) { throw std::runtime_error( @@ -131,10 +135,12 @@ static SVF::SVFModule *initSVFModule(psr::LLVMProjectIRDB &IRDB) { [[nodiscard]] auto psr::createSVFVFSAnalysis(LLVMProjectIRDB &IRDB) -> std::unique_ptr { + return std::make_unique(initSVFModule(IRDB)); } [[nodiscard]] auto psr::createSVFDDAAnalysis(LLVMProjectIRDB &IRDB) -> std::unique_ptr { + return std::make_unique(initSVFModule(IRDB)); } diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp new file mode 100644 index 000000000..72d66deca --- /dev/null +++ b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp @@ -0,0 +1,4 @@ +#include "phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h" + +// TODO: Implement abstractions/pimpl for VFS and DDA analyses +// TODO: implement all the APi functions of SVFPointsToSet From 3a227dfd057e06cc0c53d1706403382b74b587b0 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 12 Feb 2025 19:13:43 +0100 Subject: [PATCH 03/17] Add SVFPointsToInfo + Fix PointsToInfoBase --- .../PhasarLLVM/Pointer/SVF/SVFPointsToSet.h | 33 ++-- include/phasar/Pointer/PointsToInfo.h | 16 -- include/phasar/Pointer/PointsToInfoBase.h | 35 ++-- include/phasar/Utils/PointerUtils.h | 27 ++++ lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp | 43 +++++ lib/PhasarLLVM/Pointer/SVF/InitSVF.h | 12 +- .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 23 +-- lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp | 153 ++++++++++++++++++ lib/Pointer/PointsToInfo.cpp | 3 +- 9 files changed, 267 insertions(+), 78 deletions(-) create mode 100644 lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp diff --git a/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h index 8b8816ce4..33ed85fb0 100644 --- a/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h +++ b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h @@ -10,8 +10,7 @@ #define PHASAR_PHASARLLVM_POINTER_SVF_SVFPOINTSTOSET_H #include "phasar/Config/phasar-config.h" -#include "phasar/Pointer/AliasAnalysisType.h" -#include "phasar/Pointer/PointsToInfoBase.h" +#include "phasar/Pointer/PointsToInfo.h" #include "llvm/ADT/DenseSet.h" #include "llvm/IR/Value.h" @@ -23,9 +22,9 @@ namespace psr { class LLVMProjectIRDB; -class SVFPointsToSet; +class SVFPointsToInfo; -template <> struct PointsToTraits { +struct SVFPointsToInfoTraits { using v_t = const llvm::Value *; using n_t = const llvm::Instruction *; using o_t = uint32_t; @@ -38,28 +37,14 @@ template <> struct PointsToTraits { using PointsToSetPtrTy = PointsToSetTy; }; -class SVFPointsToSet : public PointsToInfoBase { - friend PointsToInfoBase; +using SVFBasedPointsToInfo = PointsToInfo; +using SVFBasedPointsToInfoRef = PointsToInfoRef; -public: - explicit SVFPointsToSet(const LLVMProjectIRDB *IRDB, - AliasAnalysisType PAType = AliasAnalysisType::SVFVFS); +[[nodiscard]] SVFBasedPointsToInfo +createSVFVFSPointsToInfo(LLVMProjectIRDB &IRDB); -private: - [[nodiscard]] o_t - asAbstractObjectImpl(ByConstRef Pointer) const noexcept; - - [[nodiscard]] std::optional asPointerOrNullImpl(o_t Obj) const noexcept; - - bool mayPointsToImpl(o_t Pointer, o_t Obj, n_t AtInstruction) const; - bool mayPointsToImpl(v_t Pointer, o_t Obj, n_t AtInstruction) const; - - PointsToSetPtrTy getPointsToSetImpl(o_t Pointer, n_t AtInstruction) const; - PointsToSetPtrTy getPointsToSetImpl(v_t Pointer, n_t AtInstruction) const; - - llvm::SmallVector - getInterestingPointersAtImpl(ByConstRef AtInstruction) const; -}; +[[nodiscard]] SVFBasedPointsToInfo +createSVFDDAPointsToInfo(LLVMProjectIRDB &IRDB); } // namespace psr diff --git a/include/phasar/Pointer/PointsToInfo.h b/include/phasar/Pointer/PointsToInfo.h index 2eaf0f438..c7c0b186a 100644 --- a/include/phasar/Pointer/PointsToInfo.h +++ b/include/phasar/Pointer/PointsToInfo.h @@ -87,7 +87,6 @@ class PointsToInfoRef, ByConstRef); - std::vector (*GetInterestingPointersAt)(const void *, ByConstRef); void (*Destroy)(const void *) noexcept; // Useful for the owning variant }; @@ -120,15 +119,6 @@ class PointsToInfoRef(PT)->getPointsToSet( Pointer, AtInstruction); }, - [](const void *PT, ByConstRef AtInstruction) { - std::vector Ret; - for (ByConstRef Ptr : - static_cast(PT)->getInterestingPointersAt( - AtInstruction)) { - Ret.push_back(Ptr); - } - return Ret; - }, [](const void *PT) noexcept { delete static_cast(PT); }, @@ -201,12 +191,6 @@ class PointsToInfoRefGetPointsToSetV(PT, Pointer, AtInstruction); } - std::vector - getInterestingPointersAtImpl(ByConstRef AtInstruction) const { - assert(VT); - return VT->GetInterestingPointersAt(PT, AtInstruction); - } - // --- const void *PT{}; const VTable<> *VT{}; diff --git a/include/phasar/Pointer/PointsToInfoBase.h b/include/phasar/Pointer/PointsToInfoBase.h index 9eef7cf3a..7925ffd73 100644 --- a/include/phasar/Pointer/PointsToInfoBase.h +++ b/include/phasar/Pointer/PointsToInfoBase.h @@ -11,6 +11,7 @@ #define PHASAR_POINTER_POINTSTOINFOBASE_H #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/PointerUtils.h" #include "phasar/Utils/TypeTraits.h" #include @@ -53,12 +54,7 @@ PSR_CONCEPT is_equivalent_PointsToTraits_v = // NOLINT /// Base class of all points-to analysis implementations. Don't use this class /// directly. For a type-erased variant, use PointsToInfoRef or PointsToInfo. template class PointsToInfoBase { -public: - using v_t = typename PointsToTraits::v_t; - using n_t = typename PointsToTraits::n_t; - using o_t = typename PointsToTraits::o_t; - using PointsToSetTy = typename PointsToTraits::PointsToSetTy; - using PointsToSetPtrTy = typename PointsToTraits::PointsToSetPtrTy; + friend Derived; explicit PointsToInfoBase() noexcept { static_assert(std::is_base_of_v, @@ -66,6 +62,13 @@ template class PointsToInfoBase { "PointsToInfoBase!"); } +public: + using v_t = typename PointsToTraits::v_t; + using n_t = typename PointsToTraits::n_t; + using o_t = typename PointsToTraits::o_t; + using PointsToSetTy = typename PointsToTraits::PointsToSetTy; + using PointsToSetPtrTy = typename PointsToTraits::PointsToSetPtrTy; + /// Creates an abstract object corresponding to the given pointer [[nodiscard]] o_t asAbstractObject(ByConstRef Pointer) const noexcept { return self().asAbstractObjectImpl(Pointer); @@ -102,29 +105,21 @@ template class PointsToInfoBase { return self().getPointsToSetImpl(Pointer, AtInstruction); } - /// Gets all pointers v_t where we have non-empty points-to information at - /// this instruction - [[nodiscard]] decltype(auto) - getInterestingPointersAt(ByConstRef AtInstruction) const { - static_assert( - is_iterable_over_v< - decltype(self().getInterestingPointersAtImpl(AtInstruction)), v_t>); - return self().getInterestingPointersAtImpl(AtInstruction); - } - private: template >> - [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, + [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, ByConstRef Obj, ByConstRef AtInstruction) const { - return getPointsToSet(asAbstractObject(Pointer), AtInstruction)->count(Obj); + auto &&Pts = getPointsToSet(Pointer, AtInstruction); + return getPointerFrom(Pts)->count(Obj); } - [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, + [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, ByConstRef Obj, ByConstRef AtInstruction) const { - return getPointsToSet(Pointer, AtInstruction)->count(Obj); + return self().mayPointsTo(self().asAbstractObject(Pointer), Obj, + AtInstruction); } template +#include namespace psr { /// A simple helper function to get a raw pointer from an arbitrary pointer type /// in generic code. This overload set is extendable. +template +constexpr std::enable_if_t, T *> +getPointerFrom(T &Ref) noexcept { + return std::addressof(Ref); +} +template +constexpr std::enable_if_t, const T *> +getPointerFrom(const T &Ref) noexcept { + return std::addressof(Ref); +} +template +constexpr std::enable_if_t, T *> +getPointerFrom(T &&Ref) noexcept = delete; + template T *getPointerFrom(T *Ptr) noexcept { return Ptr; } template constexpr T *getPointerFrom(const std::unique_ptr &Ptr) noexcept { return Ptr.get(); } template +constexpr T *getPointerFrom(std::unique_ptr &Ptr) noexcept { + return Ptr.get(); +} +template constexpr T *getPointerFrom(const std::shared_ptr &Ptr) noexcept { return Ptr.get(); } template +constexpr T *getPointerFrom(std::shared_ptr &Ptr) noexcept { + return Ptr.get(); +} +template constexpr T *getPointerFrom(const llvm::IntrusiveRefCntPtr &Ptr) noexcept { return Ptr.get(); } +template +constexpr T *getPointerFrom(llvm::IntrusiveRefCntPtr &Ptr) noexcept { + return Ptr.get(); +} } // namespace psr diff --git a/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp b/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp new file mode 100644 index 000000000..acd6d5a75 --- /dev/null +++ b/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp @@ -0,0 +1,43 @@ +#include "InitSVF.h" + +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/Utils/EmptyBaseOptimizationUtils.h" + +#include "SVF-LLVM/LLVMModule.h" +#include "Util/CommandLine.h" +#include "Util/DPItem.h" +#include "Util/Options.h" + +static psr::EmptyType initializeSVFImpl() { + char EmptyStr[] = ""; + char NoAliasCheck[] = "-alias-check=false"; + char NoStat[] = "-stat=false"; + char *MockArgv[] = { + EmptyStr, + NoAliasCheck, + NoStat, + }; + OptionBase::parseOptions(std::size(MockArgv), MockArgv, "", ""); + + SVF::ContextCond::setMaxCxtLen(SVF::Options::MaxContextLen()); + SVF::ContextCond::setMaxPathLen(SVF::Options::MaxPathLen()); + + return psr::EmptyType{}; +} + +void psr::initializeSVF() { + static const auto SVFInitialized = initializeSVFImpl(); + (void)SVFInitialized; +} + +SVF::SVFModule *psr::initSVFModule(psr::LLVMProjectIRDB &IRDB) { + psr::initializeSVF(); + + auto *Mod = SVF::LLVMModuleSet::buildSVFModule(*IRDB.getModule()); + if (!Mod) { + throw std::runtime_error( + "SVF failed to create an SVFModule from an llvm::Module!"); + } + + return Mod; +} diff --git a/lib/PhasarLLVM/Pointer/SVF/InitSVF.h b/lib/PhasarLLVM/Pointer/SVF/InitSVF.h index 112b1627b..2599a3626 100644 --- a/lib/PhasarLLVM/Pointer/SVF/InitSVF.h +++ b/lib/PhasarLLVM/Pointer/SVF/InitSVF.h @@ -1,5 +1,15 @@ #pragma once +#include "llvm/Support/Compiler.h" + +namespace SVF { +class SVFModule; +} // namespace SVF + namespace psr { -void initializeSVF(); +class LLVMProjectIRDB; + +LLVM_LIBRARY_VISIBILITY void initializeSVF(); +LLVM_LIBRARY_VISIBILITY SVF::SVFModule * +initSVFModule(psr::LLVMProjectIRDB &IRDB); } // namespace psr diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index 099b9aa45..2edff9a4d 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -17,7 +17,6 @@ #include #include -#include namespace psr { static constexpr psr::AliasResult @@ -59,7 +58,11 @@ class SVFAliasAnalysisBase : public AliasAnalysisView { class SVFVFSAnalysis : public SVFAliasAnalysisBase { public: SVFVFSAnalysis(SVF::SVFModule *Mod) - : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), VFS(PAG) {} + : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), VFS(PAG) { + VFS.initialize(); + VFS.analyze(); + VFS.finalize(); + } private: static psr::AliasResult aliasImpl(void *AACtx, const llvm::Value *V, @@ -121,26 +124,14 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { } // namespace psr -static SVF::SVFModule *initSVFModule(psr::LLVMProjectIRDB &IRDB) { - psr::initializeSVF(); - - auto *Mod = SVF::LLVMModuleSet::buildSVFModule(*IRDB.getModule()); - if (!Mod) { - throw std::runtime_error( - "SVF failed to create an SVFModule from an llvm::Module!"); - } - - return Mod; -} - [[nodiscard]] auto psr::createSVFVFSAnalysis(LLVMProjectIRDB &IRDB) -> std::unique_ptr { - return std::make_unique(initSVFModule(IRDB)); + return std::make_unique(psr::initSVFModule(IRDB)); } [[nodiscard]] auto psr::createSVFDDAAnalysis(LLVMProjectIRDB &IRDB) -> std::unique_ptr { - return std::make_unique(initSVFModule(IRDB)); + return std::make_unique(psr::initSVFModule(IRDB)); } diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp index 72d66deca..096c3900b 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp @@ -1,4 +1,157 @@ #include "phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h" +#include "phasar/Pointer/PointsToInfoBase.h" + +#include "DDA/ContextDDA.h" +#include "DDA/DDAClient.h" +#include "InitSVF.h" +#include "MemoryModel/PointerAnalysis.h" +#include "SVF-LLVM/LLVMModule.h" +#include "SVF-LLVM/SVFIRBuilder.h" +#include "WPA/Andersen.h" + +#include + +namespace { +template class SVFPointsToSet; +struct DDAPointsToSetImpl; +struct VFSPointsToSetImpl; +} // namespace + +namespace psr { +template +struct PointsToTraits> : SVFPointsToInfoTraits {}; +template <> +struct PointsToTraits : SVFPointsToInfoTraits {}; +template <> +struct PointsToTraits : SVFPointsToInfoTraits {}; +} // namespace psr + +namespace { + +template +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) +class SVFPointsToSet : public psr::PointsToInfoBase> { + using base_t = psr::PointsToInfoBase>; + friend base_t; + +public: + using typename base_t::n_t; + using typename base_t::o_t; + using typename base_t::PointsToSetPtrTy; + using typename base_t::PointsToSetTy; + using typename base_t::v_t; + + SVFPointsToSet(SVF::SVFModule *Mod) + : IRBuilder(Mod), PAG(IRBuilder.build()) {} + + ~SVFPointsToSet() { + SVF::SVFIR::releaseSVFIR(); + SVF::AndersenWaveDiff::releaseAndersenWaveDiff(); + SVF::SymbolTableInfo::releaseSymbolInfo(); + SVF::LLVMModuleSet::releaseLLVMModuleSet(); + } + +private: + [[nodiscard]] constexpr Derived &self() noexcept { + return static_cast(*this); + } + [[nodiscard]] constexpr const Derived &self() const noexcept { + return static_cast(*this); + } + + [[nodiscard]] o_t + asAbstractObjectImpl(psr::ByConstRef Pointer) const noexcept { + auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); + auto *Nod = ModSet->getSVFValue(Pointer); + + // TODO: Is this the right function to call? Or better + // PAG->getObjectNode(Nod)? + return PAG->getValueNode(Nod); + } + + [[nodiscard]] std::optional asPointerOrNullImpl(o_t Obj) const noexcept { + if (const auto *Val = PAG->getObject(Obj)->getValue()) { + auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); + if (const auto *LLVMVal = ModSet->getLLVMValue(Val)) { + return LLVMVal; + } + } + + return std::nullopt; + } + + bool mayPointsToImpl(o_t Pointer, o_t Obj, n_t /*AtInstruction*/) const { + auto &PTA = self().getPTA(); + const auto &Pts = PTA.getPts(Pointer); + return Pts.test(Obj); + } + + using base_t::mayPointsToImpl; + + PointsToSetPtrTy getPointsToSetImpl(o_t Pointer, + n_t /*AtInstruction*/) const { + auto &PTA = self().getPTA(); + const auto &Pts = PTA.getPts(Pointer); + + // TODO: Should we cache this? + PointsToSetPtrTy Ret; + Ret.reserve(Pts.count()); + Ret.insert(Pts.begin(), Pts.end()); + return Ret; + } + + using base_t::getPointsToSetImpl; + +protected: + SVF::SVFIRBuilder IRBuilder; + SVF::SVFIR *PAG; +}; + // TODO: Implement abstractions/pimpl for VFS and DDA analyses // TODO: implement all the APi functions of SVFPointsToSet + +struct VFSPointsToSetImpl : SVFPointsToSet { + VFSPointsToSetImpl(SVF::SVFModule *Mod) : SVFPointsToSet(Mod), VFS(PAG) { + VFS.initialize(); + VFS.analyze(); + VFS.finalize(); + } + + [[nodiscard]] SVF::PointerAnalysis &getPTA() const noexcept { return VFS; } + + // Note: SVF is not thread-safe anyway, so this 'mutable' should not be a + // problem + mutable SVF::VersionedFlowSensitive VFS; +}; + +struct DDAPointsToSetImpl : SVFPointsToSet { + DDAPointsToSetImpl(SVF::SVFModule *Mod) : SVFPointsToSet(Mod), Client(Mod) { + Client.initialise(Mod); + DDA.emplace(PAG, &Client); + DDA->initialize(); + Client.answerQueries(&*DDA); + DDA->finalize(); + } + + [[nodiscard]] SVF::PointerAnalysis &getPTA() const noexcept { return *DDA; } + + SVF::DDAClient Client; + + // Note: SVF is not thread-safe anyway, so this 'mutable' should not be a + // problem + mutable std::optional DDA; +}; +} // namespace + +auto psr::createSVFVFSPointsToInfo(LLVMProjectIRDB &IRDB) + -> SVFBasedPointsToInfo { + return SVFBasedPointsToInfo(std::in_place_type, + psr::initSVFModule(IRDB)); +} + +auto psr::createSVFDDAPointsToInfo(LLVMProjectIRDB &IRDB) + -> SVFBasedPointsToInfo { + return SVFBasedPointsToInfo(std::in_place_type, + psr::initSVFModule(IRDB)); +} diff --git a/lib/Pointer/PointsToInfo.cpp b/lib/Pointer/PointsToInfo.cpp index df3079fce..2d51ae2a0 100644 --- a/lib/Pointer/PointsToInfo.cpp +++ b/lib/Pointer/PointsToInfo.cpp @@ -11,6 +11,7 @@ #include "phasar/Pointer/PointsToInfoBase.h" #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/PointerUtils.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/DenseSet.h" @@ -154,7 +155,7 @@ class DummyFieldSensitivePointsToAnalysis std::in_place_type); // Make sure, the template gets instantiated: - std::ignore = TEPTA1.getInterestingPointersAt(nullptr); + std::ignore = TEPTA1.getPointsToSet({}, nullptr); } template class PointsToInfoBase; From 2fe2ec8cfe5c21d7518d1e2c64b2f845a8fd126b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Wed, 26 Feb 2025 20:09:49 +0100 Subject: [PATCH 04/17] Fixes in PointsToInfo + add minimal tests --- .../PhasarLLVM/Pointer/SVF/SVFPointsToSet.h | 2 +- include/phasar/Pointer/PointsToInfo.h | 12 ++++-- include/phasar/Pointer/PointsToInfoBase.h | 4 +- .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 9 ++++ lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp | 6 +++ .../PhasarLLVM/Pointer/SVFAliasSetTest.cpp | 43 ++++++++++++------- 6 files changed, 53 insertions(+), 23 deletions(-) diff --git a/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h index 33ed85fb0..d5cb3461e 100644 --- a/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h +++ b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h @@ -33,7 +33,7 @@ struct SVFPointsToInfoTraits { // require an expensive transformation from SVF::PointsTo using PointsToSetTy = llvm::SmallDenseSet; - // Not special pointer type + // No special pointer type using PointsToSetPtrTy = PointsToSetTy; }; diff --git a/include/phasar/Pointer/PointsToInfo.h b/include/phasar/Pointer/PointsToInfo.h index c7c0b186a..013163a98 100644 --- a/include/phasar/Pointer/PointsToInfo.h +++ b/include/phasar/Pointer/PointsToInfo.h @@ -14,10 +14,10 @@ #include "phasar/Utils/ByRef.h" #include +#include #include #include #include -#include namespace psr { @@ -29,7 +29,7 @@ struct PointsToTraits> : PTATraits {}; template struct PointsToTraits> : PTATraits {}; -/// A type-erased reference to any object implementing th PointsToInfoBase +/// A type-erased reference to any object implementing the PointsToInfoBase /// interface. Use this, if your analysis is not tied to a specific points-to /// info implementation. /// @@ -154,7 +154,7 @@ class PointsToInfoRef - asPointerOrNull(ByConstRef Obj) const noexcept { + asPointerOrNullImpl(ByConstRef Obj) const noexcept { assert(VT); return VT->AsPointerOrNull(PT, Obj); } @@ -196,7 +196,7 @@ class PointsToInfoRef *VT{}; }; -/// Similar to PointsToInfoRef, but owns the held reference. Us this, if you +/// Similar to PointsToInfoRef, but owns the held reference. Use this, if you /// need to decide dynamically, which points-to info implementation to use. /// /// Implicitly convertible to PointsToInfoRef. @@ -239,6 +239,10 @@ class [[clang::trivial_abi]] PointsToInfo< : PointsToInfoRef( new ConcretePTA(std::forward(Args)...)) {} + template + PointsToInfo(std::unique_ptr PTA) + : PointsToInfoRef(PTA.release()) {} + ~PointsToInfo() noexcept { if (*this) { this->VT->Destroy(this->PT); diff --git a/include/phasar/Pointer/PointsToInfoBase.h b/include/phasar/Pointer/PointsToInfoBase.h index 7925ffd73..5a924cdb4 100644 --- a/include/phasar/Pointer/PointsToInfoBase.h +++ b/include/phasar/Pointer/PointsToInfoBase.h @@ -106,8 +106,6 @@ template class PointsToInfoBase { } private: - template >> [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, ByConstRef Obj, ByConstRef AtInstruction) const { @@ -115,6 +113,8 @@ template class PointsToInfoBase { return getPointerFrom(Pts)->count(Obj); } + template >> [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, ByConstRef Obj, ByConstRef AtInstruction) const { diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index 2edff9a4d..efae53b25 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -12,6 +12,8 @@ #include "SVFIR/SVFIR.h" #include "SVFIR/SVFModule.h" #include "SVFIR/SVFType.h" +#include "Util/DPItem.h" +#include "Util/Options.h" #include "WPA/Andersen.h" #include "WPA/VersionedFlowSensitive.h" @@ -91,6 +93,13 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { public: SVFDDAAnalysis(SVF::SVFModule *Mod) : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), Client(Mod) { + + // Initialize these parameters to their default values. + // See https://github.com/SVF-tools/SVF/blob/master/svf/lib/DDA/DDAPass.cpp + // for reference + SVF::ContextCond::setMaxCxtLen(SVF::Options::MaxContextLen()); + SVF::ContextCond::setMaxPathLen(SVF::Options::MaxPathLen()); + Client.initialise(Mod); DDA.emplace(PAG, &Client); DDA->initialize(); diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp index 096c3900b..ec020ab93 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp @@ -127,6 +127,12 @@ struct VFSPointsToSetImpl : SVFPointsToSet { struct DDAPointsToSetImpl : SVFPointsToSet { DDAPointsToSetImpl(SVF::SVFModule *Mod) : SVFPointsToSet(Mod), Client(Mod) { + // Initialize these parameters to their default values. + // See https://github.com/SVF-tools/SVF/blob/master/svf/lib/DDA/DDAPass.cpp + // for reference + SVF::ContextCond::setMaxCxtLen(SVF::Options::MaxContextLen()); + SVF::ContextCond::setMaxPathLen(SVF::Options::MaxPathLen()); + Client.initialise(Mod); DDA.emplace(PAG, &Client); DDA->initialize(); diff --git a/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp index 6049ab328..f08c34441 100644 --- a/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp +++ b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp @@ -1,34 +1,45 @@ #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" +#include "phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h" +#include "phasar/Pointer/AliasAnalysisType.h" #include "TestConfig.h" #include "gtest/gtest.h" using namespace psr; -// TEST(SVFAliasSetTest, Intra_01) { -// LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + -// "pointers/basic_01_cpp_dbg.ll"); +TEST(SVFAliasSetTest, Alias_01) { + LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + + "pointers/basic_01_cpp_dbg.ll"); -// SVFAliasSet AS(&IRDB); + LLVMAliasSet AS(&IRDB, false, AliasAnalysisType::SVFVFS); -// const auto *V = IRDB.getInstruction(5); -// ASSERT_TRUE(V && V->getType()->isPointerTy()); + const auto *V = IRDB.getInstruction(5); + ASSERT_TRUE(V && V->getType()->isPointerTy()); -// // auto Pts = AS.getAliasSet(V); -// } + const auto *Alias = IRDB.getInstruction(0); -// TEST(SVFAliasSetTest, Call_01) { -// LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + -// "pointers/call_01_cpp_dbg.ll"); + auto ASet = AS.getAliasSet(V); + LLVMAliasSet::AliasSetTy GroundTruth = {V, Alias}; + EXPECT_EQ(GroundTruth, *ASet); +} + +TEST(SVFAliasSetTest, PointsTo_01) { + LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + + "pointers/basic_01_cpp_dbg.ll"); -// SVFAliasSet AS(&IRDB); + auto PT = createSVFVFSPointsToInfo(IRDB); -// const auto *V = IRDB.getInstruction(15); -// ASSERT_TRUE(V && V->getType()->isPointerTy()); + const auto *V = IRDB.getInstruction(5); + ASSERT_TRUE(V && V->getType()->isPointerTy()); -// auto Pts = AS.getAliasSet(V); -// } + const auto *Alloc = IRDB.getInstruction(0); + + auto PSet = PT.getPointsToSet(V, V->getNextNode()); + ASSERT_EQ(1, PSet.size()); + EXPECT_EQ(Alloc, PT.asPointerOrNull(*PSet.begin())); +} int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); From d309744320906e7b3f694445bfe01c3b15b980d7 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 28 Feb 2025 19:49:47 +0100 Subject: [PATCH 05/17] Add CRTPBase utility --- include/phasar/ControlFlow/CFGBase.h | 12 ++++---- include/phasar/ControlFlow/CallGraphBase.h | 11 ++++---- include/phasar/ControlFlow/ICFGBase.h | 16 ++++------- include/phasar/Pointer/PointsToInfo.h | 5 ++-- include/phasar/Pointer/PointsToInfoBase.h | 17 ++---------- include/phasar/Utils/CRTPUtils.h | 32 ++++++++++++++++++++++ 6 files changed, 53 insertions(+), 40 deletions(-) create mode 100644 include/phasar/Utils/CRTPUtils.h diff --git a/include/phasar/ControlFlow/CFGBase.h b/include/phasar/ControlFlow/CFGBase.h index 4abfbd983..375f703bf 100644 --- a/include/phasar/ControlFlow/CFGBase.h +++ b/include/phasar/ControlFlow/CFGBase.h @@ -11,6 +11,7 @@ #define PHASAR_CONTROLFLOW_CFGBASE_H #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/CRTPUtils.h" #include "phasar/Utils/TypeTraits.h" #include "nlohmann/json.hpp" @@ -24,7 +25,10 @@ template struct CFGTraits { // using f_t }; -template class CFGBase { +template class CFGBase : public CRTPBase { + friend Derived; + using CRTPBase::self; + public: using n_t = typename CFGTraits::n_t; using f_t = typename CFGTraits::f_t; @@ -135,12 +139,6 @@ template class CFGBase { 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 diff --git a/include/phasar/ControlFlow/CallGraphBase.h b/include/phasar/ControlFlow/CallGraphBase.h index 2f2371618..67bfb0cc9 100644 --- a/include/phasar/ControlFlow/CallGraphBase.h +++ b/include/phasar/ControlFlow/CallGraphBase.h @@ -11,6 +11,7 @@ #define PHASAR_CONTROLFLOW_CALLGRAPHBASE_H #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/CRTPUtils.h" #include "phasar/Utils/TypeTraits.h" namespace psr { @@ -22,7 +23,10 @@ template struct CGTraits { /// Base class of all CallGraph implementations within phasar (currently only /// CallGraph). /// Only represents the data, not how to create it. -template class CallGraphBase { +template class CallGraphBase : public CRTPBase { + friend Derived; + using CRTPBase::self; + public: using n_t = typename CGTraits::n_t; using f_t = typename CGTraits::f_t; @@ -46,11 +50,6 @@ template class CallGraphBase { is_iterable_over_v); return self().getCallersOfImpl(Fun); } - -private: - const Derived &self() const noexcept { - return static_cast(*this); - } }; } // namespace psr diff --git a/include/phasar/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h index bbdd5b75f..d6d52083a 100644 --- a/include/phasar/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -12,6 +12,7 @@ #include "phasar/ControlFlow/CFGBase.h" #include "phasar/ControlFlow/CallGraphBase.h" +#include "phasar/Utils/CRTPUtils.h" #include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/StringRef.h" @@ -22,16 +23,14 @@ #include namespace psr { -template class ICFGBase { +template class ICFGBase : public CRTPBase { + friend Derived; + using CRTPBase::self; + 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 { @@ -122,11 +121,6 @@ template class ICFGBase { [[nodiscard]] size_t getNumCallSites() const noexcept { return self().getNumCallSitesImpl(); } - -private: - 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 diff --git a/include/phasar/Pointer/PointsToInfo.h b/include/phasar/Pointer/PointsToInfo.h index 013163a98..af2f54d58 100644 --- a/include/phasar/Pointer/PointsToInfo.h +++ b/include/phasar/Pointer/PointsToInfo.h @@ -216,12 +216,13 @@ class [[clang::trivial_abi]] PointsToInfo< PointsToInfo() noexcept = default; PointsToInfo(std::nullptr_t) noexcept {}; + PointsToInfo(const PointsToInfo &) = delete; PointsToInfo &operator=(const PointsToInfo &) = delete; + PointsToInfo(PointsToInfo &&Other) noexcept { swap(Other); } PointsToInfo &operator=(PointsToInfo &&Other) noexcept { - auto Cpy{std::move(Other)}; - swap(Cpy); + PointsToInfo(std::move(Other)).swap(*this); return *this; } diff --git a/include/phasar/Pointer/PointsToInfoBase.h b/include/phasar/Pointer/PointsToInfoBase.h index 5a924cdb4..0bb22091f 100644 --- a/include/phasar/Pointer/PointsToInfoBase.h +++ b/include/phasar/Pointer/PointsToInfoBase.h @@ -11,6 +11,7 @@ #define PHASAR_POINTER_POINTSTOINFOBASE_H #include "phasar/Utils/ByRef.h" +#include "phasar/Utils/CRTPUtils.h" #include "phasar/Utils/PointerUtils.h" #include "phasar/Utils/TypeTraits.h" @@ -53,14 +54,9 @@ PSR_CONCEPT is_equivalent_PointsToTraits_v = // NOLINT /// Base class of all points-to analysis implementations. Don't use this class /// directly. For a type-erased variant, use PointsToInfoRef or PointsToInfo. -template class PointsToInfoBase { +template class PointsToInfoBase : public CRTPBase { friend Derived; - - explicit PointsToInfoBase() noexcept { - static_assert(std::is_base_of_v, - "Invalid CRTP instantiation: Derived must inherit from " - "PointsToInfoBase!"); - } + using CRTPBase::self; public: using v_t = typename PointsToTraits::v_t; @@ -129,13 +125,6 @@ template class PointsToInfoBase { ByConstRef AtInstruction) const { return self().getPointsToSetImpl(asAbstractObject(Pointer), AtInstruction); } - - [[nodiscard]] Derived &self() noexcept { - return static_cast(*this); - } - [[nodiscard]] const Derived &self() const noexcept { - return static_cast(*this); - } }; } // namespace psr diff --git a/include/phasar/Utils/CRTPUtils.h b/include/phasar/Utils/CRTPUtils.h new file mode 100644 index 000000000..048137071 --- /dev/null +++ b/include/phasar/Utils/CRTPUtils.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2025 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_UTILS_CRTPUTILS_H +#define PHASAR_UTILS_CRTPUTILS_H + +namespace psr { +template class CRTPBase { + friend Derived; + +protected: + constexpr CRTPBase() noexcept = default; + + [[nodiscard]] constexpr Derived &self() &noexcept { + return static_cast(*this); + } + [[nodiscard]] constexpr Derived &&self() &&noexcept { + return static_cast(*this); + } + [[nodiscard]] constexpr const Derived &self() const &noexcept { + return static_cast(*this); + } +}; +} // namespace psr + +#endif // PHASAR_UTILS_CRTPUTILS_H From fb2118c1b8572046dc5c1e27f3f9e5117ff9aea1 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 28 Feb 2025 19:50:15 +0100 Subject: [PATCH 06/17] New test + some cleanup --- lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp | 3 +++ lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp | 7 ------- lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp | 11 ----------- unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp | 7 +++++++ 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp b/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp index acd6d5a75..32376f4ae 100644 --- a/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp @@ -19,6 +19,9 @@ static psr::EmptyType initializeSVFImpl() { }; OptionBase::parseOptions(std::size(MockArgv), MockArgv, "", ""); + // Initialize these parameters to their default values. + // See https://github.com/SVF-tools/SVF/blob/master/svf/lib/DDA/DDAPass.cpp + // for reference SVF::ContextCond::setMaxCxtLen(SVF::Options::MaxContextLen()); SVF::ContextCond::setMaxPathLen(SVF::Options::MaxPathLen()); diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index efae53b25..4065b313a 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -93,13 +93,6 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { public: SVFDDAAnalysis(SVF::SVFModule *Mod) : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), Client(Mod) { - - // Initialize these parameters to their default values. - // See https://github.com/SVF-tools/SVF/blob/master/svf/lib/DDA/DDAPass.cpp - // for reference - SVF::ContextCond::setMaxCxtLen(SVF::Options::MaxContextLen()); - SVF::ContextCond::setMaxPathLen(SVF::Options::MaxPathLen()); - Client.initialise(Mod); DDA.emplace(PAG, &Client); DDA->initialize(); diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp index ec020ab93..072e75501 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp @@ -65,8 +65,6 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); auto *Nod = ModSet->getSVFValue(Pointer); - // TODO: Is this the right function to call? Or better - // PAG->getObjectNode(Nod)? return PAG->getValueNode(Nod); } @@ -108,9 +106,6 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { SVF::SVFIR *PAG; }; -// TODO: Implement abstractions/pimpl for VFS and DDA analyses -// TODO: implement all the APi functions of SVFPointsToSet - struct VFSPointsToSetImpl : SVFPointsToSet { VFSPointsToSetImpl(SVF::SVFModule *Mod) : SVFPointsToSet(Mod), VFS(PAG) { VFS.initialize(); @@ -127,12 +122,6 @@ struct VFSPointsToSetImpl : SVFPointsToSet { struct DDAPointsToSetImpl : SVFPointsToSet { DDAPointsToSetImpl(SVF::SVFModule *Mod) : SVFPointsToSet(Mod), Client(Mod) { - // Initialize these parameters to their default values. - // See https://github.com/SVF-tools/SVF/blob/master/svf/lib/DDA/DDAPass.cpp - // for reference - SVF::ContextCond::setMaxCxtLen(SVF::Options::MaxContextLen()); - SVF::ContextCond::setMaxPathLen(SVF::Options::MaxPathLen()); - Client.initialise(Mod); DDA.emplace(PAG, &Client); DDA->initialize(); diff --git a/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp index f08c34441..10629748a 100644 --- a/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp +++ b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp @@ -3,6 +3,7 @@ #include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h" #include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Pointer/AliasResult.h" #include "TestConfig.h" #include "gtest/gtest.h" @@ -23,6 +24,7 @@ TEST(SVFAliasSetTest, Alias_01) { auto ASet = AS.getAliasSet(V); LLVMAliasSet::AliasSetTy GroundTruth = {V, Alias}; EXPECT_EQ(GroundTruth, *ASet); + EXPECT_NE(AliasResult::NoAlias, AS.alias(V, Alias)); } TEST(SVFAliasSetTest, PointsTo_01) { @@ -39,6 +41,11 @@ TEST(SVFAliasSetTest, PointsTo_01) { auto PSet = PT.getPointsToSet(V, V->getNextNode()); ASSERT_EQ(1, PSet.size()); EXPECT_EQ(Alloc, PT.asPointerOrNull(*PSet.begin())); + + auto AllocObjs = PT.getPointsToSet(Alloc, Alloc->getNextNode()); + ASSERT_EQ(1, AllocObjs.size()); + auto AllocObj = *AllocObjs.begin(); + EXPECT_TRUE(PT.mayPointsTo(V, AllocObj, V->getNextNode())); } int main(int Argc, char **Argv) { From 6bc19886761cc77dbb70aa7d7bec58d009047081 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 28 Feb 2025 20:13:34 +0100 Subject: [PATCH 07/17] Fix build due to merge --- lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp b/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp index 1eac91310..2766f8e5a 100644 --- a/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp +++ b/lib/PhasarLLVM/Pointer/FilteredLLVMAliasSet.cpp @@ -9,6 +9,8 @@ #include "phasar/Utils/NlohmannLogging.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "nlohmann/json_fwd.hpp" From dcef1a12d184763bbfbdc7d50762495b30564735 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 9 Mar 2025 17:56:41 +0100 Subject: [PATCH 08/17] minor --- include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h index a3134c713..9eee1395d 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h @@ -38,7 +38,6 @@ template <> struct CFGTraits : CFGTraits {}; namespace detail { template class LLVMBasedCFGImpl : public CFGBase { - friend CFGBase; friend class LLVMBasedBackwardCFG; public: From cc500ce4cc88e8f5f269f7b12168eb7684bf9c64 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 30 Mar 2025 17:43:24 +0200 Subject: [PATCH 09/17] Simplify the SVF alias analyses + make FunctionAliasView more type-safe --- .gitignore | 7 +-- .../PhasarLLVM/Pointer/AliasAnalysisView.h | 17 ++++--- .../Pointer/LLVMBasedAliasAnalysis.cpp | 4 +- .../Pointer/LLVMBasedAliasAnalysis.h | 4 +- .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 50 ++++++------------- 5 files changed, 32 insertions(+), 50 deletions(-) diff --git a/.gitignore b/.gitignore index df7dd6a47..2aaf8ce5f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,11 +30,8 @@ doc/* log/* **/*/logs/ -# CMake build dir -build/* - # MS VS Code -.vscode/* +.vscode/ # Eclipse .cproject @@ -46,7 +43,7 @@ build/* .idea/* # cache -.cache/* +.cache/ ##### ignored files diff --git a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h index b865980d7..0e8fc0138 100644 --- a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h +++ b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h @@ -26,22 +26,25 @@ class LLVMProjectIRDB; class FunctionAliasView { public: - using AliasCallbackTy = AliasResult (*)(void *, const llvm::Value *, + template + using AliasCallbackTy = AliasResult (*)(T *, const llvm::Value *, const llvm::Value *, const llvm::DataLayout &); - [[nodiscard]] inline AliasResult alias(const llvm::Value *V, - const llvm::Value *Rep, - const llvm::DataLayout &DL) { + [[nodiscard]] AliasResult alias(const llvm::Value *V, const llvm::Value *Rep, + const llvm::DataLayout &DL) { return Alias(Context, V, Rep, DL); } - constexpr FunctionAliasView(void *Context, AliasCallbackTy Alias) noexcept - : Context(Context), Alias(Alias) {} + template + constexpr FunctionAliasView(T *Context, AliasCallbackTy Alias) noexcept + : Context(Context), Alias(AliasCallbackTy(Alias)) { + assert(Alias != nullptr); + } private: void *Context{}; - AliasCallbackTy Alias{}; + AliasCallbackTy Alias{}; }; class AliasAnalysisView { diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp index 019199f71..a614f8675 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp @@ -116,14 +116,14 @@ static AliasResult translateAAResult(llvm::AliasResult Res) noexcept { } } -AliasResult LLVMBasedAliasAnalysis::aliasImpl(void *AACtx, const llvm::Value *V, +AliasResult LLVMBasedAliasAnalysis::aliasImpl(llvm::AAResults *AA, + const llvm::Value *V, const llvm::Value *Rep, const llvm::DataLayout &DL) { assert(V->getType()->isPointerTy()); assert(Rep->getType()->isPointerTy()); - auto *AA = static_cast(AACtx); auto *ElTy = !V->getType()->isOpaquePointerTy() ? V->getType()->getNonOpaquePointerElementType() : nullptr; diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h index f6aed7805..301a65a33 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h @@ -49,8 +49,8 @@ class LLVMBasedAliasAnalysis : public AliasAnalysisView { void doClear() noexcept override; - static AliasResult aliasImpl(void *, const llvm::Value *, const llvm::Value *, - const llvm::DataLayout &); + static AliasResult aliasImpl(llvm::AAResults *, const llvm::Value *, + const llvm::Value *, const llvm::DataLayout &); [[nodiscard]] constexpr FunctionAliasView createFAView(llvm::AAResults *AAR) noexcept { return {AAR, &aliasImpl}; diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index 4065b313a..d14d8d8f9 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -12,8 +12,6 @@ #include "SVFIR/SVFIR.h" #include "SVFIR/SVFModule.h" #include "SVFIR/SVFType.h" -#include "Util/DPItem.h" -#include "Util/Options.h" #include "WPA/Andersen.h" #include "WPA/VersionedFlowSensitive.h" @@ -35,6 +33,20 @@ translateSVFAliasResult(SVF::AliasResult AR) noexcept { } } +static psr::AliasResult aliasImpl(SVF::PointerAnalysis *AA, + const llvm::Value *V, const llvm::Value *Rep, + const llvm::DataLayout & /*DL*/) { + auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); + auto *Nod1 = ModSet->getSVFValue(V); + auto *Nod2 = ModSet->getSVFValue(Rep); + + if (!Nod1 || !Nod2) { + return AliasResult::MayAlias; + } + + return translateSVFAliasResult(AA->alias(Nod1, Nod2)); +} + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) class SVFAliasAnalysisBase : public AliasAnalysisView { public: @@ -67,23 +79,8 @@ class SVFVFSAnalysis : public SVFAliasAnalysisBase { } private: - static psr::AliasResult aliasImpl(void *AACtx, const llvm::Value *V, - const llvm::Value *Rep, - const llvm::DataLayout & /*DL*/) { - auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); - auto *Nod1 = ModSet->getSVFValue(V); - auto *Nod2 = ModSet->getSVFValue(Rep); - - if (!Nod1 || !Nod2) { - return AliasResult::MayAlias; - } - - auto *AA = static_cast(AACtx); - return translateSVFAliasResult(AA->VFS.alias(Nod1, Nod2)); - } - FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { - return {this, &aliasImpl}; + return {static_cast(&VFS), &aliasImpl}; } SVF::VersionedFlowSensitive VFS; @@ -101,23 +98,8 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { } private: - static psr::AliasResult aliasImpl(void *AACtx, const llvm::Value *V, - const llvm::Value *Rep, - const llvm::DataLayout & /*DL*/) { - auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); - auto *Nod1 = ModSet->getSVFValue(V); - auto *Nod2 = ModSet->getSVFValue(Rep); - - if (!Nod1 || !Nod2) { - return AliasResult::MayAlias; - } - - auto *AA = static_cast(AACtx); - return translateSVFAliasResult(AA->DDA->alias(Nod1, Nod2)); - } - FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { - return {this, &aliasImpl}; + return {static_cast(&*DDA), &aliasImpl}; } SVF::DDAClient Client; From 72b894f1866028a6de77924cb8991f9b8679e339 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 30 Mar 2025 17:50:25 +0200 Subject: [PATCH 10/17] minor --- include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h | 3 ++- include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h | 4 ++++ include/phasar/Pointer/AliasAnalysisType.def | 4 ++-- lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp | 7 ++++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h b/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h index 91599637c..b18cadbec 100644 --- a/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h +++ b/include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h @@ -66,7 +66,8 @@ class FilteredLLVMAliasSet { typename = std::enable_if_t< std::is_constructible_v>> explicit FilteredLLVMAliasSet(ArgsT &&...Args) - : FilteredLLVMAliasSet(std::forward(Args)...) {} + : FilteredLLVMAliasSet( + std::make_unique(std::forward(Args)...)) {} // --- API Functions: diff --git a/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h index d5cb3461e..55c753222 100644 --- a/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h +++ b/include/phasar/PhasarLLVM/Pointer/SVF/SVFPointsToSet.h @@ -40,9 +40,13 @@ struct SVFPointsToInfoTraits { using SVFBasedPointsToInfo = PointsToInfo; using SVFBasedPointsToInfoRef = PointsToInfoRef; +/// Use SVF to perform a VersionedFlowSensitive pointer analysis and return the +/// results compatible to psr::PointsToInfo and psr::PointsToInfoRef [[nodiscard]] SVFBasedPointsToInfo createSVFVFSPointsToInfo(LLVMProjectIRDB &IRDB); +/// Use SVF to perform a ContextDDA pointer analysis and return the +/// results compatible to psr::PointsToInfo and psr::PointsToInfoRef [[nodiscard]] SVFBasedPointsToInfo createSVFDDAPointsToInfo(LLVMProjectIRDB &IRDB); diff --git a/include/phasar/Pointer/AliasAnalysisType.def b/include/phasar/Pointer/AliasAnalysisType.def index 9664e49ac..dda81808c 100644 --- a/include/phasar/Pointer/AliasAnalysisType.def +++ b/include/phasar/Pointer/AliasAnalysisType.def @@ -15,7 +15,7 @@ ALIAS_ANALYSIS_TYPE(Basic, "basic", "Basic LLVM alias resolving based on simple, ALIAS_ANALYSIS_TYPE(CFLSteens, "cflsteens", "Steensgaard-style alias analysis (equality-based)") ALIAS_ANALYSIS_TYPE(CFLAnders, "cflanders", "Andersen-style alias analysis (subset-based) (default)") ALIAS_ANALYSIS_TYPE(PointsTo, "points-to", "Alias-information based on (external) points-to information") -ALIAS_ANALYSIS_TYPE(SVFDDA, "svf-dda", "Alias-information based on AVF's ContextDDA analysis. Requires SVF.") -ALIAS_ANALYSIS_TYPE(SVFVFS, "svf-vfs", "Alias-information based on AVF's VersionedFlowSensitive analysis. Requires SVF.") +ALIAS_ANALYSIS_TYPE(SVFDDA, "svf-dda", "Alias-information based on SVF's ContextDDA analysis. Requires SVF.") +ALIAS_ANALYSIS_TYPE(SVFVFS, "svf-vfs", "Alias-information based on SVF's VersionedFlowSensitive analysis. Requires SVF.") #undef ALIAS_ANALYSIS_TYPE diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp index 072e75501..570f5a1bb 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp @@ -42,9 +42,6 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { using typename base_t::PointsToSetTy; using typename base_t::v_t; - SVFPointsToSet(SVF::SVFModule *Mod) - : IRBuilder(Mod), PAG(IRBuilder.build()) {} - ~SVFPointsToSet() { SVF::SVFIR::releaseSVFIR(); SVF::AndersenWaveDiff::releaseAndersenWaveDiff(); @@ -53,6 +50,9 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { } private: + SVFPointsToSet(SVF::SVFModule *Mod) + : IRBuilder(Mod), PAG(IRBuilder.build()) {} + [[nodiscard]] constexpr Derived &self() noexcept { return static_cast(*this); } @@ -104,6 +104,7 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { protected: SVF::SVFIRBuilder IRBuilder; SVF::SVFIR *PAG; + friend Derived; }; struct VFSPointsToSetImpl : SVFPointsToSet { From 5c4f52ba56cbe11798834c9ca724f81368e4a987 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 30 Mar 2025 19:19:59 +0200 Subject: [PATCH 11/17] Regain precision --- .../Pointer/LLVMBasedAliasAnalysis.cpp | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp index a614f8675..38a79105b 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp @@ -116,6 +116,27 @@ static AliasResult translateAAResult(llvm::AliasResult Res) noexcept { } } +static llvm::Type *getPointeeTypeOrNull(const llvm::Value *Ptr) { + assert(Ptr->getType()->isPointerTy()); + + if (!Ptr->getType()->isOpaquePointerTy()) { + return Ptr->getType()->getNonOpaquePointerElementType(); + } + + if (const auto *Arg = llvm::dyn_cast(Ptr)) { + if (auto *Ty = Arg->getParamByValType()) { + return Ty; + } + if (auto *Ty = Arg->getParamStructRetType()) { + return Ty; + } + } + if (const auto *Alloca = llvm::dyn_cast(Ptr)) { + return Alloca->getAllocatedType(); + } + return nullptr; +} + AliasResult LLVMBasedAliasAnalysis::aliasImpl(llvm::AAResults *AA, const llvm::Value *V, const llvm::Value *Rep, @@ -124,19 +145,16 @@ AliasResult LLVMBasedAliasAnalysis::aliasImpl(llvm::AAResults *AA, assert(V->getType()->isPointerTy()); assert(Rep->getType()->isPointerTy()); - auto *ElTy = !V->getType()->isOpaquePointerTy() - ? V->getType()->getNonOpaquePointerElementType() - : nullptr; - auto *RepElTy = !Rep->getType()->isOpaquePointerTy() - ? Rep->getType()->getNonOpaquePointerElementType() - : nullptr; + auto *ElTy = getPointeeTypeOrNull(V); + auto *RepElTy = getPointeeTypeOrNull(Rep); - auto VSize = ElTy && ElTy->isSized() ? DL.getTypeStoreSize(ElTy) - : llvm::MemoryLocation::UnknownSize; + auto VSize = ElTy && ElTy->isSized() + ? llvm::LocationSize::precise(DL.getTypeStoreSize(ElTy)) + : llvm::LocationSize::precise(1); auto RepSize = RepElTy && RepElTy->isSized() - ? DL.getTypeStoreSize(RepElTy) - : llvm::MemoryLocation::UnknownSize; + ? llvm::LocationSize::precise(DL.getTypeStoreSize(RepElTy)) + : llvm::LocationSize::precise(1); return translateAAResult(AA->alias(V, VSize, Rep, RepSize)); } From c782f0b40f6a8ce9400a4ce5a48408a4c505209c Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 30 Mar 2025 19:53:46 +0200 Subject: [PATCH 12/17] Get rid of UB + aim to resolve memory leaks with SVF --- .../PhasarLLVM/Pointer/AliasAnalysisView.h | 32 ++++++++++++++++--- .../Pointer/LLVMBasedAliasAnalysis.h | 2 +- .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 15 ++++----- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h index 0e8fc0138..0ae69e983 100644 --- a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h +++ b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h @@ -14,6 +14,7 @@ #include "phasar/Pointer/AliasResult.h" #include +#include namespace llvm { class Value; @@ -36,17 +37,38 @@ class FunctionAliasView { return Alias(Context, V, Rep, DL); } - template - constexpr FunctionAliasView(T *Context, AliasCallbackTy Alias) noexcept - : Context(Context), Alias(AliasCallbackTy(Alias)) { - assert(Alias != nullptr); - } + template < + typename T, typename AliasFn, + typename = std::enable_if_t && + std::is_default_constructible_v>> + constexpr FunctionAliasView(T *Context, AliasFn /*Alias*/) noexcept + : Context(Context), Alias(&callAlias) {} private: + template + static AliasResult callAlias(void *Context, const llvm::Value *V1, + const llvm::Value *V2, + const llvm::DataLayout &DL) { + return AliasFn{}(static_cast(Context), V1, V2, DL); + } + void *Context{}; AliasCallbackTy Alias{}; }; +#define PSR_BIND_ALIASVIEW(Ctx, ...) \ + ::psr::FunctionAliasView { \ + (Ctx), [] { \ + struct DefaultConstructibleCallable { \ + auto operator()(decltype(Ctx) Context, const llvm::Value *V1, \ + const llvm::Value *V2, const llvm::DataLayout &DL) { \ + return __VA_ARGS__(Context, V1, V2, DL); \ + } \ + }; \ + return DefaultConstructibleCallable{}; \ + }() \ + } + class AliasAnalysisView { public: constexpr AliasAnalysisView(AliasAnalysisType PATy) noexcept : PATy(PATy) {} diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h index 301a65a33..071def013 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h @@ -53,7 +53,7 @@ class LLVMBasedAliasAnalysis : public AliasAnalysisView { const llvm::Value *, const llvm::DataLayout &); [[nodiscard]] constexpr FunctionAliasView createFAView(llvm::AAResults *AAR) noexcept { - return {AAR, &aliasImpl}; + return PSR_BIND_ALIASVIEW(AAR, aliasImpl); } [[nodiscard]] bool hasAliasInfo(const llvm::Function &Fun) const; diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index d14d8d8f9..cd7bfb5ba 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -72,18 +72,17 @@ class SVFAliasAnalysisBase : public AliasAnalysisView { class SVFVFSAnalysis : public SVFAliasAnalysisBase { public: SVFVFSAnalysis(SVF::SVFModule *Mod) - : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), VFS(PAG) { - VFS.initialize(); - VFS.analyze(); - VFS.finalize(); - } + : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), + VFS(SVF::VersionedFlowSensitive::createVFSWPA(PAG)) {} + + ~SVFVFSAnalysis() override { SVF::VersionedFlowSensitive::releaseVFSWPA(); } private: FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { - return {static_cast(&VFS), &aliasImpl}; + return PSR_BIND_ALIASVIEW(VFS, aliasImpl); } - SVF::VersionedFlowSensitive VFS; + SVF::VersionedFlowSensitive *VFS; }; class SVFDDAAnalysis : public SVFAliasAnalysisBase { @@ -99,7 +98,7 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { private: FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { - return {static_cast(&*DDA), &aliasImpl}; + return PSR_BIND_ALIASVIEW(&*DDA, aliasImpl); } SVF::DDAClient Client; From 2bb10728a81e9cc0f3fab6cc6eb117d812d8b498 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 5 Apr 2025 13:21:42 +0200 Subject: [PATCH 13/17] Fix SVF memory leak --- .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 2 + lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp | 18 ++++----- .../PhasarLLVM/Pointer/SVFAliasSetTest.cpp | 38 +++++++++++++++++++ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index cd7bfb5ba..aae43a439 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -73,6 +73,8 @@ class SVFVFSAnalysis : public SVFAliasAnalysisBase { public: SVFVFSAnalysis(SVF::SVFModule *Mod) : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), + // Note: We must use the static createVFSWPA() function, otherwise SVF + // will leak memory VFS(SVF::VersionedFlowSensitive::createVFSWPA(PAG)) {} ~SVFVFSAnalysis() override { SVF::VersionedFlowSensitive::releaseVFSWPA(); } diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp index 570f5a1bb..1aa574440 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp @@ -108,17 +108,17 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { }; struct VFSPointsToSetImpl : SVFPointsToSet { - VFSPointsToSetImpl(SVF::SVFModule *Mod) : SVFPointsToSet(Mod), VFS(PAG) { - VFS.initialize(); - VFS.analyze(); - VFS.finalize(); - } + VFSPointsToSetImpl(SVF::SVFModule *Mod) + : SVFPointsToSet(Mod), + // Note: We must use the static createVFSWPA() function, otherwise SVF + // will leak memory + VFS(SVF::VersionedFlowSensitive::createVFSWPA(PAG)) {} - [[nodiscard]] SVF::PointerAnalysis &getPTA() const noexcept { return VFS; } + ~VFSPointsToSetImpl() { SVF::VersionedFlowSensitive::releaseVFSWPA(); } - // Note: SVF is not thread-safe anyway, so this 'mutable' should not be a - // problem - mutable SVF::VersionedFlowSensitive VFS; + [[nodiscard]] SVF::PointerAnalysis &getPTA() const noexcept { return *VFS; } + + SVF::VersionedFlowSensitive *VFS; }; struct DDAPointsToSetImpl : SVFPointsToSet { diff --git a/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp index 10629748a..4482d6071 100644 --- a/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp +++ b/unittests/PhasarLLVM/Pointer/SVFAliasSetTest.cpp @@ -27,6 +27,23 @@ TEST(SVFAliasSetTest, Alias_01) { EXPECT_NE(AliasResult::NoAlias, AS.alias(V, Alias)); } +TEST(SVFAliasSetTest, Alias_02) { + LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + + "pointers/basic_01_cpp_dbg.ll"); + + LLVMAliasSet AS(&IRDB, false, AliasAnalysisType::SVFDDA); + + const auto *V = IRDB.getInstruction(5); + ASSERT_TRUE(V && V->getType()->isPointerTy()); + + const auto *Alias = IRDB.getInstruction(0); + + auto ASet = AS.getAliasSet(V); + LLVMAliasSet::AliasSetTy GroundTruth = {V, Alias}; + EXPECT_EQ(GroundTruth, *ASet); + EXPECT_NE(AliasResult::NoAlias, AS.alias(V, Alias)); +} + TEST(SVFAliasSetTest, PointsTo_01) { LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + "pointers/basic_01_cpp_dbg.ll"); @@ -48,6 +65,27 @@ TEST(SVFAliasSetTest, PointsTo_01) { EXPECT_TRUE(PT.mayPointsTo(V, AllocObj, V->getNextNode())); } +TEST(SVFAliasSetTest, PointsTo_02) { + LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + + "pointers/basic_01_cpp_dbg.ll"); + + auto PT = createSVFDDAPointsToInfo(IRDB); + + const auto *V = IRDB.getInstruction(5); + ASSERT_TRUE(V && V->getType()->isPointerTy()); + + const auto *Alloc = IRDB.getInstruction(0); + + auto PSet = PT.getPointsToSet(V, V->getNextNode()); + ASSERT_EQ(1, PSet.size()); + EXPECT_EQ(Alloc, PT.asPointerOrNull(*PSet.begin())); + + auto AllocObjs = PT.getPointsToSet(Alloc, Alloc->getNextNode()); + ASSERT_EQ(1, AllocObjs.size()); + auto AllocObj = *AllocObjs.begin(); + EXPECT_TRUE(PT.mayPointsTo(V, AllocObj, V->getNextNode())); +} + int main(int Argc, char **Argv) { ::testing::InitGoogleTest(&Argc, Argv); return RUN_ALL_TESTS(); From 37bcacaf2312f31d7759cea02a918e5837d8fb4a Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 5 Apr 2025 13:57:36 +0200 Subject: [PATCH 14/17] pre-commit with new clang-format version --- include/phasar/ControlFlow/CFGBase.h | 7 ++++--- include/phasar/ControlFlow/ICFGBase.h | 7 ++++--- include/phasar/Utils/CRTPUtils.h | 6 +++--- lib/Pointer/PointsToInfo.cpp | 6 ++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/phasar/ControlFlow/CFGBase.h b/include/phasar/ControlFlow/CFGBase.h index 868f2aeb5..5b932f2b5 100644 --- a/include/phasar/ControlFlow/CFGBase.h +++ b/include/phasar/ControlFlow/CFGBase.h @@ -139,9 +139,10 @@ template class CFGBase : public CRTPBase { template // NOLINTNEXTLINE(readability-identifier-naming) -PSR_CONCEPT is_cfg_v = is_crtp_base_of_v - &&std::is_same_v - &&std::is_same_v; +PSR_CONCEPT is_cfg_v = + is_crtp_base_of_v && + std::is_same_v && + std::is_same_v; } // namespace psr diff --git a/include/phasar/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h index 71f468f49..71f340462 100644 --- a/include/phasar/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -118,9 +118,10 @@ template class ICFGBase : public CRTPBase { /// from the given analysis-Domain template // NOLINTNEXTLINE(readability-identifier-naming) -PSR_CONCEPT is_icfg_v = is_crtp_base_of_v - &&std::is_same_v - &&std::is_same_v; +PSR_CONCEPT is_icfg_v = + is_crtp_base_of_v && + std::is_same_v && + std::is_same_v; } // namespace psr diff --git a/include/phasar/Utils/CRTPUtils.h b/include/phasar/Utils/CRTPUtils.h index 048137071..e66e394e0 100644 --- a/include/phasar/Utils/CRTPUtils.h +++ b/include/phasar/Utils/CRTPUtils.h @@ -17,13 +17,13 @@ template class CRTPBase { protected: constexpr CRTPBase() noexcept = default; - [[nodiscard]] constexpr Derived &self() &noexcept { + [[nodiscard]] constexpr Derived &self() & noexcept { return static_cast(*this); } - [[nodiscard]] constexpr Derived &&self() &&noexcept { + [[nodiscard]] constexpr Derived &&self() && noexcept { return static_cast(*this); } - [[nodiscard]] constexpr const Derived &self() const &noexcept { + [[nodiscard]] constexpr const Derived &self() const & noexcept { return static_cast(*this); } }; diff --git a/lib/Pointer/PointsToInfo.cpp b/lib/Pointer/PointsToInfo.cpp index 2d51ae2a0..2f99b3df7 100644 --- a/lib/Pointer/PointsToInfo.cpp +++ b/lib/Pointer/PointsToInfo.cpp @@ -140,13 +140,11 @@ class DummyFieldSensitivePointsToAnalysis [[maybe_unused]] void testTypeErasure() { DummyFieldInsensitivePointsToAnalysis PTA1; [[maybe_unused]] PointsToInfoRef< - PointsToTraits> - TEPTA1 = &PTA1; + PointsToTraits> TEPTA1 = &PTA1; DummyFieldSensitivePointsToAnalysis PTA2; [[maybe_unused]] PointsToInfoRef< - PointsToTraits> - TEPTA2 = &PTA2; + PointsToTraits> TEPTA2 = &PTA2; PointsToInfo> TEPTA3( std::in_place_type); From de0539d381cef8cd944d79a0fc7060e461693fb9 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sat, 26 Apr 2025 13:29:54 +0200 Subject: [PATCH 15/17] Apply review comments --- lib/PhasarLLVM/Pointer/CMakeLists.txt | 2 +- lib/Pointer/PointsToInfo.cpp | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/PhasarLLVM/Pointer/CMakeLists.txt b/lib/PhasarLLVM/Pointer/CMakeLists.txt index f9cb819b0..522fd55e5 100644 --- a/lib/PhasarLLVM/Pointer/CMakeLists.txt +++ b/lib/PhasarLLVM/Pointer/CMakeLists.txt @@ -1,4 +1,4 @@ -file(GLOB POINTER_SRC *.cpp TypeGraphs/*.cpp) +file(GLOB POINTER_SRC *.cpp) add_phasar_library(phasar_llvm_pointer ${POINTER_SRC} diff --git a/lib/Pointer/PointsToInfo.cpp b/lib/Pointer/PointsToInfo.cpp index 2f99b3df7..ed3ca3b48 100644 --- a/lib/Pointer/PointsToInfo.cpp +++ b/lib/Pointer/PointsToInfo.cpp @@ -61,11 +61,6 @@ class DummyFieldInsensitivePointsToAnalysis static PointsToSetTy Empty{}; return &Empty; } - - [[nodiscard]] std::vector - getInterestingPointersAtImpl(ByConstRef /*AtInstruction*/) const { - return {}; - } }; template class PointsToInfoBase; @@ -130,11 +125,6 @@ class DummyFieldSensitivePointsToAnalysis static PointsToSetTy Empty{}; return &Empty; } - - [[nodiscard]] std::vector - getInterestingPointersAtImpl(ByConstRef /*AtInstruction*/) const { - return {}; - } }; [[maybe_unused]] void testTypeErasure() { From dc89459b64b93e15dc4d99604cb70fc54adde4cc Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 19 May 2025 18:01:35 +0200 Subject: [PATCH 16/17] Getting rid of the PSR_BIND_ALIASVIEW macro --- .../PhasarLLVM/Pointer/AliasAnalysisView.h | 13 ------ include/phasar/Utils/Fn.h | 43 +++++++++++++++++++ .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 5 ++- 3 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 include/phasar/Utils/Fn.h diff --git a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h index 0ae69e983..afdedb5de 100644 --- a/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h +++ b/include/phasar/PhasarLLVM/Pointer/AliasAnalysisView.h @@ -56,19 +56,6 @@ class FunctionAliasView { AliasCallbackTy Alias{}; }; -#define PSR_BIND_ALIASVIEW(Ctx, ...) \ - ::psr::FunctionAliasView { \ - (Ctx), [] { \ - struct DefaultConstructibleCallable { \ - auto operator()(decltype(Ctx) Context, const llvm::Value *V1, \ - const llvm::Value *V2, const llvm::DataLayout &DL) { \ - return __VA_ARGS__(Context, V1, V2, DL); \ - } \ - }; \ - return DefaultConstructibleCallable{}; \ - }() \ - } - class AliasAnalysisView { public: constexpr AliasAnalysisView(AliasAnalysisType PATy) noexcept : PATy(PATy) {} diff --git a/include/phasar/Utils/Fn.h b/include/phasar/Utils/Fn.h new file mode 100644 index 000000000..55cc64414 --- /dev/null +++ b/include/phasar/Utils/Fn.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2025 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_UTILS_FN_H +#define PHASAR_UTILS_FN_H + +#include "phasar/Utils/Macros.h" + +#include +#include + +namespace psr { +/// \brief A helper that transforms a statically known function pointer into a +/// type. +/// +/// Useful for passing functions as callbacks, while avoiding either the +/// indirect call overhead or wrapping a lambda around +template struct fn_t { // NOLINT(readability-identifier-naming) + template + constexpr std::invoke_result_t + operator()(ArgsT &&...Args) noexcept( + std::is_nothrow_invocable_v) { + return std::invoke(F, PSR_FWD(Args)...); + } +}; + +/// \brief A helper that transforms a statically known function pointer into a +/// callable object. +/// +/// Useful for passing functions as callbacks, while avoiding either the +/// indirect call overhead or wrapping a lambda around +template +static constexpr fn_t fn{}; // NOLINT(readability-identifier-naming) + +} // namespace psr + +#endif // PHASAR_UTILS_FN_H diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index aae43a439..0416a8415 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -4,6 +4,7 @@ #include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/Pointer/AliasAnalysisType.h" #include "phasar/Pointer/AliasResult.h" +#include "phasar/Utils/Fn.h" #include "DDA/ContextDDA.h" #include "DDA/DDAClient.h" @@ -81,7 +82,7 @@ class SVFVFSAnalysis : public SVFAliasAnalysisBase { private: FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { - return PSR_BIND_ALIASVIEW(VFS, aliasImpl); + return {VFS, fn}; } SVF::VersionedFlowSensitive *VFS; @@ -100,7 +101,7 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { private: FunctionAliasView doGetAAResults(const llvm::Function * /*F*/) override { - return PSR_BIND_ALIASVIEW(&*DDA, aliasImpl); + return {&*DDA, fn}; } SVF::DDAClient Client; From 1698ac7477f74f3a669fc1e85a4d309bd5a0c0f5 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Mon, 19 May 2025 18:13:26 +0200 Subject: [PATCH 17/17] fix compilation --- lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h index 071def013..2195d02ff 100644 --- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h +++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h @@ -13,6 +13,7 @@ #include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h" #include "phasar/Pointer/AliasAnalysisType.h" #include "phasar/Pointer/AliasResult.h" +#include "phasar/Utils/Fn.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Passes/PassBuilder.h" @@ -53,7 +54,7 @@ class LLVMBasedAliasAnalysis : public AliasAnalysisView { const llvm::Value *, const llvm::DataLayout &); [[nodiscard]] constexpr FunctionAliasView createFAView(llvm::AAResults *AAR) noexcept { - return PSR_BIND_ALIASVIEW(AAR, aliasImpl); + return {AAR, fn}; } [[nodiscard]] bool hasAliasInfo(const llvm::Function &Fun) const;