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
32#include "MemoryModel/PTATY.h"
34#include "Util/Options.h"
35#include <fstream>
36#include <sstream>
37
38#include "Graphs/CallGraph.h"
39
40using namespace SVF;
41using namespace SVFUtil;
42using namespace std;
43
48 PointerAnalysis(p, type, alias_check), ptCache()
49{
53 {
54 // Only maintain reverse points-to when the analysis is field-sensitive, as objects turning
55 // field-insensitive is all it is used for.
57 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutDiffPTDataTy>(maintainRevPts);
58 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersDiffPTDataTy>(getPtCache(), maintainRevPts);
59 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
60 }
61 else if (type == PTATY::Steensgaard_WPA)
62 {
63 // Steensgaard is only field-insensitive (for now?), so no reverse points-to.
64 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutDiffPTDataTy>(false);
65 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersDiffPTDataTy>(getPtCache(), false);
66 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
67 }
68 else if (type == PTATY::FSSPARSE_WPA)
69 {
71 {
72 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutIncDFPTDataTy>(false);
73 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersIncDFPTDataTy>(getPtCache(), false);
74 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
75 }
76 else
77 {
78 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutDFPTDataTy>(false);
79 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersDFPTDataTy>(getPtCache(), false);
80 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
81 }
82 }
83 else if (type == PTATY::VFS_WPA)
84 {
85 if (Options::ptDataBacking() == PTBackingType::Mutable) ptD = std::make_unique<MutVersionedPTDataTy>(false);
86 else if (Options::ptDataBacking() == PTBackingType::Persistent) ptD = std::make_unique<PersVersionedPTDataTy>(getPtCache(), false);
87 else assert(false && "BVDataPTAImpl::BVDataPTAImpl: unexpected points-to backing type!");
88 }
89 else assert(false && "no points-to data available");
90
92}
93
95{
98
100 {
101 std::string moduleName(pag->getModuleIdentifier());
102 std::vector<std::string> names = SVFUtil::split(moduleName,'/');
103 if (names.size() > 1)
104 moduleName = names[names.size() - 1];
105
106 std::string subtitle;
107
109 subtitle = "Andersen's analysis bitvector";
111 subtitle = "flow-sensitive analysis bitvector";
113 subtitle = "CFL analysis bitvector";
114 else if(ptaTy == PTATY::TypeCPP_WPA)
115 subtitle = "Type analysis bitvector";
117 subtitle = "DDA bitvector";
118 else
119 subtitle = "bitvector";
120
121 SVFUtil::outs() << "\n****Persistent Points-To Cache Statistics: " << subtitle << "****\n";
122 SVFUtil::outs() << "################ (program : " << moduleName << ")###############\n";
123 SVFUtil::outs().flags(std::ios::left);
124 ptCache.printStats("bitvector");
125 SVFUtil::outs() << "#######################################################" << std::endl;
126 SVFUtil::outs().flush();
127 }
128
129}
130
135{
136 expandedPts = pts;;
137 for(PointsTo::iterator pit = pts.begin(), epit = pts.end(); pit!=epit; ++pit)
138 {
140 {
142 }
143 }
144}
145
147{
149 for (const NodeID o : pts)
150 {
152 {
154 }
155 }
156}
157
159{
160 getPTDataTy()->remapAllPts();
161}
162
164{
165 outs() << "Storing ObjVar to '" << filename << "'...";
167 std::fstream f(filename.c_str(), std::ios_base::out);
168 if (!f.good())
169 {
170 outs() << " error opening file for writing!\n";
171 return;
172 }
173
174 // Write BaseNodes insensitivity to file
176 for (auto it = pag->begin(), ie = pag->end(); it != ie; ++it)
177 {
178 PAGNode* pagNode = it->second;
179 if (!isa<ObjVar>(pagNode)) continue;
180 NodeID n = pag->getBaseObjVarID(it->first);
181 if (NodeIDs.test(n)) continue;
182 f << n << " ";
183 f << isFieldInsensitive(n) << "\n";
184 NodeIDs.set(n);
185 }
186
187 f << "------\n";
188
189 f.close();
190 if (f.good())
191 {
192 outs() << "\n";
193 return;
194 }
195
196
197}
198
200{
201 // Write analysis results to file
202 for (auto it = pag->begin(), ie = pag->end(); it != ie; ++it)
203 {
204 NodeID var = it->first;
205 const PointsTo &pts = getPts(var);
206
208 f << var << " -> { ";
209 if (pts.empty())
210 {
211 f << " ";
212 }
213 else
214 {
215 for (NodeID n: pts)
216 {
217 f << n << " ";
218 }
219 }
220 f << "}\n";
221 }
222
223}
224
226{
227 //write gepObjVarMap to file(in form of: baseID offset gepObjNodeId)
229 for(SVFIR::OffsetToGepVarMap::const_iterator it = gepObjVarMap.begin(), eit = gepObjVarMap.end(); it != eit; it++)
230 {
232 //write the base id to file
233 f << offsetPair.first << " ";
234 //write the offset to file
235 f << offsetPair.second << " ";
236 //write the gepObjNodeId to file
237 f << it->second << "\n";
238 }
239
240}
241
248{
249
250 outs() << "Storing pointer analysis results to '" << filename << "'...";
251
253 std::fstream f(filename.c_str(), std::ios_base::app);
254 if (!f.good())
255 {
256 outs() << " error opening file for writing!\n";
257 return;
258 }
259
261
262 f << "------\n";
263
265
266 f << "------\n";
267
268 // Write BaseNodes insensitivity to file
270 for (auto it = pag->begin(), ie = pag->end(); it != ie; ++it)
271 {
272 PAGNode* pagNode = it->second;
273 if (!isa<ObjVar>(pagNode)) continue;
274 NodeID n = pag->getBaseObjVarID(it->first);
275 if (NodeIDs.test(n)) continue;
276 f << n << " ";
277 f << isFieldInsensitive(n) << "\n";
278 NodeIDs.set(n);
279 }
280
281 // Job finish and close file
282 f.close();
283 if (f.good())
284 {
285 outs() << "\n";
286 return;
287 }
288}
289
291{
292 string line;
293 // Read analysis results from file
295
296 // Read points-to sets
297 string delimiter1 = " -> { ";
298 string delimiter2 = " }";
301
302 while (F.good())
303 {
304 // Parse a single line in the form of "var -> { obj1 obj2 obj3 }"
305 getline(F, line);
306 if (line.at(0) == '[' || line == "---VERSIONED---") continue;
307 if (line == "------") break;
308 size_t pos = line.find(delimiter1);
309 if (pos == string::npos) break;
310 if (line.back() != '}') break;
311
312 // var
313 NodeID var = atoi(line.substr(0, pos).c_str());
314
315 // objs
316 pos = pos + delimiter1.length();
317 size_t len = line.length() - pos - delimiter2.length();
318 string objs = line.substr(pos, len);
320
321 if (!objs.empty())
322 {
323 // map the variable ID to its unique string pointer set
325 if (strPtsMap.count(objs)) continue;
326
328 NodeID obj;
329 while (ss.good())
330 {
331 ss >> obj;
332 dstPts.set(obj);
333 }
334 // map the string pointer set to the parsed PointsTo set
336 }
337 }
338
339 // map the variable ID to its pointer set
340 for (auto t: nodePtsMap)
341 ptD->unionPts(t.first, strPtsMap[t.second]);
342}
343
345{
346 string line;
347 //read GepObjVarMap from file
349 while (F.good())
350 {
351 getline(F, line);
352 if (line == "------") break;
353 // Parse a single line in the form of "ID baseNodeID offset"
355 NodeID base;
356 size_t offset;
357 NodeID id;
358 ss >> base >> offset >>id;
359 SVFIR::OffsetToGepVarMap::const_iterator iter = gepObjVarMap.find(std::make_pair(base, offset));
360 if (iter == gepObjVarMap.end())
361 {
362 const SVFVar* node = pag->getSVFVar(base);
363 const BaseObjVar* obj = nullptr;
364 if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast<GepObjVar>(node))
365 {
366 obj = gepObjVar->getBaseObj();
367 }
368 else if (const BaseObjVar* baseNode = SVFUtil::dyn_cast<BaseObjVar>(node))
369 {
370 obj = baseNode;
371 }
372 else if (const DummyObjVar* baseNode = SVFUtil::dyn_cast<DummyObjVar>(node))
373 {
374 obj = baseNode;
375 }
376 else
377 assert(false && "new gep obj node kind?");
378 pag->addGepObjNode( obj, offset, id);
380 }
381
382
383 }
384}
385
386void BVDataPTAImpl::readAndSetObjFieldSensitivity(std::ifstream& F, const std::string& delimiterStr)
387{
388 string line;
389 // //update ObjVar status
390 while (F.good())
391 {
392 getline(F, line);
393 if (line.empty() || line == delimiterStr)
394 break;
395 // Parse a single line in the form of "baseNodeID insensitive"
397 NodeID base;
398 bool insensitive;
399 ss >> base >> insensitive;
400
401 if (insensitive)
403 }
404
405}
406
413{
414
415 outs() << "Loading pointer analysis results from '" << filename << "'...";
416
417 ifstream F(filename.c_str());
418 if (!F.is_open())
419 {
420 outs() << " error opening file for reading!\n";
421 return false;
422 }
423
425
427
429
431
432 // Update callgraph
434
435 F.close();
436 outs() << "\n";
437
438 return true;
439}
440
441
446{
447 for (OrderedNodeSet::iterator nIter = this->getAllValidPtrs().begin();
448 nIter != this->getAllValidPtrs().end(); ++nIter)
449 {
450 const SVFVar* node = getPAG()->getSVFVar(*nIter);
451 if (getPAG()->isValidTopLevelPtr(node))
452 {
453 const PointsTo& pts = this->getPts(node->getId());
454 outs() << "\nNodeID " << node->getId() << " ";
455
456 if (pts.empty())
457 {
458 outs() << "\t\tPointsTo: {empty}\n\n";
459 }
460 else
461 {
462 outs() << "\t\tPointsTo: { ";
463 for (PointsTo::iterator it = pts.begin(), eit = pts.end();
464 it != eit; ++it)
465 outs() << *it << " ";
466 outs() << "}\n\n";
467 }
468 }
469 }
470
471 outs().flush();
472}
473
474
479{
481 for(SVFIR::iterator it = pag->begin(), eit = pag->end(); it!=eit; it++)
482 {
483 pagNodes.insert(it->first);
484 }
485
486 for (NodeID n : pagNodes)
487 {
488 outs() << "----------------------------------------------\n";
489 dumpPts(n, this->getPts(n));
490 }
491
492 outs() << "----------------------------------------------\n";
493}
494
495
502{
503 for(CallSiteToFunPtrMap::const_iterator iter = callsites.begin(), eiter = callsites.end(); iter!=eiter; ++iter)
504 {
505 const CallICFGNode* cs = iter->first;
506
507 if (cs->isVirtualCall())
508 {
509 const SVFVar* vtbl = cs->getVtablePtr();
510 assert(vtbl != nullptr);
511 NodeID vtblId = vtbl->getId();
513 }
514 else
515 resolveIndCalls(iter->first,getPts(iter->second),newEdges);
516 }
517}
518
526{
527 // add indirect fork edges
528 if(ThreadCallGraph *tdCallGraph = SVFUtil::dyn_cast<ThreadCallGraph>(callgraph))
529 {
530 for(CallSiteSet::const_iterator it = tdCallGraph->forksitesBegin(),
531 eit = tdCallGraph->forksitesEnd(); it != eit; ++it)
532 {
533 const ValVar* pVar = tdCallGraph->getThreadAPI()->getForkedFun(*it);
534 if(SVFUtil::dyn_cast<FunValVar>(pVar) == nullptr)
535 {
536 SVFIR *pag = this->getPAG();
537 const NodeBS targets = this->getPts(pVar->getId()).toNodeBS();
538 for(NodeBS::iterator ii = targets.begin(), ie = targets.end(); ii != ie; ++ii)
539 {
540 if(const ObjVar *objPN = pag->getObjVar(*ii))
541 {
542 const BaseObjVar* obj = pag->getBaseObject(objPN->getId());
543 if(obj->isFunction())
544 {
545 const FunObjVar *svfForkedFun = SVFUtil::cast<FunObjVar>(obj)->getFunction();
546 if(tdCallGraph->addIndirectForkEdge(*it, svfForkedFun))
547 newForkEdges[*it].insert(svfForkedFun);
548 }
549 }
550 }
551 }
552 }
553 }
554}
555
560{
563
564 // collect each gep node whose base node has been set as field-insensitive
566 for (auto t: memToFieldsMap)
567 {
568 NodeID base = t.first;
569 const BaseObjVar* obj = pag->getBaseObject(base);
570 assert(obj && "Invalid baseObj in memToFieldsMap");
571 assert(obj->isFieldInsensitive() == obj->isFieldInsensitive());
572 if (obj->isFieldInsensitive())
573 {
574 for (NodeID id : t.second)
575 {
576 if (SVFUtil::isa<GepObjVar>(pag->getSVFVar(id)))
577 {
578 dropNodes.set(id);
579 }
580 else
581 assert(id == base && "Not a GepObj Node or a baseObj Node?");
582 }
583 }
584 }
585
586 // remove the collected redundant gep nodes in each pointers's pts
587 for (SVFIR::iterator nIter = pag->begin(); nIter != pag->end(); ++nIter)
588 {
589 NodeID n = nIter->first;
590
591 const PointsTo &tmpPts = getPts(n);
592 for (NodeID obj : tmpPts)
593 {
594 if (!dropNodes.test(obj))
595 continue;
597 clearPts(n, obj);
598 addPts(n, baseObj);
599 }
600 }
601
602 // clear GepObjVarMap and memToFieldsMap for redundant gepnodes
603 // and remove those nodes from pag
604 for (NodeID n: dropNodes)
605 {
606 NodeID base = pag->getBaseObjVarID(n);
607 GepObjVar *gepNode = SVFUtil::dyn_cast<GepObjVar>(pag->getGNode(n));
608 const APOffset apOffset = gepNode->getConstantFieldIdx();
609 GepObjVarMap.erase(std::make_pair(base, apOffset));
610 memToFieldsMap[base].reset(n);
611
613 }
614}
615
616
624
629{
630
635
638 else
640}
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()
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)
AliasResult alias(const SVFVar *V1, const SVFVar *V2) override
Interface expose to users of our pointer analysis, given Value infos.
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.
BVDataPTAImpl(SVFIR *pag, PTATY type, bool alias_check=true)
Constructor.
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.
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:519
bool isVirtualCall() const
Definition ICFGNode.h:509
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
iterator begin()
Iterators.
void removeGNode(NodeType *node)
Delete a node.
IDToNodeMapTy::iterator iterator
Node Iterators.
NodeType * getGNode(NodeID id) const
Get a node.
static NodeIDAllocator * get(void)
Return (singleton) allocator.
static const Option< bool > INCDFPTData
Definition Options.h:133
static const OptionMap< PTBackingType > ptDataBacking
PTData type.
Definition Options.h:66
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:35
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.
CallGraph * callgraph
Call graph used for pointer analysis.
virtual void resolveCPPIndCalls(const CallICFGNode *cs, const PointsTo &target, CallEdgeMap &newEdges)
Resolve cpp indirect call edges.
void setObjFieldInsensitive(NodeID id)
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
std::pair< NodeID, APOffset > GepOffset
Definition SVFIR.h:68
NodeID getBaseObjVarID(NodeID id) const
Base and Offset methods for Value and Object node.
Definition SVFIR.h:552
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:496
const ObjVar * getObjVar(NodeID id) const
Definition SVFIR.h:147
NodeBS & getAllFieldsObjVars(const BaseObjVar *obj)
Get all fields of an object.
Definition SVFIR.cpp:573
NodeID addGepObjNode(GepObjVar *gepObj, NodeID base, const APOffset &apOffset)
Definition SVFIR.cpp:547
const CallSiteToFunPtrMap & getIndirectCallsites() const
Add/get indirect callsites.
Definition SVFIR.h:451
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:133
OffsetToGepVarMap & getGepObjNodeMap()
Return GepObjVarMap.
Definition SVFIR.h:201
Map< NodeID, NodeBS > MemObjToFieldsMap
Definition SVFIR.h:56
Map< GepOffset, NodeID > OffsetToGepVarMap
Definition SVFIR.h:70
const std::string & getModuleIdentifier() const
Definition SVFIR.h:259
MemObjToFieldsMap & getMemToFieldsMap()
Return memToFieldsMap.
Definition SVFIR.h:196
NodeID getId() const
Get ID.
Definition SVFValue.h:161
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
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:196
for isBitcode
Definition BasicTypes.h:70
@ BVDataImpl
Represents BVDataPTAImpl.
Definition PTATY.h:42
PTATY
Pointer analysis type list.
Definition PTATY.h:9
@ Cxt_DDA
context sensitive DDA
Definition PTATY.h:32
@ VFS_WPA
Versioned sparse flow-sensitive WPA.
Definition PTATY.h:21
@ Andersen_WPA
Andersen PTA.
Definition PTATY.h:12
@ FSSPARSE_WPA
Sparse flow sensitive WPA.
Definition PTATY.h:20
@ AndersenSFR_WPA
Stride-based field representation.
Definition PTATY.h:14
@ FieldS_DDA
Field sensitive DDA.
Definition PTATY.h:29
@ FlowS_DDA
Flow sensitive DDA.
Definition PTATY.h:30
@ AndersenWaveDiff_WPA
Diff wave propagation andersen-style WPA.
Definition PTATY.h:15
@ CFLFICI_WPA
Flow-, context-, insensitive CFL-reachability-based analysis.
Definition PTATY.h:23
@ TypeCPP_WPA
Type-based analysis for C++.
Definition PTATY.h:26
@ FSDATAFLOW_WPA
Traditional Dataflow-based flow sensitive WPA.
Definition PTATY.h:19
@ Steensgaard_WPA
Steensgaard PTA.
Definition PTATY.h:16
@ FSCS_WPA
Flow-, context- sensitive WPA.
Definition PTATY.h:22
@ CFLFSCS_WPA
Flow-, context-, CFL-reachability-based analysis.
Definition PTATY.h:25
@ Andersen_BASE
Base Andersen PTA.
Definition PTATY.h:11
@ AndersenSCD_WPA
Selective cycle detection andersen-style WPA.
Definition PTATY.h:13
OrderedSet< NodeID > OrderedNodeSet
u32_t NodeID
Definition GeneralType.h:56
s64_t APOffset
Definition GeneralType.h:60
AliasResult
Definition SVFType.h:636
@ MayAlias
Definition SVFType.h:638
@ NoAlias
Definition SVFType.h:637
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
@ Mutable
Definition PTATY.h:49
@ Persistent
Definition PTATY.h:50