Skip to content

Commit 64412c5

Browse files
authored
SVF Pointer Analyses (#767)
* Add SVF dependency + make the LLVMBasedAliasAnalysis polymorphic to allow injecting the SVF analysis * Add public interface for SVFPointsToSet * Add SVFPointsToInfo + Fix PointsToInfoBase * Fixes in PointsToInfo + add minimal tests * Add CRTPBase utility * New test + some cleanup * Fix build due to merge * minor * Simplify the SVF alias analyses + make FunctionAliasView more type-safe * minor * Regain precision * Get rid of UB + aim to resolve memory leaks with SVF * Fix SVF memory leak * pre-commit with new clang-format version * Apply review comments * Getting rid of the PSR_BIND_ALIASVIEW macro * fix compilation
1 parent 28a25b7 commit 64412c5

35 files changed

+978
-200
lines changed

.clang-tidy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ Checks: '-*,
2929
-cppcoreguidelines-init-variables,
3030
-cppcoreguidelines-macro-usage,
3131
-cppcoreguidelines-avoid-do-while,
32+
-cppcoreguidelines-avoid-c-arrays,
3233
bugprone-*,
3334
-bugprone-easily-swappable-parameters,
3435
modernize-*,
3536
-modernize-use-trailing-return-type,
37+
-modernize-avoid-c-arrays,
3638
performance-*,
3739
clang-analyzer-*
3840
'

.gitignore

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,8 @@ doc/*
3030
log/*
3131
**/*/logs/
3232

33-
# CMake build dir
34-
build/*
35-
3633
# MS VS Code
37-
.vscode/*
34+
.vscode/
3835

3936
# Eclipse
4037
.cproject

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,18 @@ endif()
308308
include(add_llvm)
309309
add_llvm()
310310

311+
# SVF
312+
option(PHASAR_USE_SVF "Use SVF for more options in alias analysis (default is OFF)" OFF)
313+
if(PHASAR_USE_SVF)
314+
find_package(SVF REQUIRED CONFIG)
315+
message(STATUS "Found SVF ${SVF_VERSION}")
316+
317+
if (NOT PHASAR_USE_Z3)
318+
message(WARNING "SVF requires Z3. Set PHASAR_USE_Z3=ON")
319+
set(PHASAR_USE_Z3 ON)
320+
endif()
321+
endif()
322+
311323
# Z3 Solver
312324
if(PHASAR_IN_TREE)
313325
set (PHASAR_USE_Z3 OFF)

config.h.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@
1313

1414
#cmakedefine PHASAR_HAS_SQLITE
1515

16+
#cmakedefine PHASAR_USE_SVF
17+
1618
#endif /* PHASAR_CONFIG_CONFIG_H */

include/phasar/ControlFlow/CFGBase.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define PHASAR_CONTROLFLOW_CFGBASE_H
1212

1313
#include "phasar/Utils/ByRef.h"
14+
#include "phasar/Utils/CRTPUtils.h"
1415
#include "phasar/Utils/TypeTraits.h"
1516

1617
namespace psr {
@@ -22,7 +23,12 @@ template <typename T> struct CFGTraits {
2223
// using f_t
2324
};
2425

25-
template <typename Derived> class CFGBase {
26+
template <typename Derived> class CFGBase : public CRTPBase<Derived> {
27+
friend Derived;
28+
29+
protected:
30+
using CRTPBase<Derived>::self;
31+
2632
public:
2733
using n_t = typename CFGTraits<Derived>::n_t;
2834
using f_t = typename CFGTraits<Derived>::f_t;
@@ -129,19 +135,14 @@ template <typename Derived> class CFGBase {
129135
void print(ByConstRef<f_t> Fun, llvm::raw_ostream &OS) const {
130136
self().printImpl(Fun, OS);
131137
}
132-
133-
protected:
134-
Derived &self() noexcept { return static_cast<Derived &>(*this); }
135-
const Derived &self() const noexcept {
136-
return static_cast<const Derived &>(*this);
137-
}
138138
};
139139

140140
template <typename ICF, typename Domain>
141141
// NOLINTNEXTLINE(readability-identifier-naming)
142-
PSR_CONCEPT is_cfg_v = is_crtp_base_of_v<CFGBase, ICF>
143-
&&std::is_same_v<typename ICF::n_t, typename Domain::n_t>
144-
&&std::is_same_v<typename ICF::f_t, typename Domain::f_t>;
142+
PSR_CONCEPT is_cfg_v =
143+
is_crtp_base_of_v<CFGBase, ICF> &&
144+
std::is_same_v<typename ICF::n_t, typename Domain::n_t> &&
145+
std::is_same_v<typename ICF::f_t, typename Domain::f_t>;
145146

146147
} // namespace psr
147148

include/phasar/ControlFlow/CallGraphBase.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define PHASAR_CONTROLFLOW_CALLGRAPHBASE_H
1212

1313
#include "phasar/Utils/ByRef.h"
14+
#include "phasar/Utils/CRTPUtils.h"
1415
#include "phasar/Utils/TypeTraits.h"
1516

1617
namespace psr {
@@ -22,7 +23,10 @@ template <typename T> struct CGTraits {
2223
/// Base class of all CallGraph implementations within phasar (currently only
2324
/// CallGraph<N, F>).
2425
/// Only represents the data, not how to create it.
25-
template <typename Derived> class CallGraphBase {
26+
template <typename Derived> class CallGraphBase : public CRTPBase<Derived> {
27+
friend Derived;
28+
using CRTPBase<Derived>::self;
29+
2630
public:
2731
using n_t = typename CGTraits<Derived>::n_t;
2832
using f_t = typename CGTraits<Derived>::f_t;
@@ -46,11 +50,6 @@ template <typename Derived> class CallGraphBase {
4650
is_iterable_over_v<decltype(self().getCallersOfImpl(Fun)), n_t>);
4751
return self().getCallersOfImpl(Fun);
4852
}
49-
50-
private:
51-
const Derived &self() const noexcept {
52-
return static_cast<const Derived &>(*this);
53-
}
5453
};
5554
} // namespace psr
5655

include/phasar/ControlFlow/ICFGBase.h

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "phasar/ControlFlow/CFGBase.h"
1414
#include "phasar/ControlFlow/CallGraphBase.h"
15+
#include "phasar/Utils/CRTPUtils.h"
1516
#include "phasar/Utils/TypeTraits.h"
1617

1718
#include "llvm/ADT/StringRef.h"
@@ -20,16 +21,14 @@
2021
#include <type_traits>
2122

2223
namespace psr {
23-
template <typename Derived> class ICFGBase {
24+
template <typename Derived> class ICFGBase : public CRTPBase<Derived> {
25+
friend Derived;
26+
using CRTPBase<Derived>::self;
27+
2428
public:
2529
using n_t = typename CFGTraits<Derived>::n_t;
2630
using f_t = typename CFGTraits<Derived>::f_t;
2731

28-
ICFGBase() noexcept {
29-
static_assert(is_crtp_base_of_v<CFGBase, Derived>,
30-
"An ICFG must also be a CFG");
31-
}
32-
3332
/// Returns an iterable range of all function definitions or declarations in
3433
/// the ICFG
3534
[[nodiscard]] decltype(auto) getAllFunctions() const {
@@ -113,20 +112,16 @@ template <typename Derived> class ICFGBase {
113112
[[nodiscard]] size_t getNumCallSites() const noexcept {
114113
return self().getNumCallSitesImpl();
115114
}
116-
117-
private:
118-
const Derived &self() const noexcept {
119-
return static_cast<const Derived &>(*this);
120-
}
121115
};
122116

123117
/// True, iff ICF is a proper instantiation of ICFGBase with n_t and f_t taken
124118
/// from the given analysis-Domain
125119
template <typename ICF, typename Domain>
126120
// NOLINTNEXTLINE(readability-identifier-naming)
127-
PSR_CONCEPT is_icfg_v = is_crtp_base_of_v<ICFGBase, ICF>
128-
&&std::is_same_v<typename ICF::n_t, typename Domain::n_t>
129-
&&std::is_same_v<typename ICF::f_t, typename Domain::f_t>;
121+
PSR_CONCEPT is_icfg_v =
122+
is_crtp_base_of_v<ICFGBase, ICF> &&
123+
std::is_same_v<typename ICF::n_t, typename Domain::n_t> &&
124+
std::is_same_v<typename ICF::f_t, typename Domain::f_t>;
130125

131126
} // namespace psr
132127

include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ template <> struct CFGTraits<LLVMBasedBackwardCFG> : CFGTraits<LLVMBasedCFG> {};
3838

3939
namespace detail {
4040
template <typename Derived> class LLVMBasedCFGImpl : public CFGBase<Derived> {
41-
friend CFGBase<Derived>;
4241
friend class LLVMBasedBackwardCFG;
4342

4443
public:

include/phasar/PhasarLLVM/Pointer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
#ifndef PHASAR_PHASARLLVM_POINTER_H
1111
#define PHASAR_PHASARLLVM_POINTER_H
1212

13+
#include "phasar/PhasarLLVM/Pointer/AliasAnalysisView.h"
1314
#include "phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h"
1415
#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h"
1516
#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h"
16-
#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h"
1717
#include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h"
1818

1919
#endif // PHASAR_PHASARLLVM_POINTER_H
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/******************************************************************************
2+
* Copyright (c) 2025 Fabian Schiebel.
3+
* All rights reserved. This program and the accompanying materials are made
4+
* available under the terms of LICENSE.txt.
5+
*
6+
* Contributors:
7+
* Fabian Schiebel and others
8+
*****************************************************************************/
9+
10+
#ifndef PHASAR_PHASARLLVM_POINTER_ALIASANALYSISVIEW_H
11+
#define PHASAR_PHASARLLVM_POINTER_ALIASANALYSISVIEW_H
12+
13+
#include "phasar/Pointer/AliasAnalysisType.h"
14+
#include "phasar/Pointer/AliasResult.h"
15+
16+
#include <memory>
17+
#include <type_traits>
18+
19+
namespace llvm {
20+
class Value;
21+
class DataLayout;
22+
class Function;
23+
} // namespace llvm
24+
25+
namespace psr {
26+
class LLVMProjectIRDB;
27+
28+
class FunctionAliasView {
29+
public:
30+
template <typename T>
31+
using AliasCallbackTy = AliasResult (*)(T *, const llvm::Value *,
32+
const llvm::Value *,
33+
const llvm::DataLayout &);
34+
35+
[[nodiscard]] AliasResult alias(const llvm::Value *V, const llvm::Value *Rep,
36+
const llvm::DataLayout &DL) {
37+
return Alias(Context, V, Rep, DL);
38+
}
39+
40+
template <
41+
typename T, typename AliasFn,
42+
typename = std::enable_if_t<std::is_empty_v<AliasFn> &&
43+
std::is_default_constructible_v<AliasFn>>>
44+
constexpr FunctionAliasView(T *Context, AliasFn /*Alias*/) noexcept
45+
: Context(Context), Alias(&callAlias<T, AliasFn>) {}
46+
47+
private:
48+
template <typename T, typename AliasFn>
49+
static AliasResult callAlias(void *Context, const llvm::Value *V1,
50+
const llvm::Value *V2,
51+
const llvm::DataLayout &DL) {
52+
return AliasFn{}(static_cast<T *>(Context), V1, V2, DL);
53+
}
54+
55+
void *Context{};
56+
AliasCallbackTy<void> Alias{};
57+
};
58+
59+
class AliasAnalysisView {
60+
public:
61+
constexpr AliasAnalysisView(AliasAnalysisType PATy) noexcept : PATy(PATy) {}
62+
63+
virtual ~AliasAnalysisView() = default;
64+
65+
[[nodiscard]] FunctionAliasView getAAResults(const llvm::Function *F) {
66+
assert(F != nullptr);
67+
return doGetAAResults(F);
68+
}
69+
70+
void erase(llvm::Function *F) noexcept {
71+
assert(F != nullptr);
72+
doErase(F);
73+
}
74+
75+
void clear() noexcept { doClear(); }
76+
77+
[[nodiscard]] constexpr AliasAnalysisType
78+
getPointerAnalysisType() const noexcept {
79+
return PATy;
80+
};
81+
82+
[[nodiscard]] static std::unique_ptr<AliasAnalysisView>
83+
create(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation, AliasAnalysisType PATy);
84+
85+
private:
86+
static std::unique_ptr<AliasAnalysisView>
87+
createLLVMBasedAnalysis(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation,
88+
AliasAnalysisType PATy);
89+
90+
virtual FunctionAliasView doGetAAResults(const llvm::Function *F) = 0;
91+
virtual void doErase(llvm::Function *F) noexcept = 0;
92+
virtual void doClear() noexcept = 0;
93+
94+
AliasAnalysisType PATy{};
95+
};
96+
97+
} // namespace psr
98+
99+
#endif // PHASAR_PHASARLLVM_POINTER_ALIASANALYSISVIEW_H

0 commit comments

Comments
 (0)