Static Value-Flow Analysis
Loading...
Searching...
No Matches
FSMPTA.cpp
Go to the documentation of this file.
1//===- FSMPTA.cpp -- Flow-sensitive multithreaded pointer analysis (FSAM) ===//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===----------------------------------------------------------------------===//
22
23/*
24 * FSMPTA.cpp
25 *
26 * Author: Jiawei Yang
27 *
28 * Implements the flow-sensitive multithreaded pointer analysis (FSAM): build
29 * the thread-aware SVFG, then run the sparse flow-sensitive solver over it.
30 */
31
32#include "MTA/FSMPTA.h"
33#include "WPA/Andersen.h"
34#include "WPA/WPAStat.h"
35#include "Util/Options.h"
36#include <cstdlib>
37#include <deque>
38
39using namespace SVF;
40
41template<class SVFGGraph>
43 SVFGGraph solveGraph)
44 : FlowSensitive(pre.getPAG()), preAnalysis(&pre), backingGraph(&graph),
45 solveGraph(solveGraph)
46{
47}
48
49template<class SVFGGraph>
55
56template<class SVFGGraph>
58 const SVFGNode* node, NodeBS& retained,
59 std::deque<NodeID>& nodeWorklist)
60{
61 if (node != nullptr && !retained.test(node->getId()))
62 {
63 retained.set(node->getId());
64 nodeWorklist.push_back(node->getId());
65 }
66}
67
68template<class SVFGGraph>
70 const SVFVar* var, SVFG* graph, NodeBS& demandedVars, NodeBS& retained,
71 std::deque<NodeID>& nodeWorklist)
72{
73 const ValVar* val = SVFUtil::dyn_cast<ValVar>(var);
74 if (val == nullptr || !val->isPointer() || demandedVars.test(val->getId()))
75 return;
76
77 demandedVars.set(val->getId());
78 if (graph->hasDefSVFGNode(val))
79 enqueueSVFGNode(graph->getDefSVFGNode(val), retained, nodeWorklist);
80}
81
85template<class SVFGGraph>
87 const SVFGNode* node, SVFG* graph, NodeBS& demandedVars,
88 NodeBS& retained, std::deque<NodeID>& nodeWorklist)
89{
90 if (const CopySVFGNode* copy = SVFUtil::dyn_cast<CopySVFGNode>(node))
91 demandTopLevelPointer(copy->getSrcNode(), graph, demandedVars,
93 else if (const GepSVFGNode* gep = SVFUtil::dyn_cast<GepSVFGNode>(node))
94 demandTopLevelPointer(gep->getSrcNode(), graph, demandedVars,
96 else if (const PHISVFGNode* phi = SVFUtil::dyn_cast<PHISVFGNode>(node))
97 for (auto it = phi->opVerBegin(), eit = phi->opVerEnd(); it != eit; ++it)
98 demandTopLevelPointer(it->second, graph, demandedVars,
100 else if (const LoadSVFGNode* load = SVFUtil::dyn_cast<LoadSVFGNode>(node))
101 demandTopLevelPointer(load->getSrcNode(), graph, demandedVars,
103 else if (const StoreSVFGNode* store = SVFUtil::dyn_cast<StoreSVFGNode>(node))
104 {
105 demandTopLevelPointer(store->getDstNode(), graph, demandedVars,
107 demandTopLevelPointer(store->getSrcNode(), graph, demandedVars,
109 }
110 else if (const ActualParmSVFGNode* actual =
111 SVFUtil::dyn_cast<ActualParmSVFGNode>(node))
112 demandTopLevelPointer(actual->getParam(), graph, demandedVars,
114 else if (const FormalRetSVFGNode* formal =
115 SVFUtil::dyn_cast<FormalRetSVFGNode>(node))
116 demandTopLevelPointer(formal->getRet(), graph, demandedVars,
118}
119
120template<class SVFGGraph>
122 SVFG* graph, AndersenBase* preAnalysis, NodeBS dependencyNodes)
123{
124 if (graph == nullptr || preAnalysis == nullptr)
125 {
126 SVFUtil::errs() << "[ERROR] FSMPTA execution closure requires a BaseSVFG "
127 << "and Andersen targets\n";
128 return NodeBS();
129 }
130
131 std::deque<NodeID> nodeWorklist;
132 for (NodeID id : dependencyNodes)
133 nodeWorklist.push_back(id);
134
136 // FlowSensitive::solveConstraints invokes updateCallGraph() for the whole
137 // program after every iteration. Its function-pointer reads are therefore
138 // execution roots even when the call site is not itself in the target slice.
139 SVFIR* pag = graph->getPAG();
140 for (const auto& callsiteAndPtr : pag->getIndirectCallsites())
141 {
142 const SVFVar* funPtr = pag->getGNode(callsiteAndPtr.second);
143 demandTopLevelPointer(funPtr, graph, demandedVars,
145 }
146
149 for (const auto& callsiteAndPtr : pag->getIndirectCallsites())
150 indirectSites.insert(callsiteAndPtr.first);
151 for (const auto& callsiteAndTargets : preAnalysis->getIndCallMap())
152 for (const FunObjVar* target : callsiteAndTargets.second)
153 indirectTargets.insert(target);
154
155 // One backing-SVFG pass collects both kinds of solver-global roots:
156 // updateCallGraph boundary nodes and variant-GEP side effects.
157 for (SVFG::const_iterator it = graph->begin(), eit = graph->end();
158 it != eit; ++it)
159 {
160 const SVFGNode* node = it->second;
161 bool boundary = false;
162 if (const ActualParmSVFGNode* actual =
163 SVFUtil::dyn_cast<ActualParmSVFGNode>(node))
164 boundary = indirectSites.count(actual->getCallSite()) > 0;
165 else if (const ActualRetSVFGNode* actual =
166 SVFUtil::dyn_cast<ActualRetSVFGNode>(node))
167 boundary = indirectSites.count(actual->getCallSite()) > 0;
168 else if (const ActualINSVFGNode* actual =
169 SVFUtil::dyn_cast<ActualINSVFGNode>(node))
170 boundary = indirectSites.count(actual->getCallSite()) > 0;
171 else if (const ActualOUTSVFGNode* actual =
172 SVFUtil::dyn_cast<ActualOUTSVFGNode>(node))
173 boundary = indirectSites.count(actual->getCallSite()) > 0;
174 else if (const FormalParmSVFGNode* formal =
175 SVFUtil::dyn_cast<FormalParmSVFGNode>(node))
176 boundary = indirectTargets.count(formal->getFun()) > 0;
177 else if (const FormalRetSVFGNode* formal =
178 SVFUtil::dyn_cast<FormalRetSVFGNode>(node))
179 boundary = indirectTargets.count(formal->getFun()) > 0;
180 else if (const FormalINSVFGNode* formal =
181 SVFUtil::dyn_cast<FormalINSVFGNode>(node))
183 formal->getFunEntryNode()->getFun()) > 0;
184 else if (const FormalOUTSVFGNode* formal =
185 SVFUtil::dyn_cast<FormalOUTSVFGNode>(node))
187 formal->getFunExitNode()->getFun()) > 0;
188 else if (const InterMSSAPHISVFGNode* phi =
189 SVFUtil::dyn_cast<InterMSSAPHISVFGNode>(node))
190 boundary = phi->isFormalINPHI()
191 ? indirectTargets.count(phi->getFun()) > 0
192 : indirectSites.count(phi->getCallSite()) > 0;
193
194 if (boundary)
195 enqueueSVFGNode(node, dependencyNodes, nodeWorklist);
196
197 // A variant GEP changes field-sensitivity globally. Later transfers
198 // read that state without an explicit SVFG edge.
199 if (const GepSVFGNode* gep = SVFUtil::dyn_cast<GepSVFGNode>(node))
200 {
201 const GepStmt* stmt = SVFUtil::cast<GepStmt>(gep->getSVFStmt());
202 if (stmt->isVariantFieldGep())
203 enqueueSVFGNode(gep, dependencyNodes, nodeWorklist);
204 }
205 }
206
207 // Joint fixed point: explicit SVFG predecessors carry direct/MemorySSA
208 // dependencies; definition roots cover FlowSensitive's implicit reads from
209 // the solver-global top-level points-to relation.
210 while (!nodeWorklist.empty())
211 {
212 const NodeID id = nodeWorklist.front();
213 nodeWorklist.pop_front();
214 const SVFGNode* node = graph->getSVFGNode(id);
215
216 for (const SVFGEdge* edge : node->getInEdges())
217 enqueueSVFGNode(
218 edge->getSrcNode(), dependencyNodes, nodeWorklist);
219
220 collectNodeInputDependencies(
222 }
223 return dependencyNodes;
224}
225
226template<class SVFGGraph>
228{
230 stat = new FlowSensitiveStat(this);
231 // SlicedMTA reports the deployment-facing result summary. Avoid the generic
232 // FlowSensitive statistics pass because it recomputes SCCs on the full SVFG.
233 disablePrintStat();
234
235 if (!supportsCurrentConfiguration())
236 {
237 SVFUtil::errs() << "[ERROR] FSMPTA does not support clustered Andersen, "
238 << "clustered FS, or plain FS mappings\n";
239 std::abort();
240 }
241
242 // Reuse both the Andersen result and the already-built base SVFG. The main
243 // ILA overlay has been attached by SlicedMTA before analysis starts.
244 ander = preAnalysis;
245 svfg = backingGraph;
246 // Retain the stock graph handle for FlowSensitive's dynamic-call support;
247 // SCC/worklist topology is supplied exclusively by solveSCC below.
248 setGraph(svfg);
249 solveSCC = std::make_unique<SCCDetection<SVFGGraph>>(solveGraph);
250 if constexpr (SolveGraphTraits::isFilteredGraph)
251 buildRetainedAdjacency();
252}
253
254template<class SVFGGraph>
256{
257 if (Options::DumpVFG())
258 svfg->dump("fs_solved", true);
260}
261
262template<class SVFGGraph>
264{
265 if (SolveGraphTraits::containsEdge(solveGraph, edge) &&
266 retainedEdgeSet.insert(edge).second)
267 retainedOutEdges[edge->getSrcID()].push_back(edge);
268}
269
270template<class SVFGGraph>
272{
273 for (SVFG::iterator it = svfg->begin(), eit = svfg->end(); it != eit; ++it)
274 {
275 SVFGNode* node = it->second;
276 if (!SolveGraphTraits::containsNode(solveGraph, node))
277 continue;
278 for (SVFGEdge* edge : node->getOutEdges())
279 cacheRetainedEdge(edge);
280 }
281}
282
283template<class SVFGGraph>
285{
286 const double start = stat->getClk();
287 solveSCC->find();
288 assert(solveNodeStack.empty() && "FSMPTA SCC stack was not fully consumed");
289
290 FIFOWorkList<NodeID> revTopo = solveSCC->revTopoNodeStack();
291 while (!revTopo.empty())
292 {
293 const NodeID rep = revTopo.front();
294 revTopo.pop();
295 const NodeBS& subNodes = solveSCC->subNodes(rep);
296 for (NodeID id : subNodes)
297 solveNodeStack.push(id);
298 }
299
300 assert(solveNodeStack.size() == SolveGraphTraits::graphSize(solveGraph) &&
301 "FSMPTA SCC topology must contain exactly the solve graph");
302
303 const double end = stat->getClk();
304 sccTime += (end - start) / TIMEINTERVAL;
305 return solveNodeStack;
306}
307
308template<class SVFGGraph>
310{
311 SVFGNode* node = svfg->getSVFGNode(nodeId);
312 assert(SolveGraphTraits::containsNode(solveGraph, node) &&
313 "FSMPTA worklist must never contain a node outside the solve graph");
314
315 if (processSVFGNode(node))
316 {
317 if constexpr (SolveGraphTraits::isFilteredGraph)
318 {
319 const auto found = retainedOutEdges.find(nodeId);
320 if (found != retainedOutEdges.end())
321 {
322 for (SVFGEdge* edge : found->second)
323 {
324 if (propFromSrcToDst(edge))
325 {
326 pushIntoWorklist(edge->getDstID());
327 }
328 }
329 }
330 }
331 else
332 {
333 for (SVFGEdge* edge : node->getOutEdges())
334 {
335 if (propFromSrcToDst(edge))
336 {
337 pushIntoWorklist(edge->getDstID());
338 }
339 }
340 }
341 }
342 clearAllDFOutVarFlag(node);
343}
344
345template<class SVFGGraph>
347{
348 if constexpr (SolveGraphTraits::isFilteredGraph)
349 {
350 SVFGEdgeSetTy keptEdges;
351 for (SVFGEdge* edge : edges)
352 if (SolveGraphTraits::containsEdge(solveGraph, edge))
353 {
354 keptEdges.insert(edge);
355 cacheRetainedEdge(edge);
356 }
358 }
359 else
360 {
362 }
363}
364
365template class SVF::FSMPTA<SVF::SVFG*>;
#define TIMEINTERVAL
Definition SVFType.h:604
copy
Definition cJSON.cpp:414
void finalize() override
Finalization of pointer analysis, and normalize points-to information to Bit Vector representation.
void cacheRetainedEdge(SVFGEdge *edge)
Definition FSMPTA.cpp:263
static NodeBS buildExecutionDependencyClosure(SVFG *graph, AndersenBase *preAnalysis, NodeBS dependencyNodes)
Definition FSMPTA.cpp:121
static void enqueueSVFGNode(const SVFGNode *node, NodeBS &retained, std::deque< NodeID > &worklist)
Definition FSMPTA.cpp:57
void processNode(NodeID nodeId) override
Handle various constraints.
Definition FSMPTA.cpp:309
FSMPTA(AndersenWaveDiff &preAnalysis, SVFG &backingGraph, SVFGGraph solveGraph)
Definition FSMPTA.cpp:42
void finalize() override
Finalize analysis.
Definition FSMPTA.cpp:255
void buildRetainedAdjacency()
Definition FSMPTA.cpp:271
void updateConnectedNodes(const SVFGEdgeSetTy &edges) override
Update nodes connected during updating call graph.
Definition FSMPTA.cpp:346
NodeStack & SCCDetect() override
SCC detection.
Definition FSMPTA.cpp:284
static void demandTopLevelPointer(const SVFVar *var, SVFG *graph, NodeBS &demandedVars, NodeBS &retained, std::deque< NodeID > &worklist)
Definition FSMPTA.cpp:69
static bool supportsCurrentConfiguration()
Definition FSMPTA.cpp:50
void initialize() override
Initialize analysis.
Definition FSMPTA.cpp:227
static void collectNodeInputDependencies(const SVFGNode *node, SVFG *graph, NodeBS &demandedVars, NodeBS &retained, std::deque< NodeID > &worklist)
Definition FSMPTA.cpp:86
virtual void updateConnectedNodes(const SVFGEdgeSetTy &edges)
Update nodes connected during updating call graph.
SVFG::SVFGEdgeSetTy SVFGEdgeSetTy
iterator begin()
Iterators.
IDToNodeMapTy::const_iterator const_iterator
IDToNodeMapTy::iterator iterator
Node Iterators.
NodeType * getGNode(NodeID id) const
Get a node.
const GEdgeSetTy & getOutEdges() const
const GEdgeSetTy & getInEdges() const
bool isVariantFieldGep() const
Gep statement with a variant field index (pointer arithmetic) for struct field access.
static const Option< bool > PlainMappingFs
Use an explicitly plain mapping with flow-sensitive (not null).
Definition Options.h:43
static const Option< bool > ClusterAnder
Whether to stage Andersen's with Steensgaard and cluster based on that data.
Definition Options.h:37
static const Option< bool > ClusterFs
Whether to cluster FS or VFS with the auxiliary Andersen's.
Definition Options.h:40
static const Option< bool > DumpVFG
Definition Options.h:107
virtual void initialize()
Initialization of a pointer analysis, including building symbol table and SVFIR etc.
CallEdgeMap & getIndCallMap()
Get callees from an indirect callsite.
SVFGNode * getSVFGNode(NodeID id) const
Get a SVFG node.
Definition SVFG.h:150
bool hasDefSVFGNode(const ValVar *valVar) const
Given a valVar, return whether it has definition site.
Definition SVFG.h:177
const SVFGNode * getDefSVFGNode(const ValVar *valVar) const
Given a valVar, return its definition site.
Definition SVFG.h:171
const CallSiteToFunPtrMap & getIndirectCallsites() const
Add/get indirect callsites.
Definition SVFIR.h:453
NodeID getId() const
Get ID.
Definition SVFValue.h:158
SVFIR * getPAG() const
Return SVFIR.
Definition VFG.h:133
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
for isBitcode
Definition BasicTypes.h:70
std::stack< NodeID > NodeStack
Definition GeneralType.h:92
u32_t NodeID
Definition GeneralType.h:76
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
SparseBitVector NodeBS
Definition GeneralType.h:82