Skip to content

Commit d9d0b65

Browse files
fabianbs96mxHuber
andauthored
Sparse IDE (#714)
* Start with sparse ICFG * Build sparse CFG (not tested yet) * Integrate Sparse CFG into IDESolver + add test (WIP) * Make sparse IDE work for linear constant analysis * Add taint analysis to SparseIDETest (passes) -- NO SPARSITY!! * minor * Select right opt tool for mem2reg * Introduce PSR_FWD * Integrate sparse ifds taint analysis into phasar-cli * Fix build after merge from dev +relax opt path requirement * Fix opt-tool selection * fallback * Fixed seqfault if find() = end() * AliasAnalysis for fuzzyMayAlias * changed to LLVMAliasInfoRef * some cleanup * minor * Fix build due to merge --------- Co-authored-by: mxHuber <[email protected]>
1 parent 751a984 commit d9d0b65

26 files changed

+1053
-21
lines changed

.clang-tidy

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Checks: '-*,
1717
-readability-convert-member-functions-to-static,
1818
-readability-isolate-declaration,
1919
-readability-identifier-length,
20+
-readability-redundant-member-init,
21+
-readability-use-anyofallof,
2022
cppcoreguidelines-*,
2123
-cppcoreguidelines-avoid-non-const-global-variables,
2224
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ set(RELEASE_CONFIGURATIONS RELWITHDEBINFO RELEASE CACHE INTERNAL "" FORCE)
7171
# https://reviews.llvm.org/D157613
7272

7373
string(APPEND CMAKE_CXX_FLAGS " -MP -fstack-protector-strong -ffunction-sections -fdata-sections -pipe")
74-
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og -fno-omit-frame-pointer")
74+
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer")
7575
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-omit-frame-pointer")
7676
string(APPEND CMAKE_CXX_FLAGS_RELEASE "")
7777

config/double-free-config.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "double-free",
3+
"version": 1.0,
4+
"functions": [
5+
{
6+
"name": "free",
7+
"params": {
8+
"source": [
9+
0
10+
],
11+
"sink": [
12+
0
13+
]
14+
}
15+
},
16+
{
17+
"name": "_ZdlPv",
18+
"params": {
19+
"source": [
20+
0
21+
],
22+
"sink": [
23+
0
24+
]
25+
}
26+
}
27+
]
28+
}

include/phasar/ControlFlow/CFGBase.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ template <typename Derived> class CFGBase {
136136
return self().getAsJsonImpl(Fun);
137137
}
138138

139-
private:
139+
protected:
140140
Derived &self() noexcept { return static_cast<Derived &>(*this); }
141141
const Derived &self() const noexcept {
142142
return static_cast<const Derived &>(*this);
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/******************************************************************************
2+
* Copyright (c) 2024 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_CONTROLFLOW_SPARSECFGBASE_H
11+
#define PHASAR_CONTROLFLOW_SPARSECFGBASE_H
12+
13+
#include "phasar/ControlFlow/CFGBase.h"
14+
#include "phasar/Utils/ByRef.h"
15+
#include "phasar/Utils/Nullable.h"
16+
17+
namespace psr {
18+
template <typename Derived> class SparseCFGBase : public CFGBase<Derived> {
19+
public:
20+
using typename CFGBase<Derived>::n_t;
21+
using typename CFGBase<Derived>::f_t;
22+
23+
/// Gets the next instruction in control-flow order, starting from
24+
/// FromInstruction, that may use or define Val.
25+
/// If the next user is ambiguous, returns null.
26+
[[nodiscard]] Nullable<n_t>
27+
nextUserOrNull(ByConstRef<n_t> FromInstruction) const {
28+
return self().nextUserOrNullImpl(FromInstruction);
29+
}
30+
31+
protected:
32+
using CFGBase<Derived>::self;
33+
};
34+
35+
template <typename ICF, typename Domain>
36+
// NOLINTNEXTLINE(readability-identifier-naming)
37+
constexpr bool is_sparse_cfg_v = is_crtp_base_of_v<SparseCFGBase, ICF>
38+
&&std::is_same_v<typename ICF::n_t, typename Domain::n_t>
39+
&&std::is_same_v<typename ICF::f_t, typename Domain::f_t>;
40+
41+
} // namespace psr
42+
43+
#endif // PHASAR_CONTROLFLOW_SPARSECFGBASE_H
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/******************************************************************************
2+
* Copyright (c) 2024 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_CONTROLFLOW_SPARSECFGPROVIDER_H
11+
#define PHASAR_CONTROLFLOW_SPARSECFGPROVIDER_H
12+
13+
#include "phasar/Utils/ByRef.h"
14+
15+
#include <type_traits>
16+
17+
namespace psr {
18+
template <typename T> T valueOf(T Val) { return Val; }
19+
20+
template <typename Derived, typename F, typename V> class SparseCFGProvider {
21+
public:
22+
using f_t = F;
23+
using v_t = V;
24+
25+
template <typename D>
26+
[[nodiscard]] decltype(auto) getSparseCFG(ByConstRef<f_t> Fun,
27+
const D &Val) const {
28+
using psr::valueOf;
29+
static_assert(std::is_convertible_v<decltype(valueOf(Val)), v_t>);
30+
return self().getSparseCFGImpl(Fun, valueOf(Val));
31+
}
32+
33+
private:
34+
Derived &self() noexcept { return static_cast<Derived &>(*this); }
35+
const Derived &self() const noexcept {
36+
return static_cast<const Derived &>(*this);
37+
}
38+
};
39+
40+
template <typename T, typename D, typename = void>
41+
struct has_getSparseCFG : std::false_type {}; // NOLINT
42+
template <typename T, typename D>
43+
struct has_getSparseCFG<
44+
T, D,
45+
std::void_t<decltype(std::declval<const T>().getSparseCFG(
46+
std::declval<typename T::f_t>(), std::declval<D>()))>>
47+
: std::true_type {};
48+
49+
template <typename T, typename D>
50+
// NOLINTNEXTLINE
51+
static constexpr bool has_getSparseCFG_v = has_getSparseCFG<T, D>::value;
52+
} // namespace psr
53+
54+
#endif // PHASAR_CONTROLFLOW_SPARSECFGPROVIDER_H

include/phasar/DataFlow/IfdsIde/FlowFunctions.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef PHASAR_DATAFLOW_IFDSIDE_FLOWFUNCTIONS_H
1818
#define PHASAR_DATAFLOW_IFDSIDE_FLOWFUNCTIONS_H
1919

20+
#include "phasar/Utils/Macros.h"
2021
#include "phasar/Utils/TypeTraits.h"
2122

2223
#include "llvm/ADT/ArrayRef.h"
@@ -131,7 +132,7 @@ Container makeContainer(Range &&Rng) {
131132
Container C;
132133
reserveIfPossible(C, Rng.size());
133134
for (auto &&Fact : Rng) {
134-
C.insert(std::forward<decltype(Fact)>(Fact));
135+
C.insert(PSR_FWD(Fact));
135136
}
136137
return C;
137138
}

include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h

+73-10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define PHASAR_DATAFLOW_IFDSIDE_SOLVER_IDESOLVER_H
1919

2020
#include "phasar/Config/Configuration.h"
21+
#include "phasar/ControlFlow/SparseCFGProvider.h"
2122
#include "phasar/DB/ProjectIRDBBase.h"
2223
#include "phasar/DataFlow/IfdsIde/EdgeFunction.h"
2324
#include "phasar/DataFlow/IfdsIde/EdgeFunctionStats.h"
@@ -35,15 +36,19 @@
3536
#include "phasar/DataFlow/IfdsIde/SolverResults.h"
3637
#include "phasar/Domain/AnalysisDomain.h"
3738
#include "phasar/Utils/Average.h"
39+
#include "phasar/Utils/ByRef.h"
3840
#include "phasar/Utils/DOTGraph.h"
3941
#include "phasar/Utils/JoinLattice.h"
4042
#include "phasar/Utils/Logger.h"
43+
#include "phasar/Utils/Macros.h"
44+
#include "phasar/Utils/Nullable.h"
4145
#include "phasar/Utils/PAMMMacros.h"
4246
#include "phasar/Utils/Table.h"
4347
#include "phasar/Utils/Utilities.h"
4448

4549
#include "llvm/ADT/DenseSet.h"
4650
#include "llvm/ADT/StringRef.h"
51+
#include "llvm/Support/TypeName.h"
4752
#include "llvm/Support/raw_ostream.h"
4853

4954
#include "nlohmann/json.hpp"
@@ -81,14 +86,24 @@ class IDESolver
8186
using t_t = typename AnalysisDomainTy::t_t;
8287
using v_t = typename AnalysisDomainTy::v_t;
8388

89+
template <typename I>
8490
IDESolver(IDETabulationProblem<AnalysisDomainTy, Container> &Problem,
85-
const i_t *ICF)
86-
: IDEProblem(Problem), ZeroValue(Problem.getZeroValue()), ICF(ICF),
91+
const I *ICF)
92+
: IDEProblem(Problem), ZeroValue(Problem.getZeroValue()),
93+
ICF(&static_cast<const i_t &>(*ICF)), SVFG(ICF),
8794
SolverConfig(Problem.getIFDSIDESolverConfig()),
8895
CachedFlowEdgeFunctions(Problem), AllTop(Problem.allTopFunction()),
8996
JumpFn(std::make_shared<JumpFunctions<AnalysisDomainTy, Container>>()),
9097
Seeds(Problem.initialSeeds()) {
9198
assert(ICF != nullptr);
99+
100+
if constexpr (has_getSparseCFG_v<I, d_t>) {
101+
NextUserOrNullCB = [](const void *SVFG, ByConstRef<f_t> Fun,
102+
ByConstRef<d_t> d3, ByConstRef<n_t> n) {
103+
auto &&SCFG = static_cast<const I *>(SVFG)->getSparseCFG(Fun, d3);
104+
return SCFG.nextUserOrNull(n);
105+
};
106+
}
92107
}
93108

94109
IDESolver(IDETabulationProblem<AnalysisDomainTy, Container> *Problem,
@@ -339,6 +354,15 @@ class IDESolver
339354
}
340355

341356
protected:
357+
Nullable<n_t> getNextUserOrNull(ByConstRef<f_t> Fun, ByConstRef<d_t> d3,
358+
ByConstRef<n_t> n) {
359+
if (!NextUserOrNullCB || IDEProblem.isZeroValue(d3)) {
360+
return {};
361+
}
362+
363+
return NextUserOrNullCB(SVFG, Fun, d3, n);
364+
}
365+
342366
/// Lines 13-20 of the algorithm; processing a call site in the caller's
343367
/// context.
344368
///
@@ -382,6 +406,15 @@ class IDESolver
382406

383407
bool HasNoCalleeInformation = true;
384408

409+
auto &&Fun = ICF->getFunctionOf(n);
410+
auto GetNextUse = [this, &Fun, &n](n_t nPrime, ByConstRef<d_t> d3) {
411+
if (auto &&NextUser = getNextUserOrNull(Fun, d3, n)) {
412+
return psr::unwrapNullable(PSR_FWD(NextUser));
413+
}
414+
415+
return nPrime;
416+
};
417+
385418
// for each possible callee
386419
for (f_t SCalledProcN : Callees) { // still line 14
387420
// check if a special summary for the called procedure exists
@@ -409,7 +442,9 @@ class IDESolver
409442
"Queried Summary Edge Function: " << SumEdgFnE);
410443
PHASAR_LOG_LEVEL(DEBUG,
411444
"Compose: " << SumEdgFnE << " * " << f << '\n');
412-
WorkList.emplace_back(PathEdge(d1, ReturnSiteN, std::move(d3)),
445+
446+
auto DestN = GetNextUse(ReturnSiteN, d3);
447+
WorkList.emplace_back(PathEdge(d1, DestN, std::move(d3)),
413448
IDEProblem.extend(f, SumEdgFnE));
414449
}
415450
}
@@ -508,8 +543,10 @@ class IDESolver
508543
d_t d5_restoredCtx = restoreContextOnReturnedFact(n, d2, d5);
509544
// propagte the effects of the entire call
510545
PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f);
546+
547+
auto DestN = GetNextUse(RetSiteN, d5_restoredCtx);
511548
WorkList.emplace_back(
512-
PathEdge(d1, RetSiteN, std::move(d5_restoredCtx)),
549+
PathEdge(d1, DestN, std::move(d5_restoredCtx)),
513550
IDEProblem.extend(f, fPrime));
514551
}
515552
}
@@ -545,7 +582,8 @@ class IDESolver
545582
auto fPrime = IDEProblem.extend(f, EdgeFnE);
546583
PHASAR_LOG_LEVEL(DEBUG, "Compose: " << EdgeFnE << " * " << f << " = "
547584
<< fPrime);
548-
WorkList.emplace_back(PathEdge(d1, ReturnSiteN, std::move(d3)),
585+
auto DestN = GetNextUse(ReturnSiteN, d3);
586+
WorkList.emplace_back(PathEdge(d1, DestN, std::move(d3)),
549587
std::move(fPrime));
550588
}
551589
}
@@ -563,6 +601,8 @@ class IDESolver
563601
EdgeFunction<l_t> f = jumpFunction(Edge);
564602
auto [d1, n, d2] = Edge.consume();
565603

604+
const auto &Fun = ICF->getFunctionOf(n);
605+
566606
for (const auto nPrime : ICF->getSuccsOf(n)) {
567607
FlowFunctionPtrType FlowFunc =
568608
CachedFlowEdgeFunctions.getNormalFlowFunction(n, nPrime);
@@ -575,14 +615,23 @@ class IDESolver
575615
CachedFlowEdgeFunctions.getNormalEdgeFunction(n, d2, nPrime, d3);
576616
PHASAR_LOG_LEVEL(DEBUG, "Queried Normal Edge Function: " << g);
577617
EdgeFunction<l_t> fPrime = IDEProblem.extend(f, g);
618+
619+
auto DestN = [&, &n = n] {
620+
if (auto &&NextUser = getNextUserOrNull(Fun, d3, n)) {
621+
return psr::unwrapNullable(PSR_FWD(NextUser));
622+
}
623+
624+
return nPrime;
625+
}();
626+
578627
if (SolverConfig.emitESG()) {
579-
IntermediateEdgeFunctions[std::make_tuple(n, d2, nPrime, d3)]
628+
IntermediateEdgeFunctions[std::make_tuple(n, d2, DestN, d3)]
580629
.push_back(g);
581630
}
582631
PHASAR_LOG_LEVEL(DEBUG,
583632
"Compose: " << g << " * " << f << " = " << fPrime);
584633
INC_COUNTER("EF Queries", 1, Full);
585-
WorkList.emplace_back(PathEdge(d1, nPrime, std::move(d3)),
634+
WorkList.emplace_back(PathEdge(d1, DestN, std::move(d3)),
586635
std::move(fPrime));
587636
}
588637
}
@@ -915,6 +964,7 @@ class IDESolver
915964
for (const auto &Entry : Inc) {
916965
// line 22
917966
n_t c = Entry.first;
967+
auto &&Fun = ICF->getFunctionOf(c);
918968
// for each return site
919969
for (n_t RetSiteC : ICF->getReturnSitesOfCallAt(c)) {
920970
// compute return-flow function
@@ -968,9 +1018,19 @@ class IDESolver
9681018
d_t d3 = ValAndFunc.first;
9691019
d_t d5_restoredCtx = restoreContextOnReturnedFact(c, d4, d5);
9701020
PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f3);
971-
WorkList.emplace_back(PathEdge(std::move(d3), RetSiteC,
972-
std::move(d5_restoredCtx)),
973-
IDEProblem.extend(f3, fPrime));
1021+
1022+
auto DestN = [&] {
1023+
if (auto &&NextUser =
1024+
getNextUserOrNull(Fun, d5_restoredCtx, c)) {
1025+
return psr::unwrapNullable(PSR_FWD(NextUser));
1026+
}
1027+
1028+
return RetSiteC;
1029+
}();
1030+
1031+
WorkList.emplace_back(
1032+
PathEdge(std::move(d3), DestN, std::move(d5_restoredCtx)),
1033+
IDEProblem.extend(f3, fPrime));
9741034
}
9751035
}
9761036
}
@@ -1809,7 +1869,10 @@ class IDESolver
18091869
IDETabulationProblem<AnalysisDomainTy, Container> &IDEProblem;
18101870
d_t ZeroValue;
18111871
const i_t *ICF;
1872+
const void *SVFG;
18121873
IFDSIDESolverConfig &SolverConfig;
1874+
Nullable<n_t> (*NextUserOrNullCB)(const void *, ByConstRef<f_t>,
1875+
ByConstRef<d_t>, ByConstRef<n_t>) = nullptr;
18131876

18141877
std::vector<std::pair<PathEdge<n_t, d_t>, EdgeFunction<l_t>>> WorkList;
18151878
std::vector<std::pair<n_t, d_t>> ValuePropWL;

include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,17 @@ class IFDSSolver
3737
using n_t = typename AnalysisDomainTy::n_t;
3838
using i_t = typename AnalysisDomainTy::i_t;
3939

40-
template <typename IfdsDomainTy,
40+
template <typename IfdsDomainTy, typename I,
4141
typename = std::enable_if_t<
4242
std::is_base_of_v<IfdsDomainTy, AnalysisDomainTy>>>
4343
IFDSSolver(IFDSTabulationProblem<IfdsDomainTy, Container> &IFDSProblem,
44-
const i_t *ICF)
45-
: IDESolver<WithBinaryValueDomain<AnalysisDomainTy>>(&IFDSProblem, ICF) {}
46-
template <typename IfdsDomainTy,
44+
const I *ICF)
45+
: IDESolver<WithBinaryValueDomain<AnalysisDomainTy>>(IFDSProblem, ICF) {}
46+
template <typename IfdsDomainTy, typename I,
4747
typename = std::enable_if_t<
4848
std::is_base_of_v<IfdsDomainTy, AnalysisDomainTy>>>
4949
IFDSSolver(IFDSTabulationProblem<IfdsDomainTy, Container> *IFDSProblem,
50-
const i_t *ICF)
50+
const I *ICF)
5151
: IDESolver<WithBinaryValueDomain<AnalysisDomainTy>>(IFDSProblem, ICF) {}
5252

5353
~IFDSSolver() override = default;

0 commit comments

Comments
 (0)