Static Value-Flow Analysis
Loading...
Searching...
No Matches
PointerAnalysisImpl.cpp
Go to the documentation of this file.
1//===- PointerAnalysisImpl.cpp -- Pointer analysis implementation--------------------//
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/*
25 * PointerAnalysisImpl.cpp
26 *
27 * Created on: 28Mar.,2020
28 * Author: yulei
29 */
30
31
33#include "Util/Options.h"
34#include <fstream>
35#include <sstream>
36
37#include "Graphs/CallGraph.h"
38
39using namespace SVF;
40using namespace SVFUtil;
41using namespace std;
42
47 PointerAnalysis(p, type, alias_check), ptCache()
48{
50 || type == TypeCPP_WPA || type == FlowS_DDA
52 {
53 // Only maintain reverse points-to when the analysis is field-sensitive, as objects turning
54 // field-insensitive is all it is used for.
56 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutDiffPTDataTy>(maintainRevPts);
57 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersDiffPTDataTy>(getPtCache(), maintainRevPts);
58 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
59 }
60 else if (type == Steensgaard_WPA)
61 {
62 // Steensgaard is only field-insensitive (for now?), so no reverse points-to.
63 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutDiffPTDataTy>(false);
64 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersDiffPTDataTy>(getPtCache(), false);
65 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
66 }
67 else if (type == FSSPARSE_WPA)
68 {
70 {
71 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutIncDFPTDataTy>(false);
72 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersIncDFPTDataTy>(getPtCache(), false);
73 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
74 }
75 else
76 {
77 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutDFPTDataTy>(false);
78 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersDFPTDataTy>(getPtCache(), false);
79 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
80 }
81 }
82 else if (type == VFS_WPA)
83 {
84 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutVersionedPTDataTy>(false);
85 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersVersionedPTDataTy>(getPtCache(), false);
86 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
87 }
88 else assert(false && "no points-to data available");
89
91}
92
94{
97
99 {
100 std::string moduleName(pag->getModule()->getModuleIdentifier());
101 std::vector<std::string> names = SVFUtil::split(moduleName,'/');
102 if (names.size() > 1)
103 moduleName = names[names.size() - 1];
104
105 std::string subtitle;
106
108 subtitle = "Andersen's analysis bitvector";
109 else if(ptaTy >=FSDATAFLOW_WPA && ptaTy <=FSCS_WPA)
110 subtitle = "flow-sensitive analysis bitvector";
111 else if(ptaTy >=CFLFICI_WPA && ptaTy <=CFLFSCS_WPA)
112 subtitle = "CFL analysis bitvector";
113 else if(ptaTy == TypeCPP_WPA)
114 subtitle = "Type analysis bitvector";
115 else if(ptaTy >=FieldS_DDA && ptaTy <=Cxt_DDA)
116 subtitle = "DDA bitvector";
117 else
118 subtitle = "bitvector";
119
120 SVFUtil::outs() << "\n****Persistent Points-To Cache Statistics: " << subtitle << "****\n";
121 SVFUtil::outs() << "################ (program : " << moduleName << ")###############\n";
122 SVFUtil::outs().flags(std::ios::left);
123 ptCache.printStats("bitvector");
124 SVFUtil::outs() << "#######################################################" << std::endl;
125 SVFUtil::outs().flush();
126 }
127
128}
129
134{
135 expandedPts = pts;;
136 for(PointsTo::iterator pit = pts.begin(), epit = pts.end(); pit!=epit; ++pit)
137 {
139 {
141 }
142 }
143}
144
146{
148 for (const NodeID o : pts)
149 {
151 {
153 }
154 }
155}
156
158{
159 getPTDataTy()->remapAllPts();
160}
161
163{
164 outs() << "Storing ObjVar to '" << filename << "'...";
166 std::fstream f(filename.c_str(), std::ios_base::out);
167 if (!f.good())
168 {
169 outs() << " error opening file for writing!\n";
170 return;
171 }
172
173 // Write BaseNodes insensitivity to file
175 for (auto it = pag->begin(), ie = pag->end(); it != ie; ++it)
176 {
177 PAGNode* pagNode = it->second;
178 if (!isa<ObjVar>(pagNode)) continue;
179 NodeID n = pag->getBaseObjVar(it->first);
180 if (NodeIDs.test(n)) continue;
181 f << n << " ";
182 f << isFieldInsensitive(n) << "\n";
183 NodeIDs.set(n);
184 }
185
186 f << "------\n";
187
188 f.close();
189 if (f.good())
190 {
191 outs() << "\n";
192 return;
193 }
194
195
196}
197
199{
200 // Write analysis results to file
201 for (auto it = pag->begin(), ie = pag->end(); it != ie; ++it)
202 {
203 NodeID var = it->first;
204 const PointsTo &pts = getPts(var);
205
207 f << var << " -> { ";
208 if (pts.empty())
209 {
210 f << " ";
211 }
212 else
213 {
214 for (NodeID n: pts)
215 {
216 f << n << " ";
217 }
218 }
219 f << "}\n";
220 }
221
222}
223
225{
226 //write gepObjVarMap to file(in form of: baseID offset gepObjNodeId)
228 for(SVFIR::NodeOffsetMap::const_iterator it = gepObjVarMap.begin(), eit = gepObjVarMap.end(); it != eit; it++)
229 {
231 //write the base id to file
232 f << offsetPair.first << " ";
233 //write the offset to file
234 f << offsetPair.second << " ";
235 //write the gepObjNodeId to file
236 f << it->second << "\n";
237 }
238
239}
240
247{
248
249 outs() << "Storing pointer analysis results to '" << filename << "'...";
250
252 std::fstream f(filename.c_str(), std::ios_base::app);
253 if (!f.good())
254 {
255 outs() << " error opening file for writing!\n";
256 return;
257 }
258
260
261 f << "------\n";
262
264
265 f << "------\n";
266
267 // Write BaseNodes insensitivity to file
269 for (auto it = pag->begin(), ie = pag->end(); it != ie; ++it)
270 {
271 PAGNode* pagNode = it->second;
272 if (!isa<ObjVar>(pagNode)) continue;
273 NodeID n = pag->getBaseObjVar(it->first);
274 if (NodeIDs.test(n)) continue;
275 f << n << " ";
276 f << isFieldInsensitive(n) << "\n";
277 NodeIDs.set(n);
278 }
279
280 // Job finish and close file
281 f.close();
282 if (f.good())
283 {
284 outs() << "\n";
285 return;
286 }
287}
288
290{
291 string line;
292 // Read analysis results from file
294
295 // Read points-to sets
296 string delimiter1 = " -> { ";
297 string delimiter2 = " }";
300
301 while (F.good())
302 {
303 // Parse a single line in the form of "var -> { obj1 obj2 obj3 }"
304 getline(F, line);
305 if (line.at(0) == '[' || line == "---VERSIONED---") continue;
306 if (line == "------") break;
307 size_t pos = line.find(delimiter1);
308 if (pos == string::npos) break;
309 if (line.back() != '}') break;
310
311 // var
312 NodeID var = atoi(line.substr(0, pos).c_str());
313
314 // objs
315 pos = pos + delimiter1.length();
316 size_t len = line.length() - pos - delimiter2.length();
317 string objs = line.substr(pos, len);
319
320 if (!objs.empty())
321 {
322 // map the variable ID to its unique string pointer set
324 if (strPtsMap.count(objs)) continue;
325
327 NodeID obj;
328 while (ss.good())
329 {
330 ss >> obj;
331 dstPts.set(obj);
332 }
333 // map the string pointer set to the parsed PointsTo set
335 }
336 }
337
338 // map the variable ID to its pointer set
339 for (auto t: nodePtsMap)
340 ptD->unionPts(t.first, strPtsMap[t.second]);
341}
342
344{
345 string line;
346 //read GepObjVarMap from file
348 while (F.good())
349 {
350 getline(F, line);
351 if (line == "------") break;
352 // Parse a single line in the form of "ID baseNodeID offset"
354 NodeID base;
355 size_t offset;
356 NodeID id;
357 ss >> base >> offset >>id;
358 SVFIR::NodeOffsetMap::const_iterator iter = gepObjVarMap.find(std::make_pair(base, offset));
359 if (iter == gepObjVarMap.end())
360 {
361 SVFVar* node = pag->getGNode(base);
362 const MemObj* obj = nullptr;
363 if (GepObjVar* gepObjVar = SVFUtil::dyn_cast<GepObjVar>(node))
364 obj = gepObjVar->getMemObj();
365 else if (BaseObjVar* baseNode = SVFUtil::dyn_cast<BaseObjVar>(node))
366 obj = baseNode->getMemObj();
367 else if (DummyObjVar* baseNode = SVFUtil::dyn_cast<DummyObjVar>(node))
368 obj = baseNode->getMemObj();
369 else
370 assert(false && "new gep obj node kind?");
373 }
374
375
376 }
377}
378
379void BVDataPTAImpl::readAndSetObjFieldSensitivity(std::ifstream& F, const std::string& delimiterStr)
380{
381 string line;
382 // //update ObjVar status
383 while (F.good())
384 {
385 getline(F, line);
386 if (line.empty() || line == delimiterStr)
387 break;
388 // Parse a single line in the form of "baseNodeID insensitive"
390 NodeID base;
391 bool insensitive;
392 ss >> base >> insensitive;
393
394 if (insensitive)
396 }
397
398}
399
406{
407
408 outs() << "Loading pointer analysis results from '" << filename << "'...";
409
410 ifstream F(filename.c_str());
411 if (!F.is_open())
412 {
413 outs() << " error opening file for reading!\n";
414 return false;
415 }
416
418
420
422
424
425 // Update callgraph
427
428 F.close();
429 outs() << "\n";
430
431 return true;
432}
433
434
439{
440 for (OrderedNodeSet::iterator nIter = this->getAllValidPtrs().begin();
441 nIter != this->getAllValidPtrs().end(); ++nIter)
442 {
443 const PAGNode* node = getPAG()->getGNode(*nIter);
444 if (getPAG()->isValidTopLevelPtr(node))
445 {
446 const PointsTo& pts = this->getPts(node->getId());
447 outs() << "\nNodeID " << node->getId() << " ";
448
449 if (pts.empty())
450 {
451 outs() << "\t\tPointsTo: {empty}\n\n";
452 }
453 else
454 {
455 outs() << "\t\tPointsTo: { ";
456 for (PointsTo::iterator it = pts.begin(), eit = pts.end();
457 it != eit; ++it)
458 outs() << *it << " ";
459 outs() << "}\n\n";
460 }
461 }
462 }
463
464 outs().flush();
465}
466
467
472{
474 for(SVFIR::iterator it = pag->begin(), eit = pag->end(); it!=eit; it++)
475 {
476 pagNodes.insert(it->first);
477 }
478
479 for (NodeID n : pagNodes)
480 {
481 outs() << "----------------------------------------------\n";
482 dumpPts(n, this->getPts(n));
483 }
484
485 outs() << "----------------------------------------------\n";
486}
487
488
495{
496 for(CallSiteToFunPtrMap::const_iterator iter = callsites.begin(), eiter = callsites.end(); iter!=eiter; ++iter)
497 {
498 const CallICFGNode* cs = iter->first;
499
500 if (cs->isVirtualCall())
501 {
502 const SVFVar* vtbl = cs->getVtablePtr();
503 assert(vtbl != nullptr);
504 NodeID vtblId = vtbl->getId();
506 }
507 else
508 resolveIndCalls(iter->first,getPts(iter->second),newEdges);
509 }
510}
511
519{
520 // add indirect fork edges
521 if(ThreadCallGraph *tdCallGraph = SVFUtil::dyn_cast<ThreadCallGraph>(callgraph))
522 {
523 for(CallSiteSet::const_iterator it = tdCallGraph->forksitesBegin(),
524 eit = tdCallGraph->forksitesEnd(); it != eit; ++it)
525 {
526 const ValVar* pVar = tdCallGraph->getThreadAPI()->getForkedFun(*it);
527 if(SVFUtil::dyn_cast<FunValVar>(pVar) == nullptr)
528 {
529 SVFIR *pag = this->getPAG();
530 const NodeBS targets = this->getPts(pVar->getId()).toNodeBS();
531 for(NodeBS::iterator ii = targets.begin(), ie = targets.end(); ii != ie; ++ii)
532 {
533 if(ObjVar *objPN = SVFUtil::dyn_cast<ObjVar>(pag->getGNode(*ii)))
534 {
535 const MemObj *obj = pag->getObject(objPN);
536 if(obj->isFunction())
537 {
538 const SVFFunction *svfForkedFun = SVFUtil::cast<CallGraphNode>(obj->getGNode())->getFunction();
539 if(tdCallGraph->addIndirectForkEdge(*it, svfForkedFun))
540 newForkEdges[*it].insert(svfForkedFun);
541 }
542 }
543 }
544 }
545 }
546 }
547}
548
553{
555 SVFIR::NodeOffsetMap &GepObjVarMap = pag->getGepObjNodeMap();
556
557 // collect each gep node whose base node has been set as field-insensitive
559 for (auto t: memToFieldsMap)
560 {
561 NodeID base = t.first;
562 const MemObj* memObj = pag->getObject(base);
563 assert(memObj && "Invalid memobj in memToFieldsMap");
564 if (memObj->isFieldInsensitive())
565 {
566 for (NodeID id : t.second)
567 {
568 if (SVFUtil::isa<GepObjVar>(pag->getGNode(id)))
569 {
570 dropNodes.set(id);
571 }
572 else
573 assert(id == base && "Not a GepObj Node or a baseObj Node?");
574 }
575 }
576 }
577
578 // remove the collected redundant gep nodes in each pointers's pts
579 for (SVFIR::iterator nIter = pag->begin(); nIter != pag->end(); ++nIter)
580 {
581 NodeID n = nIter->first;
582
583 const PointsTo &tmpPts = getPts(n);
584 for (NodeID obj : tmpPts)
585 {
586 if (!dropNodes.test(obj))
587 continue;
589 clearPts(n, obj);
590 addPts(n, baseObj);
591 }
592 }
593
594 // clear GepObjVarMap and memToFieldsMap for redundant gepnodes
595 // and remove those nodes from pag
596 for (NodeID n: dropNodes)
597 {
598 NodeID base = pag->getBaseObjVar(n);
599 GepObjVar *gepNode = SVFUtil::dyn_cast<GepObjVar>(pag->getGNode(n));
600 const APOffset apOffset = gepNode->getConstantFieldIdx();
601 GepObjVarMap.erase(std::make_pair(base, apOffset));
602 memToFieldsMap[base].reset(n);
603
605 }
606}
607
616
624
629{
630
635
638 else
640}
#define F(f)
cJSON * p
Definition cJSON.cpp:2559
newitem type
Definition cJSON.cpp:2739
buffer offset
Definition cJSON.cpp:1113
cJSON * n
Definition cJSON.cpp:2558
virtual void normalizePointsTo()
AliasResult alias(const SVFValue *V1, const SVFValue *V2) override
Interface expose to users of our pointer analysis, given Value infos.
virtual void writeToFile(const std::string &filename)
Interface for analysis result storage on filesystem.
virtual bool readFromFile(const std::string &filename)
virtual void writeObjVarToFile(const std::string &filename)
virtual void clearPts(NodeID id, NodeID element)
Remove element from the points-to set of id.
virtual void readAndSetObjFieldSensitivity(std::ifstream &f, const std::string &delimiterStr)
virtual void writeGepObjVarMapToFile(std::fstream &f)
void finalize() override
Finalization of pointer analysis, and normalize points-to information to Bit Vector representation.
virtual void writePtsResultToFile(std::fstream &f)
virtual void expandFIObjs(const PointsTo &pts, PointsTo &expandedPts)
Expand FI objects.
void remapPointsToSets(void)
Remap all points-to sets to use the current mapping.
virtual void onTheFlyThreadCallGraphSolve(const CallSiteToFunPtrMap &callsites, CallEdgeMap &newForkEdges)
On the fly thread call graph construction respecting forksite.
PersistentPointsToCache< PointsTo > ptCache
virtual void onTheFlyCallGraphSolve(const CallSiteToFunPtrMap &callsites, CallEdgeMap &newEdges)
On the fly call graph construction.
virtual bool updateCallGraph(const CallSiteToFunPtrMap &)
Update callgraph. This should be implemented by its subclass.
BVDataPTAImpl(SVFIR *pag, PointerAnalysis::PTATY type, bool alias_check=true)
Constructor.
std::unique_ptr< PTDataTy > ptD
Points-to data.
PersistentPointsToCache< PointsTo > & getPtCache()
PTData< NodeID, NodeSet, NodeID, PointsTo > PTDataTy
void dumpTopLevelPtsTo() override
const PointsTo & getPts(NodeID id) override
virtual void readPtsResultFromFile(std::ifstream &f)
PTDataTy * getPTDataTy() const
Get points-to data structure.
virtual bool addPts(NodeID id, NodeID ptd)
virtual void readGepObjVarMapFromFile(std::ifstream &f)
const SVFVar * getVtablePtr() const
Definition ICFGNode.h:537
bool isVirtualCall() const
Definition ICFGNode.h:527
iterator begin()
Iterators.
void removeGNode(NodeType *node)
Delete a node.
IDToNodeMapTy::iterator iterator
Node Iterators.
NodeType * getGNode(NodeID id) const
Get a node.
NodeID getValueNode(const SVFValue *V)
Definition IRGraph.h:137
static NodeIDAllocator * get(void)
Return (singleton) allocator.
static const Option< bool > INCDFPTData
Definition Options.h:136
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:38
static const OptionMap< BVDataPTAImpl::PTBackingType > ptDataBacking
PTData type.
Definition Options.h:69
PTATY
Pointer analysis type list.
@ Cxt_DDA
context sensitive DDA
@ CFLFICI_WPA
Flow-, context-, insensitive CFL-reachability-based analysis.
@ VFS_WPA
Versioned sparse flow-sensitive WPA.
@ FSCS_WPA
Flow-, context- sensitive WPA.
@ FSDATAFLOW_WPA
Traditional Dataflow-based flow sensitive WPA.
@ AndersenSCD_WPA
Selective cycle detection andersen-style WPA.
@ Andersen_BASE
Base Andersen PTA.
@ FlowS_DDA
Flow sensitive DDA.
@ Andersen_WPA
Andersen PTA.
@ CFLFSCS_WPA
Flow-, context-, CFL-reachability-based analysis.
@ FieldS_DDA
Field sensitive DDA.
@ AndersenWaveDiff_WPA
Diff wave propagation andersen-style WPA.
@ TypeCPP_WPA
Type-based analysis for C++.
@ AndersenSFR_WPA
Stride-based field representation.
@ Steensgaard_WPA
Steensgaard PTA.
@ FSSPARSE_WPA
Sparse flow sensitive WPA.
bool isFieldInsensitive(NodeID id) const
virtual void finalize()
Finalization of a pointer analysis, including checking alias correctness.
virtual void dumpPts(NodeID ptr, const PointsTo &pts)
bool print_stat
User input flags.
OrderedMap< const CallICFGNode *, FunctionSet > CallEdgeMap
bool containBlackHoleNode(const PointsTo &pts)
Determine whether a points-to contains a black hole or constant node.
PTAImplTy ptaImplTy
PTA implementation type.
SVFIR * getPAG() const
OrderedNodeSet & getAllValidPtrs()
Get all Valid Pointers for resolution.
virtual void resolveIndCalls(const CallICFGNode *cs, const PointsTo &target, CallEdgeMap &newEdges)
Resolve indirect call edges.
virtual void resolveCPPIndCalls(const CallICFGNode *cs, const PointsTo &target, CallEdgeMap &newEdges)
Resolve cpp indirect call edges.
@ BVDataImpl
Represents BVDataPTAImpl.
void setObjFieldInsensitive(NodeID id)
PTACallGraph * callgraph
Call graph used for pointer analysis.
SVFIR::CallSiteToFunPtrMap CallSiteToFunPtrMap
static SVFIR * pag
SVFIR.
PTATY ptaTy
Pointer analysis Type.
NodeBS toNodeBS() const
Returns this points-to set as a NodeBS.
Definition PointsTo.cpp:313
NodeID getId() const
Get ID.
std::pair< NodeID, APOffset > NodeOffset
Definition SVFIR.h:69
NodeID addGepObjNode(const MemObj *obj, const APOffset &apOffset, const NodeID gepId)
Add a field obj node, this method can only invoked by getGepObjVar.
Definition SVFIR.cpp:450
NodeBS & getAllFieldsObjVars(const MemObj *obj)
Get all fields of an object.
Definition SVFIR.cpp:489
NodeID getBaseObjVar(NodeID id) const
Base and Offset methods for Value and Object node.
Definition SVFIR.h:477
SVFModule * getModule()
Definition SVFIR.h:162
NodeOffsetMap & getGepObjNodeMap()
Return GepObjVarMap.
Definition SVFIR.h:135
const CallSiteToFunPtrMap & getIndirectCallsites() const
Add/get indirect callsites.
Definition SVFIR.h:351
Map< NodeID, NodeBS > MemObjToFieldsMap
Definition SVFIR.h:58
const MemObj * getObject(NodeID id) const
Definition SVFIR.h:396
Map< NodeOffset, NodeID > NodeOffsetMap
Definition SVFIR.h:71
MemObjToFieldsMap & getMemToFieldsMap()
Return memToFieldsMap.
Definition SVFIR.h:130
const std::string & getModuleIdentifier() const
Definition SVFModule.h:185
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:50
std::vector< std::string > split(const std::string &s, char separator)
Split into two substrings around the first occurrence of a separator string.
Definition SVFUtil.h:203
for isBitcode
Definition BasicTypes.h:68
OrderedSet< NodeID > OrderedNodeSet
u32_t NodeID
Definition GeneralType.h:55
s64_t APOffset
Definition GeneralType.h:60
AliasResult
Definition SVFType.h:527
@ MayAlias
Definition SVFType.h:529
@ NoAlias
Definition SVFType.h:528
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74