Skip to content

Commit cd5f556

Browse files
authored
Filtered AliasSet (#723)
* Add alias set filter * Add test * apply review comments from vulder * Add caching for reachable allocation sites * Bugfix * adding noexcept * Rename Context to AliasQueryInst in IFDSTaintAnalysis
1 parent 74baa2a commit cd5f556

File tree

9 files changed

+595
-18
lines changed

9 files changed

+595
-18
lines changed

include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ class IFDSTaintAnalysis
9999
const llvm::Function *Callee) const;
100100

101101
void populateWithMayAliases(container_type &Facts,
102-
const llvm::Instruction *Context) const;
102+
const llvm::Instruction *AliasQueryInst) const;
103103
void populateWithMustAliases(container_type &Facts,
104-
const llvm::Instruction *Context) const;
104+
const llvm::Instruction *AliasQueryInst) const;
105105
};
106106
} // namespace psr
107107

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/******************************************************************************
2+
* Copyright (c) 2020 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_FILTEREDLLVMALIASSET_H
11+
#define PHASAR_PHASARLLVM_POINTER_FILTEREDLLVMALIASSET_H
12+
13+
#include "phasar/Pointer/AliasAnalysisType.h"
14+
#include "phasar/Pointer/AliasInfoTraits.h"
15+
#include "phasar/Pointer/AliasResult.h"
16+
#include "phasar/Pointer/AliasSetOwner.h"
17+
#include "phasar/Utils/AnalysisProperties.h"
18+
#include "phasar/Utils/MaybeUniquePtr.h"
19+
20+
#include "llvm/ADT/DenseMap.h"
21+
#include "llvm/ADT/DenseMapInfo.h"
22+
#include "llvm/ADT/Hashing.h"
23+
#include "llvm/ADT/PointerIntPair.h"
24+
#include "llvm/IR/Function.h"
25+
#include "llvm/Support/ErrorHandling.h"
26+
27+
#include "nlohmann/json_fwd.hpp"
28+
29+
#include <type_traits>
30+
#include <utility>
31+
32+
namespace llvm {
33+
class Value;
34+
class Instruction;
35+
} // namespace llvm
36+
37+
namespace psr {
38+
39+
class LLVMAliasSet;
40+
class FilteredLLVMAliasSet;
41+
42+
template <>
43+
struct AliasInfoTraits<FilteredLLVMAliasSet>
44+
: DefaultAATraits<const llvm::Value *, const llvm::Instruction *> {};
45+
46+
class FilteredLLVMAliasSet {
47+
public:
48+
using alias_traits_t = AliasInfoTraits<FilteredLLVMAliasSet>;
49+
using n_t = alias_traits_t::n_t;
50+
using v_t = alias_traits_t::v_t;
51+
using AliasSetTy = alias_traits_t::AliasSetTy;
52+
using AliasSetPtrTy = alias_traits_t::AliasSetPtrTy;
53+
using AllocationSiteSetPtrTy = alias_traits_t::AllocationSiteSetPtrTy;
54+
55+
FilteredLLVMAliasSet(LLVMAliasSet *AS) noexcept;
56+
57+
FilteredLLVMAliasSet(const FilteredLLVMAliasSet &) = delete;
58+
FilteredLLVMAliasSet &operator=(const FilteredLLVMAliasSet &) = delete;
59+
FilteredLLVMAliasSet &operator=(FilteredLLVMAliasSet &&) noexcept = delete;
60+
61+
FilteredLLVMAliasSet(FilteredLLVMAliasSet &&) noexcept = default;
62+
63+
~FilteredLLVMAliasSet();
64+
65+
template <typename... ArgsT,
66+
typename = std::enable_if_t<
67+
std::is_constructible_v<LLVMAliasSet, ArgsT...>>>
68+
explicit FilteredLLVMAliasSet(ArgsT &&...Args)
69+
: FilteredLLVMAliasSet(std::forward<ArgsT>(Args)...) {}
70+
71+
// --- API Functions:
72+
73+
[[nodiscard]] inline bool isInterProcedural() const noexcept {
74+
return false;
75+
};
76+
77+
[[nodiscard]] AliasAnalysisType getAliasAnalysisType() const noexcept;
78+
79+
[[nodiscard]] AliasResult alias(const llvm::Value *V1, const llvm::Value *V2,
80+
const llvm::Instruction *I);
81+
[[nodiscard]] AliasResult alias(const llvm::Value *V1, const llvm::Value *V2,
82+
const llvm::Function *Fun);
83+
84+
[[nodiscard]] AliasSetPtrTy getAliasSet(const llvm::Value *V,
85+
const llvm::Instruction *I);
86+
[[nodiscard]] AliasSetPtrTy getAliasSet(const llvm::Value *V,
87+
const llvm::Function *Fun);
88+
89+
[[nodiscard]] AllocationSiteSetPtrTy
90+
getReachableAllocationSites(const llvm::Value *V, bool IntraProcOnly = false,
91+
const llvm::Instruction *I = nullptr);
92+
93+
// Checks if PotentialValue is in the reachable allocation sites of V.
94+
[[nodiscard]] bool isInReachableAllocationSites(
95+
const llvm::Value *V, const llvm::Value *PotentialValue,
96+
bool IntraProcOnly = false, const llvm::Instruction *I = nullptr);
97+
98+
void mergeWith(const FilteredLLVMAliasSet & /*OtherPTI*/) {
99+
llvm::report_fatal_error("Not Supported");
100+
}
101+
102+
void introduceAlias(const llvm::Value * /*V1*/, const llvm::Value * /*V2*/,
103+
const llvm::Instruction * /*I*/ = nullptr,
104+
AliasResult /*Kind*/ = AliasResult::MustAlias) {
105+
llvm::report_fatal_error("Not Supported");
106+
}
107+
108+
void print(llvm::raw_ostream &OS = llvm::outs()) const;
109+
110+
[[nodiscard]] nlohmann::json getAsJson() const;
111+
112+
void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const;
113+
114+
[[nodiscard]] AnalysisProperties getAnalysisProperties() const noexcept {
115+
return AnalysisProperties::None;
116+
}
117+
118+
private:
119+
struct ReachableAllocationSitesKey {
120+
llvm::PointerIntPair<const llvm::Function *, 1, bool> FunAndIntraProcOnly;
121+
v_t Value{};
122+
};
123+
124+
struct ReachableAllocationSitesKeyDMI {
125+
inline static ReachableAllocationSitesKey getEmptyKey() noexcept {
126+
return {{}, llvm::DenseMapInfo<v_t>::getEmptyKey()};
127+
}
128+
inline static ReachableAllocationSitesKey getTombstoneKey() noexcept {
129+
return {{}, llvm::DenseMapInfo<v_t>::getTombstoneKey()};
130+
}
131+
inline static auto getHashValue(ReachableAllocationSitesKey Key) noexcept {
132+
return llvm::hash_combine(Key.FunAndIntraProcOnly.getOpaqueValue(),
133+
Key.Value);
134+
}
135+
inline static bool isEqual(ReachableAllocationSitesKey Key1,
136+
ReachableAllocationSitesKey Key2) noexcept {
137+
return Key1.FunAndIntraProcOnly == Key2.FunAndIntraProcOnly &&
138+
Key1.Value == Key2.Value;
139+
}
140+
};
141+
142+
FilteredLLVMAliasSet(MaybeUniquePtr<LLVMAliasSet, true> AS) noexcept;
143+
144+
MaybeUniquePtr<LLVMAliasSet, /*RequireAlignment=*/true> AS;
145+
AliasSetOwner<AliasSetTy> Owner;
146+
llvm::DenseMap<std::pair<const llvm::Function *, v_t>, AliasSetPtrTy>
147+
AliasSetMap;
148+
llvm::DenseMap<ReachableAllocationSitesKey, std::unique_ptr<AliasSetTy>,
149+
ReachableAllocationSitesKeyDMI>
150+
ReachableAllocationSitesMap;
151+
};
152+
} // namespace psr
153+
154+
#endif // PHASAR_PHASARLLVM_POINTER_FILTEREDLLVMALIASSET_H

include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ struct AliasInfoTraits<LLVMAliasSet>
4646

4747
class LLVMAliasSet : public AnalysisPropertiesMixin<LLVMAliasSet>,
4848
public AliasInfoBaseUtils {
49+
// For int*IsReachableAllocationSiteTy:
50+
friend class FilteredLLVMAliasSet;
4951

5052
public:
5153
using traits_t = AliasInfoTraits<LLVMAliasSet>;

include/phasar/Pointer/AliasInfoTraits.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
#define PHASAR_POINTER_ALIASINFOTRAITS_H
1212

1313
#include "phasar/Utils/BoxedPointer.h"
14+
#include "phasar/Utils/MaybeUniquePtr.h"
1415

1516
#include "llvm/ADT/DenseSet.h"
1617

17-
#include <memory>
18-
1918
namespace psr {
2019

2120
template <typename T> struct AliasInfoTraits {
@@ -31,7 +30,7 @@ template <typename V, typename N> struct DefaultAATraits {
3130
using v_t = V;
3231
using AliasSetTy = llvm::DenseSet<v_t>;
3332
using AliasSetPtrTy = BoxedConstPtr<AliasSetTy>;
34-
using AllocationSiteSetPtrTy = std::unique_ptr<AliasSetTy>;
33+
using AllocationSiteSetPtrTy = MaybeUniquePtr<const AliasSetTy>;
3534
};
3635
} // namespace psr
3736

include/phasar/Utils/MaybeUniquePtr.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ template <typename T> class MaybeUniquePtrBase<T, true> {
5959
/// \tparam RequireAlignment If true, the datastructure only works if
6060
/// alignof(T) > 1 holds. Enables incomplete T types
6161
template <typename T, bool RequireAlignment = false>
62-
class MaybeUniquePtr : detail::MaybeUniquePtrBase<T, RequireAlignment> {
62+
class [[clang::trivial_abi]] MaybeUniquePtr
63+
: detail::MaybeUniquePtrBase<T, RequireAlignment> {
6364
using detail::MaybeUniquePtrBase<T, RequireAlignment>::Data;
6465

6566
public:
@@ -79,8 +80,9 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase<T, RequireAlignment> {
7980
: MaybeUniquePtr(Owner.release(), true) {}
8081

8182
constexpr MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept
82-
: detail::MaybeUniquePtrBase<T, RequireAlignment>(
83-
std::exchange(Other.Data, {})) {}
83+
: detail::MaybeUniquePtrBase<T, RequireAlignment>(std::move(Other)) {
84+
Other.Data = {};
85+
}
8486

8587
constexpr void swap(MaybeUniquePtr &Other) noexcept {
8688
std::swap(Data, Other.Data);

lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,17 @@ bool IFDSTaintAnalysis::isSanitizerCall(const llvm::CallBase * /*CB*/,
116116
[this](const auto &Arg) { return Config->isSanitizer(&Arg); });
117117
}
118118

119-
static bool canSkipAtContext(const llvm::Value *Val,
120-
const llvm::Instruction *Context) noexcept {
119+
static bool
120+
canSkipAtQueryInst(const llvm::Value *Val,
121+
const llvm::Instruction *AliasQueryInst) noexcept {
121122
if (const auto *Inst = llvm::dyn_cast<llvm::Instruction>(Val)) {
122123
/// Mapping instructions between functions is done via the call-FF and
123124
/// ret-FF
124-
if (Inst->getFunction() != Context->getFunction()) {
125+
if (Inst->getFunction() != AliasQueryInst->getFunction()) {
125126
return true;
126127
}
127-
if (Inst->getParent() == Context->getParent() &&
128-
Context->comesBefore(Inst)) {
128+
if (Inst->getParent() == AliasQueryInst->getParent() &&
129+
AliasQueryInst->comesBefore(Inst)) {
129130
// We will see that inst later
130131
return true;
131132
}
@@ -134,7 +135,7 @@ static bool canSkipAtContext(const llvm::Value *Val,
134135

135136
if (const auto *Arg = llvm::dyn_cast<llvm::Argument>(Val)) {
136137
// An argument is only valid in the function it belongs to
137-
if (Arg->getParent() != Context->getFunction()) {
138+
if (Arg->getParent() != AliasQueryInst->getFunction()) {
138139
return true;
139140
}
140141
}
@@ -151,12 +152,12 @@ static bool isCompiletimeConstantData(const llvm::Value *Val) noexcept {
151152
}
152153

153154
void IFDSTaintAnalysis::populateWithMayAliases(
154-
container_type &Facts, const llvm::Instruction *Context) const {
155+
container_type &Facts, const llvm::Instruction *AliasQueryInst) const {
155156
container_type Tmp = Facts;
156157
for (const auto *Fact : Facts) {
157-
auto Aliases = PT.getAliasSet(Fact);
158+
auto Aliases = PT.getAliasSet(Fact, AliasQueryInst);
158159
for (const auto *Alias : *Aliases) {
159-
if (canSkipAtContext(Alias, Context)) {
160+
if (canSkipAtQueryInst(Alias, AliasQueryInst)) {
160161
continue;
161162
}
162163

@@ -178,7 +179,7 @@ void IFDSTaintAnalysis::populateWithMayAliases(
178179
}
179180

180181
void IFDSTaintAnalysis::populateWithMustAliases(
181-
container_type &Facts, const llvm::Instruction *Context) const {
182+
container_type &Facts, const llvm::Instruction *AliasQueryInst) const {
182183
/// TODO: Find must-aliases; Currently the AliasSet only contains
183184
/// may-aliases
184185
}

0 commit comments

Comments
 (0)