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>
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{
91 demandTopLevelPointer(copy->getSrcNode(), graph, demandedVars,
92 retained, nodeWorklist);
93 else if (const GepSVFGNode* gep = SVFUtil::dyn_cast<GepSVFGNode>(node))
94 demandTopLevelPointer(gep->getSrcNode(), graph, demandedVars,
95 retained, nodeWorklist);
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,
99 retained, nodeWorklist);
100 else if (const LoadSVFGNode* load = SVFUtil::dyn_cast<LoadSVFGNode>(node))
101 demandTopLevelPointer(load->getSrcNode(), graph, demandedVars,
102 retained, nodeWorklist);
103 else if (const StoreSVFGNode* store = SVFUtil::dyn_cast<StoreSVFGNode>(node))
104 {
105 demandTopLevelPointer(store->getDstNode(), graph, demandedVars,
106 retained, nodeWorklist);
107 demandTopLevelPointer(store->getSrcNode(), graph, demandedVars,
108 retained, nodeWorklist);
109 }
110 else if (const ActualParmSVFGNode* actual =
112 demandTopLevelPointer(actual->getParam(), graph, demandedVars,
113 retained, nodeWorklist);
114 else if (const FormalRetSVFGNode* formal =
116 demandTopLevelPointer(formal->getRet(), graph, demandedVars,
117 retained, nodeWorklist);
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
135 NodeBS demandedVars;
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,
144 dependencyNodes, nodeWorklist);
145 }
146
147 Set<const CallICFGNode*> indirectSites;
148 Set<const FunObjVar*> indirectTargets;
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 =
164 boundary = indirectSites.count(actual->getCallSite()) > 0;
165 else if (const ActualRetSVFGNode* actual =
167 boundary = indirectSites.count(actual->getCallSite()) > 0;
168 else if (const ActualINSVFGNode* actual =
170 boundary = indirectSites.count(actual->getCallSite()) > 0;
171 else if (const ActualOUTSVFGNode* actual =
173 boundary = indirectSites.count(actual->getCallSite()) > 0;
174 else if (const FormalParmSVFGNode* formal =
176 boundary = indirectTargets.count(formal->getFun()) > 0;
177 else if (const FormalRetSVFGNode* formal =
179 boundary = indirectTargets.count(formal->getFun()) > 0;
180 else if (const FormalINSVFGNode* formal =
182 boundary = indirectTargets.count(
183 formal->getFunEntryNode()->getFun()) > 0;
184 else if (const FormalOUTSVFGNode* formal =
186 boundary = indirectTargets.count(
187 formal->getFunExitNode()->getFun()) > 0;
188 else if (const InterMSSAPHISVFGNode* phi =
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())
218 edge->getSrcNode(), dependencyNodes, nodeWorklist);
219
221 node, graph, demandedVars, dependencyNodes, nodeWorklist);
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.
234
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.
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)
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 }
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.
bool empty() const
Definition WorkList.h:161
NodeStack solveNodeStack
Definition FSMPTA.h:97
void cacheRetainedEdge(SVFGEdge *edge)
Definition FSMPTA.cpp:263
static NodeBS buildExecutionDependencyClosure(SVFG *graph, AndersenBase *preAnalysis, NodeBS dependencyNodes)
Definition FSMPTA.cpp:121
SVFG * backingGraph
Definition FSMPTA.h:94
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
Map< NodeID, std::vector< SVFGEdge * > > retainedOutEdges
Definition FSMPTA.h:98
std::unique_ptr< SCCDetection< SVFGGraph > > solveSCC
Definition FSMPTA.h:96
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
SVFGGraph solveGraph
Definition FSMPTA.h:95
AndersenWaveDiff * preAnalysis
Definition FSMPTA.h:93
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
Set< const SVFGEdge * > retainedEdgeSet
Definition FSMPTA.h:99
virtual void updateConnectedNodes(const SVFGEdgeSetTy &edges)
Update nodes connected during updating call graph.
AndersenWaveDiff * ander
SVFG::SVFGEdgeSetTy SVFGEdgeSetTy
bool propFromSrcToDst(SVFGEdge *edge) override
Propagation.
friend class FlowSensitiveStat
void clearAllDFOutVarFlag(const SVFGNode *stmt)
bool processSVFGNode(SVFGNode *node)
FlowSensitive(SVFIR *_pag, PTATY type=PTATY::FSSPARSE_WPA)
Constructor.
double sccTime
time of SCC detection.
NodeID getDstID() const
NodeID getSrcID() const
get methods of the components
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:108
virtual void initialize()
Initialization of a pointer analysis, including building symbol table and SVFIR etc.
PTAStat * stat
Statistics.
SVFIR * getPAG() const
static SVFIR * pag
SVFIR.
void disablePrintStat()
Whether print statistics.
NodeID getId() const
Get ID.
Definition SVFValue.h:158
virtual bool isPointer() const
Check if this variable represents a pointer.
bool test(unsigned Idx) const
void set(unsigned Idx)
VFGNodeIDToNodeMapTy::const_iterator const_iterator
Definition VFG.h:81
VFGNodeIDToNodeMapTy::iterator iterator
Definition VFG.h:80
virtual void pushIntoWorklist(NodeID id)
Definition WPASolver.h:157
void setGraph(GraphType g)
Definition WPASolver.h:79
const GraphType graph()
Get/Set graph methods.
Definition WPASolver.h:75
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
Definition Casting.h:360
std::ostream & errs()
Overwrite llvm::errs().
Definition SVFUtil.h:64
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
Definition Casting.h:405
for isBitcode
Definition BasicTypes.h:70
ActualParmVFGNode ActualParmSVFGNode
Definition SVFG.h:44
std::stack< NodeID > NodeStack
Definition GeneralType.h:92
LoadVFGNode LoadSVFGNode
Definition SVFG.h:54
u32_t NodeID
Definition GeneralType.h:76
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition GeneralType.h:51
StoreVFGNode StoreSVFGNode
Definition SVFG.h:53
VFGNode SVFGNode
Definition SVFG.h:43
GepVFGNode GepSVFGNode
Definition SVFG.h:55
PHIVFGNode PHISVFGNode
Definition SVFG.h:56
ActualRetVFGNode ActualRetSVFGNode
Definition SVFG.h:45
VFGEdge SVFGEdge
Definition SVFG.h:42
SparseBitVector NodeBS
Definition GeneralType.h:82
CopyVFGNode CopySVFGNode
Definition SVFG.h:52
FormalParmVFGNode FormalParmSVFGNode
Definition SVFG.h:46
FormalRetVFGNode FormalRetSVFGNode
Definition SVFG.h:47