Skip to content

Commit c484261

Browse files
authored
Cleanup FlowFunction Templates (#550)
* Abstract away creating flow functions based on the common templates from FlowFunctions.h. TODO: LLVMFlowFunctions.h + move custom flow functions to lambdaFlow in order to get rid of the shared_ptr occurrences in analysis code + document the flow-function templates * Rewrite and simplify LLVMFlowFunctions * Add comments to the flow function templates in FlowFunctions.h * Mark old flow function templates as deprecated * FIx mapFactsAlongsideCallSite() + make callbacks of flow function tempaltes type-safe * Modernize flow functions of LCA * Documentation comments on LLVMFlowFunctions * Split parameter-predicate and return-value-predicate for the mapFactsToCaller flow function based on review comment
1 parent 5a9c59f commit c484261

File tree

14 files changed

+1384
-893
lines changed

14 files changed

+1384
-893
lines changed

include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h

Lines changed: 853 additions & 304 deletions
Large diffs are not rendered by default.

include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ class IDETabulationProblem : public FlowFunctions<AnalysisDomainTy, Container>,
123123
virtual bool setSoundness(Soundness /*S*/) { return false; }
124124

125125
protected:
126+
typename FlowFunctions<AnalysisDomainTy, Container>::FlowFunctionPtrType
127+
generateFromZero(d_t FactToGenerate) {
128+
return generateFlow(std::move(FactToGenerate), getZeroValue());
129+
}
130+
126131
const db_t *IRDB{};
127132
std::vector<std::string> EntryPoints;
128133
std::optional<d_t> ZeroValue;

include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h

Lines changed: 367 additions & 351 deletions
Large diffs are not rendered by default.

include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ template <typename EdgeFactType = std::string,
184184
class IDEInstInteractionAnalysisT
185185
: public IDETabulationProblem<
186186
IDEInstInteractionAnalysisDomain<EdgeFactType>> {
187+
using IDETabulationProblem<
188+
IDEInstInteractionAnalysisDomain<EdgeFactType>>::generateFromZero;
189+
187190
public:
188191
using AnalysisDomainTy = IDEInstInteractionAnalysisDomain<EdgeFactType>;
189192

@@ -242,7 +245,7 @@ class IDEInstInteractionAnalysisT
242245
//
243246
if (const auto *Alloca = llvm::dyn_cast<llvm::AllocaInst>(Curr)) {
244247
PHASAR_LOG_LEVEL(DFADEBUG, "AllocaInst");
245-
return std::make_shared<Gen<d_t>>(Alloca, this->getZeroValue());
248+
return generateFromZero(Alloca);
246249
}
247250

248251
// Handle indirect taints, i. e., propagate values that depend on branch
@@ -414,7 +417,7 @@ class IDEInstInteractionAnalysisT
414417
// 0 y x
415418
//
416419
if (const auto *Load = llvm::dyn_cast<llvm::LoadInst>(Curr)) {
417-
return std::make_shared<Gen<d_t>>(Load, Load->getPointerOperand());
420+
return generateFlow<d_t>(Load, Load->getPointerOperand());
418421
}
419422
// Handle store instructions
420423
//
@@ -564,11 +567,11 @@ class IDEInstInteractionAnalysisT
564567
f_t DestFun) override {
565568
if (this->ICF->isHeapAllocatingFunction(DestFun)) {
566569
// Kill add facts and model the effects in getCallToRetFlowFunction().
567-
return KillAll<d_t>::getInstance();
570+
return killAllFlows<d_t>();
568571
}
569572
if (DestFun->isDeclaration()) {
570573
// We don't have anything that we could analyze, kill all facts.
571-
return KillAll<d_t>::getInstance();
574+
return killAllFlows<d_t>();
572575
}
573576
const auto *CS = llvm::cast<llvm::CallBase>(CallSite);
574577
// Map actual to formal parameters.
@@ -609,7 +612,7 @@ class IDEInstInteractionAnalysisT
609612
return {};
610613
}
611614
// Pass ZeroValue as is, if desired
612-
if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source)) {
615+
if (LLVMZeroValue::isLLVMZeroValue(Source)) {
613616
return {Source};
614617
}
615618
container_type Res;
@@ -678,10 +681,10 @@ class IDEInstInteractionAnalysisT
678681
SRetFormals.insert(DestFun->getArg(Idx));
679682
}
680683
}
681-
auto GenSRetFormals = std::make_shared<GenAllAndKillAllOthers<d_t>>(
682-
SRetFormals, this->getZeroValue());
683-
return std::make_shared<Union<d_t>>(
684-
std::vector<FlowFunctionPtrType>({MapFactsToCalleeFF, GenSRetFormals}));
684+
685+
return unionFlows(std::move(MapFactsToCalleeFF),
686+
generateManyFlowsAndKillAllOthers(std::move(SRetFormals),
687+
this->getZeroValue()));
685688
}
686689

687690
inline FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun,
@@ -712,7 +715,7 @@ class IDEInstInteractionAnalysisT
712715

713716
std::set<IDEIIAFlowFact> computeTargets(IDEIIAFlowFact Source) override {
714717
// Pass ZeroValue as is, if desired
715-
if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source.getBase())) {
718+
if (LLVMZeroValue::isLLVMZeroValue(Source.getBase())) {
716719
return {Source};
717720
}
718721
// Pass global variables as is, if desired
@@ -778,11 +781,9 @@ class IDEInstInteractionAnalysisT
778781
// Generate the respective callsite. The callsite will receive its
779782
// value from this very return instruction cf.
780783
// getReturnEdgeFunction().
781-
auto ConstantRetGen = std::make_shared<GenAndKillAllOthers<d_t>>(
782-
CallSite, this->getZeroValue());
783-
return std::make_shared<Union<d_t>>(
784-
std::vector<FlowFunctionPtrType>(
785-
{MapFactsToCallerFF, ConstantRetGen}));
784+
return unionFlows(std::move(MapFactsToCallerFF),
785+
generateFlowAndKillAllOthers<d_t>(
786+
CallSite, this->getZeroValue()));
786787
}
787788
}
788789
}
@@ -811,7 +812,7 @@ class IDEInstInteractionAnalysisT
811812
// v v
812813
// 0 x
813814
//
814-
return std::make_shared<Gen<d_t>>(CallSite, this->getZeroValue());
815+
return generateFromZero(CallSite);
815816
}
816817
}
817818
}

include/phasar/Utils/TypeTraits.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,29 @@ constexpr bool is_string_like_v = std::is_convertible_v<T, std::string_view>;
174174
template <template <typename> typename Base, typename Derived>
175175
constexpr bool is_crtp_base_of_v = // NOLINT
176176
detail::is_crtp_base_of<Base, Derived>::value;
177+
178+
#if __cplusplus < 202002L
179+
template <typename T> struct type_identity { using type = T; }; // NOLINT
180+
#else
181+
template <typename T> using type_identity = std::type_identity<T>;
182+
#endif
183+
184+
template <typename T> using type_identity_t = typename type_identity<T>::type;
185+
186+
struct TrueFn {
187+
template <typename... Args>
188+
[[nodiscard]] bool operator()(const Args &.../*unused*/) const noexcept {
189+
return true;
190+
}
191+
};
192+
193+
struct FalseFn {
194+
template <typename... Args>
195+
[[nodiscard]] bool operator()(const Args &.../*unused*/) const noexcept {
196+
return false;
197+
}
198+
};
199+
177200
// NOLINTEND(readability-identifier-naming)
178201
} // namespace psr
179202

lib/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ IDEExtendedTaintAnalysis::getNormalFlowFunction(n_t Curr,
109109
}
110110

111111
if (const auto *Phi = llvm::dyn_cast<llvm::PHINode>(Curr)) {
112-
return makeLambdaFlow<d_t>([this, Phi](d_t Source) -> std::set<d_t> {
112+
return lambdaFlow<d_t>([this, Phi](d_t Source) -> std::set<d_t> {
113113
auto NumOps = Phi->getNumIncomingValues();
114114
for (unsigned I = 0; I < NumOps; ++I) {
115115
if (equivalent(Source, makeFlowFact(Phi->getIncomingValue(I)))) {
@@ -136,8 +136,8 @@ IDEExtendedTaintAnalysis::getStoreFF(const llvm::Value *PointerOp,
136136
PointsToInfo<v_t, n_t>::PointsToSetPtrTy PTS = nullptr;
137137

138138
auto Mem = makeFlowFact(PointerOp);
139-
return makeLambdaFlow<d_t>([this, TV, Mem, PTS, PointerOp, ValueOp, Store,
140-
PALevel](d_t Source) mutable -> std::set<d_t> {
139+
return lambdaFlow<d_t>([this, TV, Mem, PTS, PointerOp, ValueOp, Store,
140+
PALevel](d_t Source) mutable -> std::set<d_t> {
141141
if (Source->isZero()) {
142142
std::set<d_t> Ret = {Source};
143143
generateFromZero(Ret, Store, PointerOp, ValueOp,
@@ -282,8 +282,8 @@ auto IDEExtendedTaintAnalysis::handleConfig(const llvm::Instruction *Inst,
282282
populateWithMayAliases(SourceConfig);
283283
}
284284

285-
return makeLambdaFlow<d_t>([Inst, this, SourceConfig{std::move(SourceConfig)},
286-
SinkConfig{std::move(SinkConfig)}](d_t Source) {
285+
return lambdaFlow<d_t>([Inst, this, SourceConfig{std::move(SourceConfig)},
286+
SinkConfig{std::move(SinkConfig)}](d_t Source) {
287287
std::set<d_t> Ret = {Source};
288288

289289
if (Source->isZero()) {
@@ -314,8 +314,8 @@ IDEExtendedTaintAnalysis::getCallFlowFunction(n_t CallStmt, f_t DestFun) {
314314
bool HasVarargs = Call->arg_size() > DestFun->arg_size();
315315
const auto *const VA = HasVarargs ? getVAListTagOrNull(DestFun) : nullptr;
316316

317-
return makeLambdaFlow<d_t>([this, Call, DestFun,
318-
VA](d_t Source) -> std::set<d_t> {
317+
return lambdaFlow<d_t>([this, Call, DestFun,
318+
VA](d_t Source) -> std::set<d_t> {
319319
if (isZeroValue(Source)) {
320320
return {Source};
321321
}
@@ -403,7 +403,7 @@ IDEExtendedTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t CalleeFun,
403403
if (!CallSite) {
404404
/// In case of unbalanced return, we may reach the artificial Global Ctor
405405
/// caller that has no caller
406-
return makeEF<KillIf<d_t>>([](d_t Source) {
406+
return killFlowIf<d_t>([](d_t Source) {
407407
return !llvm::isa_and_nonnull<llvm::GlobalValue>(Source->base());
408408
});
409409
}
@@ -430,11 +430,11 @@ IDEExtendedTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t CalleeFun,
430430
};
431431

432432
const auto *Call = llvm::cast<llvm::CallBase>(CallSite);
433-
return makeLambdaFlow<d_t>([this, Call, CalleeFun,
434-
ExitStmt{llvm::cast<llvm::ReturnInst>(ExitStmt)},
435-
PTC{ArgPointsToCache(PT, Call->arg_size(),
436-
HasPrecisePointsToInfo)}](
437-
d_t Source) -> std::set<d_t> {
433+
return lambdaFlow<d_t>([this, Call, CalleeFun,
434+
ExitStmt{llvm::cast<llvm::ReturnInst>(ExitStmt)},
435+
PTC{ArgPointsToCache(PT, Call->arg_size(),
436+
HasPrecisePointsToInfo)}](
437+
d_t Source) -> std::set<d_t> {
438438
if (isZeroValue(Source)) {
439439
return {Source};
440440
}
@@ -506,7 +506,7 @@ IDEExtendedTaintAnalysis::getCallToRetFlowFunction(
506506
// into
507507
// // that function
508508

509-
// return makeLambdaFlow<d_t>([CallSite, this](d_t Source) -> std::set<d_t>
509+
// return lambdaFlow<d_t>([CallSite, this](d_t Source) -> std::set<d_t>
510510
// {
511511
// if (isZeroValue(Source)) {
512512
// return {};
@@ -550,7 +550,7 @@ IDEExtendedTaintAnalysis::getCallToRetFlowFunction(
550550
return Identity<d_t>::getInstance();
551551
}
552552

553-
return makeFF<Kill<d_t>>(getZeroValue());
553+
return killFlow(getZeroValue());
554554
}
555555

556556
IDEExtendedTaintAnalysis::FlowFunctionPtrType

lib/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h"
1313
#include "phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h"
1414
#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h"
15+
#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h"
1516
#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h"
1617
#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h"
1718
#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h"
@@ -37,8 +38,8 @@ using namespace glca;
3738

3839
template <typename Fn, typename = std::enable_if_t<
3940
std::is_invocable_v<Fn, IDEGeneralizedLCA::d_t>>>
40-
inline std::shared_ptr<FlowFunction<IDEGeneralizedLCA::d_t>> flow(Fn Func) {
41-
return makeLambdaFlow<IDEGeneralizedLCA::d_t>(std::forward<Fn>(Func));
41+
inline auto flow(Fn Func) {
42+
return lambdaFlow<IDEGeneralizedLCA::d_t>(std::forward<Fn>(Func));
4243
}
4344

4445
IDEGeneralizedLCA::IDEGeneralizedLCA(const LLVMProjectIRDB *IRDB,
@@ -59,9 +60,10 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr,
5960
const auto *ValueOp = Store->getValueOperand();
6061
if (isConstant(ValueOp)) {
6162
// llvm::outs() << "==> constant store" << std::endl;
62-
return flow([=](IDEGeneralizedLCA::d_t Source)
63-
-> std::set<IDEGeneralizedLCA::d_t> {
64-
// llvm::outs() << "##> normal flow for: " << llvmIRToString(curr)
63+
return lambdaFlow<d_t>([=](IDEGeneralizedLCA::d_t Source)
64+
-> std::set<IDEGeneralizedLCA::d_t> {
65+
// llvm::outs() << "##> normal lambdaFlow<d_t> for: " <<
66+
// llvmIRToString(curr)
6567
// << " with " << llvmIRToString(source) << std::endl;
6668
if (Source == PointerOp) {
6769
return {};
@@ -72,7 +74,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr,
7274
return {Source};
7375
});
7476
}
75-
return flow(
77+
return lambdaFlow<d_t>(
7678
[=](IDEGeneralizedLCA::d_t Source) -> std::set<IDEGeneralizedLCA::d_t> {
7779
if (Source == PointerOp) {
7880
return {};
@@ -84,7 +86,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr,
8486
});
8587
}
8688
if (const auto *Load = llvm::dyn_cast<llvm::LoadInst>(Curr)) {
87-
return flow(
89+
return lambdaFlow<d_t>(
8890
[=](IDEGeneralizedLCA::d_t Source) -> std::set<IDEGeneralizedLCA::d_t> {
8991
// llvm::outs() << "LOAD " << llvmIRToString(curr) << std::endl;
9092
// llvm::outs() << "\twith " << llvmIRToString(source) << " ==> ";
@@ -97,7 +99,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr,
9799
});
98100
}
99101
if (const auto *Gep = llvm::dyn_cast<llvm::GetElementPtrInst>(Curr)) {
100-
return flow(
102+
return lambdaFlow<d_t>(
101103
[=](IDEGeneralizedLCA::d_t Source) -> std::set<IDEGeneralizedLCA::d_t> {
102104
if (Source == Gep->getPointerOperand()) {
103105
return {Source, Gep};
@@ -111,7 +113,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr,
111113
Cast->getSrcTy()->isFloatingPointTy()) &&
112114
(Cast->getDestTy()->isIntegerTy() ||
113115
Cast->getDestTy()->isFloatingPointTy())) {
114-
return flow(
116+
return lambdaFlow<d_t>(
115117
[=](IDEGeneralizedLCA::d_t Source) -> std::set<IDEGeneralizedLCA::d_t> {
116118
if (Source == Cast->getOperand(0)) {
117119
return {Source, Cast};
@@ -127,7 +129,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr,
127129
bool BothConst = LeftConst && RightConst;
128130
bool NoneConst = !LeftConst && !RightConst;
129131

130-
return flow(
132+
return lambdaFlow<d_t>(
131133
[=](IDEGeneralizedLCA::d_t Source) -> std::set<IDEGeneralizedLCA::d_t> {
132134
if (Source == Lhs || Source == Rhs ||
133135
((BothConst || NoneConst) && isZeroValue(Source))) {
@@ -137,7 +139,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr,
137139
});
138140
} /*else if (llvm::isa<llvm::UnaryOperator>(curr)) {
139141
auto op = curr->getOperand(0);
140-
return flow([=](IDEGeneralizedLCA::d_t source)
142+
return lambdaFlow<d_t>([=](IDEGeneralizedLCA::d_t source)
141143
-> std::set<IDEGeneralizedLCA::d_t> {
142144
if (source == op)
143145
return {source, curr};
@@ -155,7 +157,7 @@ IDEGeneralizedLCA::getCallFlowFunction(IDEGeneralizedLCA::n_t CallStmt,
155157
assert(llvm::isa<llvm::CallBase>(CallStmt));
156158
if (isStringConstructor(DestMthd)) {
157159
// kill all data-flow facts at calls to string constructors
158-
return KillAll<IDEGeneralizedLCA::d_t>::getInstance();
160+
return killAllFlows<d_t>();
159161
}
160162
return std::make_shared<MapFactsToCalleeFlowFunction>(
161163
llvm::cast<llvm::CallBase>(CallStmt), DestMthd);
@@ -167,7 +169,8 @@ IDEGeneralizedLCA::getRetFlowFunction(IDEGeneralizedLCA::n_t CallSite,
167169
IDEGeneralizedLCA::n_t ExitStmt,
168170
IDEGeneralizedLCA::n_t /*RetSite*/) {
169171
assert(llvm::isa<llvm::CallBase>(CallSite));
170-
// llvm::outs() << "Ret flow: " << llvmIRToString(ExitStmt) << std::endl;
172+
// llvm::outs() << "Ret flow: " << llvmIRToString(ExitStmt) <<
173+
// std::endl;
171174
/*return std::make_shared<MapFactsToCaller>(
172175
llvm::ImmutableCallSite(callSite), calleeMthd, exitStmt,
173176
[](const llvm::Value *v) -> bool {
@@ -181,16 +184,16 @@ std::shared_ptr<FlowFunction<IDEGeneralizedLCA::d_t>>
181184
IDEGeneralizedLCA::getCallToRetFlowFunction(IDEGeneralizedLCA::n_t CallSite,
182185
IDEGeneralizedLCA::n_t /*RetSite*/,
183186
llvm::ArrayRef<f_t> /*Callees*/) {
184-
// llvm::outs() << "CTR flow: " << llvmIRToString(CallSite) << std::endl;
187+
// llvm::outs() << "CTR flow: " << llvmIRToString(CallSite) <<
188+
// std::endl;
185189
if (const auto *CS = llvm::dyn_cast<llvm::CallBase>(CallSite)) {
186190
// check for ctor and then demangle function name and check for
187191
// std::basic_string
188192
if (isStringConstructor(CS->getCalledFunction())) {
189193
// found std::string ctor
190-
return std::make_shared<Gen<IDEGeneralizedLCA::d_t>>(CS->getArgOperand(0),
191-
getZeroValue());
194+
return generateFromZero(CS->getArgOperand(0));
192195
}
193-
// return flow([Call](IDEGeneralizedLCA::d_t Source)
196+
// return lambdaFlow<d_t>([Call](IDEGeneralizedLCA::d_t Source)
194197
// -> std::set<IDEGeneralizedLCA::d_t> {
195198
// // llvm::outs() << "In getCallToRetFlowFunction\n";
196199
// // llvm::outs() << llvmIRToString(Source) << '\n';

0 commit comments

Comments
 (0)