From 061ce088663b8466e1f2aab272a4f56412d179a6 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Sun, 25 Jan 2026 16:39:53 +0100 Subject: [PATCH] Update phasar's SVF bindings to support SVF-3.1 and SVF-3.2 --- CMakeLists.txt | 37 ++++---- lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt | 2 + lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp | 12 +-- lib/PhasarLLVM/Pointer/SVF/InitSVF.h | 7 +- lib/PhasarLLVM/Pointer/SVF/PhasarSVFUtils.h | 37 ++++---- .../Pointer/SVF/SVFBasedAliasAnalysis.cpp | 88 +++++++++---------- lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp | 42 ++++----- 7 files changed, 103 insertions(+), 122 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f929582f71..c6a7b1c9f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -356,22 +356,27 @@ if(PHASAR_IN_TREE) set (PHASAR_USE_Z3 OFF) else() if(PHASAR_USE_Z3) - # This z3-version is the same version LLVM requires; however, we cannot just use Z3 via the LLVM interface - # as it lacks some functionality (such as z3::expr::simplify()) that we require - - # FindZ3.cmake by llvm tries to compile a snippet with Z3 which crashes on arm with sanitizers enabled - set(SAFE_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS "") - find_package(Z3 4.7.1 REQUIRED) - set(CMAKE_CXX_FLAGS "${SAFE_CMAKE_CXX_FLAGS}") - - if(Z3_FOUND) - if (NOT TARGET z3) - add_library(z3 IMPORTED SHARED) - set_property(TARGET z3 PROPERTY - IMPORTED_LOCATION ${Z3_LIBRARIES}) - set_property(TARGET z3 PROPERTY - INTERFACE_INCLUDE_DIRECTORIES ${Z3_INCLUDE_DIR}) + if (TARGET z3::libz3) + # When including SVF, it also tries to find z3, but in addition to LLVM's search it already creates a target: z3::libz3. + # Reuse it here: + if(NOT TARGET z3) + add_library(z3 ALIAS z3::libz3) + endif() + else() + # FindZ3.cmake by llvm tries to compile a snippet with Z3 which crashes on arm with sanitizers enabled + set(SAFE_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "") + find_package(Z3 REQUIRED) + set(CMAKE_CXX_FLAGS "${SAFE_CMAKE_CXX_FLAGS}") + + if(Z3_FOUND) + if (NOT TARGET z3) + add_library(z3 IMPORTED SHARED) + set_target_properties(z3 PROPERTIES + IMPORTED_LOCATION ${Z3_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES ${Z3_INCLUDE_DIR} + ) + endif() endif() endif() endif() diff --git a/lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt b/lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt index ec59ba7f2b..e49e76755c 100644 --- a/lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt +++ b/lib/PhasarLLVM/Pointer/SVF/CMakeLists.txt @@ -22,3 +22,5 @@ add_phasar_library(phasar_llvm_pointer_svf 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}) +# Such that SVF finds its extapi.bc without system-wide installation: +target_compile_options(phasar_llvm_pointer_svf PRIVATE -DPHASAR_SVF_INSTALL_LIBDIR="${SVF_INSTALL_LIBDIR}") diff --git a/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp b/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp index 32376f4ae2..33eebc3035 100644 --- a/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/InitSVF.cpp @@ -12,10 +12,12 @@ static psr::EmptyType initializeSVFImpl() { char EmptyStr[] = ""; char NoAliasCheck[] = "-alias-check=false"; char NoStat[] = "-stat=false"; + char Extapi[] = "-extapi=" PHASAR_SVF_INSTALL_LIBDIR "/extapi.bc"; char *MockArgv[] = { EmptyStr, NoAliasCheck, NoStat, + Extapi, }; OptionBase::parseOptions(std::size(MockArgv), MockArgv, "", ""); @@ -33,14 +35,8 @@ void psr::initializeSVF() { (void)SVFInitialized; } -SVF::SVFModule *psr::initSVFModule(psr::LLVMProjectIRDB &IRDB) { +void 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; + SVF::LLVMModuleSet::buildSVFModule(*IRDB.getModule()); } diff --git a/lib/PhasarLLVM/Pointer/SVF/InitSVF.h b/lib/PhasarLLVM/Pointer/SVF/InitSVF.h index 2599a3626e..cb7eb120b2 100644 --- a/lib/PhasarLLVM/Pointer/SVF/InitSVF.h +++ b/lib/PhasarLLVM/Pointer/SVF/InitSVF.h @@ -2,14 +2,9 @@ #include "llvm/Support/Compiler.h" -namespace SVF { -class SVFModule; -} // namespace SVF - namespace psr { class LLVMProjectIRDB; LLVM_LIBRARY_VISIBILITY void initializeSVF(); -LLVM_LIBRARY_VISIBILITY SVF::SVFModule * -initSVFModule(psr::LLVMProjectIRDB &IRDB); +LLVM_LIBRARY_VISIBILITY void initSVFModule(psr::LLVMProjectIRDB &IRDB); } // namespace psr diff --git a/lib/PhasarLLVM/Pointer/SVF/PhasarSVFUtils.h b/lib/PhasarLLVM/Pointer/SVF/PhasarSVFUtils.h index 85dfd53042..91ea440397 100644 --- a/lib/PhasarLLVM/Pointer/SVF/PhasarSVFUtils.h +++ b/lib/PhasarLLVM/Pointer/SVF/PhasarSVFUtils.h @@ -6,16 +6,22 @@ #include "Util/GeneralType.h" namespace psr { + +[[nodiscard]] inline const llvm::Value * +svfVarToLLVMOrNull(const SVF::SVFVar *Var, SVF::LLVMModuleSet &ModSet) { + if (ModSet.hasLLVMValue(Var)) { + return ModSet.getLLVMValue(Var); + } + + return nullptr; +} + [[nodiscard]] inline const llvm::Value * pointerNodeToLLVMOrNull(SVF::NodeID Nod, SVF::LLVMModuleSet &ModSet, SVF::SVFIR &PAG) { if (const SVF::SVFVar *Var = PAG.getGNode(Nod)) { - if (const auto *Val = Var->getValue()) { - if (const auto *LLVMVal = ModSet.getLLVMValue(Val)) { - return LLVMVal; - } - } + return svfVarToLLVMOrNull(Var, ModSet); } return nullptr; } @@ -23,27 +29,16 @@ pointerNodeToLLVMOrNull(SVF::NodeID Nod, SVF::LLVMModuleSet &ModSet, [[nodiscard]] inline const llvm::Value * objectNodeToLLVMOrNull(SVF::NodeID Nod, SVF::LLVMModuleSet &ModSet, SVF::SVFIR &PAG) { - if (const SVF::MemObj *Mem = PAG.getObject(Nod)) { - if (const auto *Val = Mem->getValue()) { - if (const auto *LLVMVal = ModSet.getLLVMValue(Val)) { - return LLVMVal; - } - } - } - return nullptr; + return pointerNodeToLLVMOrNull(Nod, ModSet, PAG); } [[nodiscard]] inline SVF::NodeID getNodeId(const llvm::Value *Pointer, - SVF::LLVMModuleSet &ModSet, - SVF::SVFIR &PAG) { - auto *Nod = ModSet.getSVFValue(Pointer); - return PAG.getValueNode(Nod); + SVF::LLVMModuleSet &ModSet) { + return ModSet.getValueNode(Pointer); } [[nodiscard]] inline SVF::NodeID getObjNodeId(const llvm::Value *Obj, - SVF::LLVMModuleSet &ModSet, - SVF::SVFIR &PAG) { - auto *Nod = ModSet.getSVFValue(Obj); - return PAG.getObjectNode(Nod); + SVF::LLVMModuleSet &ModSet) { + return ModSet.getObjectNode(Obj); } } // namespace psr diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp index a87901706c..d69b496ece 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFBasedAliasAnalysis.cpp @@ -27,7 +27,6 @@ #include "SVF-LLVM/LLVMModule.h" #include "SVF-LLVM/SVFIRBuilder.h" #include "SVFIR/SVFIR.h" -#include "SVFIR/SVFModule.h" #include "SVFIR/SVFType.h" #include "Util/GeneralType.h" #include "WPA/Andersen.h" @@ -36,7 +35,10 @@ #include #include -namespace psr { +using namespace psr; + +namespace { + static constexpr psr::AliasResult translateSVFAliasResult(SVF::AliasResult AR) noexcept { switch (AR) { @@ -55,13 +57,14 @@ static psr::AliasResult doAliasImpl(SVF::PointerAnalysis *AA, const llvm::Value *V, const llvm::Value *Rep) { auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); - auto *Nod1 = ModSet->getSVFValue(V); - auto *Nod2 = ModSet->getSVFValue(Rep); - if (!Nod1 || !Nod2) { + if (!ModSet->hasValueNode(V) || !ModSet->hasValueNode(Rep)) { return AliasResult::MayAlias; } + auto Nod1 = getNodeId(V, *ModSet); + auto Nod2 = getNodeId(Rep, *ModSet); + return translateSVFAliasResult(AA->alias(Nod1, Nod2)); } @@ -74,13 +77,12 @@ static psr::AliasResult aliasImpl(SVF::PointerAnalysis *AA, // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) class SVFAliasAnalysisBase : public AliasAnalysisView { public: - SVFAliasAnalysisBase(SVF::SVFModule *Mod, AliasAnalysisType PATy) - : AliasAnalysisView(PATy), IRBuilder(Mod), PAG(IRBuilder.build()) {} + SVFAliasAnalysisBase(AliasAnalysisType PATy) + : AliasAnalysisView(PATy), PAG(IRBuilder.build()) {} ~SVFAliasAnalysisBase() override { SVF::SVFIR::releaseSVFIR(); SVF::AndersenWaveDiff::releaseAndersenWaveDiff(); - SVF::SymbolTableInfo::releaseSymbolInfo(); SVF::LLVMModuleSet::releaseLLVMModuleSet(); } @@ -95,8 +97,8 @@ class SVFAliasAnalysisBase : public AliasAnalysisView { class SVFVFSAnalysis : public SVFAliasAnalysisBase { public: - SVFVFSAnalysis(SVF::SVFModule *Mod) - : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), + SVFVFSAnalysis() + : SVFAliasAnalysisBase(AliasAnalysisType::SVFVFS), // Note: We must use the static createVFSWPA() function, otherwise SVF // will leak memory VFS(SVF::VersionedFlowSensitive::createVFSWPA(PAG)) {} @@ -121,9 +123,8 @@ class SVFVFSAnalysis : public SVFAliasAnalysisBase { class SVFDDAAnalysis : public SVFAliasAnalysisBase { public: - SVFDDAAnalysis(SVF::SVFModule *Mod) - : SVFAliasAnalysisBase(Mod, AliasAnalysisType::SVFVFS), Client(Mod) { - Client.initialise(Mod); + SVFDDAAnalysis() : SVFAliasAnalysisBase(AliasAnalysisType::SVFVFS) { + Client.initialise(); DDA.emplace(PAG, &Client); DDA->initialize(); Client.answerQueries(&*DDA); @@ -149,28 +150,6 @@ class SVFDDAAnalysis : public SVFAliasAnalysisBase { mutable std::optional DDA; }; -} // namespace psr - -auto psr::createSVFVFSAnalysis(LLVMProjectIRDB &IRDB) - -> std::unique_ptr { - - return std::make_unique(psr::initSVFModule(IRDB)); -} - -auto psr::createSVFDDAAnalysis(LLVMProjectIRDB &IRDB) - -> std::unique_ptr { - - return std::make_unique(psr::initSVFModule(IRDB)); -} - -namespace psr { - -class SVFAliasInfoImpl; - -template <> -struct AliasInfoTraits - : DefaultAATraits {}; - class SVFAliasInfoImpl : public SVFDDAAnalysis, public AnalysisPropertiesMixin, @@ -217,9 +196,7 @@ class SVFAliasInfoImpl Ret = Set; auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); - auto *Nod = ModSet->getSVFValue(Ptr); - - auto PointerNod = PAG->getValueNode(Nod); + auto PointerNod = getNodeId(Ptr, *ModSet); createAliasSet(PointerNod, *Set, *ModSet); @@ -235,7 +212,7 @@ class SVFAliasInfoImpl } auto &ModSet = *SVF::LLVMModuleSet::getLLVMModuleSet(); - auto Nod = getNodeId(Ptr, ModSet, *PAG); + auto Nod = getNodeId(Ptr, ModSet); const auto &Pts = getPTA().getPts(Nod); const auto *VFun = AliasInfoBaseUtils::retrieveFunction(Ptr); @@ -267,14 +244,14 @@ class SVFAliasInfoImpl } auto &ModSet = *SVF::LLVMModuleSet::getLLVMModuleSet(); - auto Nod = getNodeId(Ptr, ModSet, *PAG); + auto Nod = getNodeId(Ptr, ModSet); if (IntraProcOnly && llvm::isa(AllocSite)) { - auto AllocSiteNod = getNodeId(AllocSite, ModSet, *PAG); + auto AllocSiteNod = getNodeId(AllocSite, ModSet); return getPTA().alias(Nod, AllocSiteNod) != SVF::NoAlias; } - auto AllocSiteNod = getObjNodeId(AllocSite, ModSet, *PAG); + auto AllocSiteNod = getObjNodeId(AllocSite, ModSet); const auto &Pts = getPTA().getPts(Nod); return Pts.test(AllocSiteNod); @@ -285,11 +262,7 @@ class SVFAliasInfoImpl auto &ModSet = *SVF::LLVMModuleSet::getLLVMModuleSet(); for (const auto &[Nod, Var] : *PAG) { - if (!Var->hasValue()) { - continue; - } - - const auto *PointerVal = ModSet.getLLVMValue(Var->getValue()); + const auto *PointerVal = svfVarToLLVMOrNull(Var, ModSet); if (!PointerVal) { continue; } @@ -352,8 +325,27 @@ class SVFAliasInfoImpl AliasSetOwner::memory_resource_type MRes; AliasSetOwner Owner{&MRes}; }; +} // namespace + +namespace psr { +template <> +struct AliasInfoTraits + : DefaultAATraits {}; } // namespace psr +auto psr::createSVFVFSAnalysis(LLVMProjectIRDB &IRDB) + -> std::unique_ptr { + psr::initSVFModule(IRDB); + return std::make_unique(); +} + +auto psr::createSVFDDAAnalysis(LLVMProjectIRDB &IRDB) + -> std::unique_ptr { + psr::initSVFModule(IRDB); + return std::make_unique(); +} + auto psr::createLLVMSVFDDAAliasInfo(LLVMProjectIRDB &IRDB) -> LLVMAliasInfo { - return std::make_unique(psr::initSVFModule(IRDB)); + psr::initSVFModule(IRDB); + return std::make_unique(); } diff --git a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp index 2de171a186..07168bd923 100644 --- a/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp +++ b/lib/PhasarLLVM/Pointer/SVF/SVFPointsToSet.cpp @@ -51,15 +51,13 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { ~SVFPointsToSet() { SVF::SVFIR::releaseSVFIR(); SVF::AndersenWaveDiff::releaseAndersenWaveDiff(); - SVF::SymbolTableInfo::releaseSymbolInfo(); SVF::LLVMModuleSet::releaseLLVMModuleSet(); } [[nodiscard]] constexpr SVF::SVFIR &getPAG() const noexcept { return *PAG; } private: - SVFPointsToSet(SVF::SVFModule *Mod) - : IRBuilder(Mod), PAG(IRBuilder.build()) {} + SVFPointsToSet() : PAG(IRBuilder.build()) {} [[nodiscard]] constexpr Derived &self() noexcept { return static_cast(*this); @@ -71,7 +69,7 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { [[nodiscard]] o_t asAbstractObjectImpl(psr::ByConstRef Pointer) const noexcept { auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); - return psr::getNodeId(Pointer, *ModSet, *PAG); + return psr::getNodeId(Pointer, *ModSet); } [[nodiscard]] std::optional asPointerOrNullImpl(o_t Obj) const noexcept { @@ -112,9 +110,8 @@ class SVFPointsToSet : public psr::PointsToInfoBase> { }; struct VFSPointsToSetImpl : SVFPointsToSet { - VFSPointsToSetImpl(SVF::SVFModule *Mod) - : SVFPointsToSet(Mod), - // Note: We must use the static createVFSWPA() function, otherwise SVF + VFSPointsToSetImpl() + : // Note: We must use the static createVFSWPA() function, otherwise SVF // will leak memory VFS(SVF::VersionedFlowSensitive::createVFSWPA(PAG)) {} @@ -126,8 +123,8 @@ struct VFSPointsToSetImpl : SVFPointsToSet { }; struct DDAPointsToSetImpl : SVFPointsToSet { - DDAPointsToSetImpl(SVF::SVFModule *Mod) : SVFPointsToSet(Mod), Client(Mod) { - Client.initialise(Mod); + DDAPointsToSetImpl() { + Client.initialise(); DDA.emplace(PAG, &Client); DDA->initialize(); Client.answerQueries(&*DDA); @@ -146,26 +143,25 @@ struct DDAPointsToSetImpl : SVFPointsToSet { auto psr::createSVFVFSPointsToInfo(LLVMProjectIRDB &IRDB) -> SVFBasedPointsToInfo { - return SVFBasedPointsToInfo(std::in_place_type, - psr::initSVFModule(IRDB)); + psr::initSVFModule(IRDB); + return SVFBasedPointsToInfo(std::in_place_type); } auto psr::createSVFDDAPointsToInfo(LLVMProjectIRDB &IRDB) -> SVFBasedPointsToInfo { - return SVFBasedPointsToInfo(std::in_place_type, - psr::initSVFModule(IRDB)); + psr::initSVFModule(IRDB); + return SVFBasedPointsToInfo(std::in_place_type); } auto psr::createSVFPointsToInfo(LLVMProjectIRDB &IRDB, SVFPointsToAnalysisType PTATy) -> SVFBasedPointsToInfo { + psr::initSVFModule(IRDB); switch (PTATy) { case SVFPointsToAnalysisType::DDA: - return SVFBasedPointsToInfo(std::in_place_type, - psr::initSVFModule(IRDB)); + return SVFBasedPointsToInfo(std::in_place_type); case SVFPointsToAnalysisType::VFS: - return SVFBasedPointsToInfo(std::in_place_type, - psr::initSVFModule(IRDB)); + return SVFBasedPointsToInfo(std::in_place_type); } llvm_unreachable("Should have handled all SVFPointsToAnalysisType variants " "in the switch above!"); @@ -178,7 +174,7 @@ template struct SVFLLVMPointsToIterator { using v_t = const llvm::Value *; using o_t = const llvm::Value *; - SVFLLVMPointsToIterator(SVF::SVFModule *Mod) : PT(Mod) {} + SVFLLVMPointsToIterator() = default; [[nodiscard]] constexpr o_t asAbstractObject(v_t Pointer) const noexcept { return Pointer; @@ -186,11 +182,11 @@ template struct SVFLLVMPointsToIterator { [[nodiscard]] SVF::NodeID getNodeId(v_t Pointer) const noexcept { auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); - return psr::getNodeId(Pointer, *ModSet, PT.getPAG()); + return psr::getNodeId(Pointer, *ModSet); } [[nodiscard]] SVF::NodeID getObjNodeId(o_t Obj) const noexcept { auto *ModSet = SVF::LLVMModuleSet::getLLVMModuleSet(); - return psr::getObjNodeId(Obj, *ModSet, PT.getPAG()); + return psr::getObjNodeId(Obj, *ModSet); } void forallPointeesOf(o_t Pointer, n_t /*At*/, @@ -227,13 +223,13 @@ template struct SVFLLVMPointsToIterator { auto psr::createLLVMSVFPointsToIterator(LLVMProjectIRDB &IRDB, SVFPointsToAnalysisType PTATy) -> LLVMPointsToIterator { - auto *Mod = psr::initSVFModule(IRDB); + psr::initSVFModule(IRDB); switch (PTATy) { case SVFPointsToAnalysisType::DDA: - return {std::make_unique>(Mod)}; + return {std::make_unique>()}; case SVFPointsToAnalysisType::VFS: - return {std::make_unique>(Mod)}; + return {std::make_unique>()}; } llvm_unreachable("Should have handled all SVFPointsToAnalysisType variants " "in the switch above!");