Static Value-Flow Analysis
Loading...
Searching...
No Matches
PointerAnalysis.cpp
Go to the documentation of this file.
1//===- PointerAnalysis.cpp -- Base class of pointer analyses------------------//
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 * PointerAnalysis.cpp
25 *
26 * Created on: May 14, 2013
27 * Author: Yulei Sui
28 */
29
30#include "Util/Options.h"
31#include "Util/SVFUtil.h"
32
33#include "MemoryModel/PTATY.h"
36#include "Util/PTAStat.h"
38#include "Graphs/ICFG.h"
39#include "Graphs/CallGraph.h"
41
42#include <cstdlib>
43#include <iomanip>
44#include <iostream>
45#include <fstream>
46#include <sstream>
47
48using namespace SVF;
49using namespace SVFUtil;
50
51
53
54const std::string PointerAnalysis::aliasTestMayAlias = "MAYALIAS";
55const std::string PointerAnalysis::aliasTestMayAliasMangled = "_Z8MAYALIASPvS_";
56const std::string PointerAnalysis::aliasTestNoAlias = "NOALIAS";
57const std::string PointerAnalysis::aliasTestNoAliasMangled = "_Z7NOALIASPvS_";
58const std::string PointerAnalysis::aliasTestPartialAlias = "PARTIALALIAS";
59const std::string PointerAnalysis::aliasTestPartialAliasMangled = "_Z12PARTIALALIASPvS_";
60const std::string PointerAnalysis::aliasTestMustAlias = "MUSTALIAS";
61const std::string PointerAnalysis::aliasTestMustAliasMangled = "_Z9MUSTALIASPvS_";
62const std::string PointerAnalysis::aliasTestFailMayAlias = "EXPECTEDFAIL_MAYALIAS";
63const std::string PointerAnalysis::aliasTestFailMayAliasMangled = "_Z21EXPECTEDFAIL_MAYALIASPvS_";
64const std::string PointerAnalysis::aliasTestFailNoAlias = "EXPECTEDFAIL_NOALIAS";
65const std::string PointerAnalysis::aliasTestFailNoAliasMangled = "_Z20EXPECTEDFAIL_NOALIASPvS_";
66
80
85{
86 destroy();
87 // do not delete the SVFIR for now
88 //delete pag;
89}
90
91
93{
94 SVFUtil::errs() << "getMayAliases is not supported by this pointer analysis.\n";
95 std::abort();
96}
97
98
100{
101 delete callgraph;
102 callgraph = nullptr;
103
104 delete callGraphSCC;
105 callGraphSCC = nullptr;
106
107 delete stat;
108 stat = nullptr;
109}
110
115{
116 assert(pag && "SVFIR has not been built!");
117
118 chgraph = pag->getCHG();
119
122 {
124 callgraph = bd.buildThreadCallGraph();
125 }
126 else
127 {
129 callgraph = bd.buildPTACallGraph();
130 }
132
133 // dump callgraph
135 getCallGraph()->dump("callgraph_initial");
136}
137
138
143{
145 assert(baseObjVar && "base object not found!!");
146 if(SVFUtil::isa<StackObjVar>(baseObjVar))
147 {
148 if(const FunObjVar* svffun = pag->getSVFVar(id)->getFunction())
149 {
150 return callGraphSCC->isInCycle(getCallGraph()->getCallGraphNode(svffun)->getId());
151 }
152 }
153 return false;
154}
155
160{
161 for (SVFIR::iterator nIter = pag->begin(); nIter != pag->end(); ++nIter)
162 {
163 if(ObjVar* node = SVFUtil::dyn_cast<ObjVar>(nIter->second))
164 const_cast<BaseObjVar*>(pag->getBaseObject(node->getId()))->setFieldSensitive();
165 }
166}
167
168/*
169 * Dump statistics
170 */
171
173{
174
175 if(print_stat && stat)
176 {
177 stat->performStat();
178 }
179}
180
186{
187
189 dumpStat();
190
192 if (Options::PTSPrint())
193 {
195 //dumpAllPts();
196 //dumpCPts();
197 }
198
199 if (Options::TypePrint())
200 dumpAllTypes();
201
203 dumpAllPts();
204
207
209
211 getCallGraph()->dump("callgraph_final");
212
215
218}
219
239
240
242{
243 for (OrderedNodeSet::iterator nIter = this->getAllValidPtrs().begin();
244 nIter != this->getAllValidPtrs().end(); ++nIter)
245 {
246 const SVFVar* node = getPAG()->getSVFVar(*nIter);
247 if (SVFUtil::isa<DummyObjVar, DummyValVar>(node))
248 continue;
249
250 outs() << "##<" << node->getName() << "> ";
251 outs() << "Source Loc: " << node->getSourceLoc();
252 outs() << "\nNodeID " << node->getId() << "\n";
253
254 const SVFType* type = node->getType();
256 }
257}
258
263{
264
265 const SVFVar* node = pag->getSVFVar(ptr);
267 if (SVFUtil::isa<DummyObjVar> (node))
268 {
269 outs() << "##<Dummy Obj > id:" << node->getId();
270 }
271 else if (!SVFUtil::isa<DummyValVar>(node) && !SVFIR::pagReadFromTXT())
272 {
273 outs() << "##<" << node->getName() << "> ";
274 outs() << "Source Loc: " << node->getSourceLoc();
275 }
276 outs() << "\nPtr " << node->getId() << " ";
277
278 if (pts.empty())
279 {
280 outs() << "\t\tPointsTo: {empty}\n\n";
281 }
282 else
283 {
284 outs() << "\t\tPointsTo: { ";
285 for (PointsTo::iterator it = pts.begin(), eit = pts.end(); it != eit;
286 ++it)
287 outs() << *it << " ";
288 outs() << "}\n\n";
289 }
290
291 outs() << "";
292
293 for (PointsTo::iterator it = pts.begin(), eit = pts.end(); it != eit; ++it)
294 {
295 const SVFVar* node = pag->getSVFVar(*it);
296 if(SVFUtil::isa<ObjVar>(node) == false)
297 continue;
298 NodeID ptd = node->getId();
299 outs() << "!!Target NodeID " << ptd << "\t [";
300 const SVFVar* pagNode = pag->getSVFVar(ptd);
301 if (SVFUtil::isa<DummyValVar>(node))
302 outs() << "DummyVal\n";
303 else if (SVFUtil::isa<DummyObjVar>(node))
304 outs() << "Dummy Obj id: " << node->getId() << "]\n";
305 else
306 {
308 {
309 outs() << "<" << pagNode->getName() << "> ";
310 outs() << "Source Loc: "
311 << pagNode->getSourceLoc() << "] \n";
312 }
313 }
314 }
315}
316
321{
322 outs() << "\nNodeID: " << getFunPtr(cs);
323 outs() << "\nCallSite: ";
324 outs() << cs->toString();
325 outs() << "\tLocation: " << cs->getSourceLoc();
326 outs() << "\t with Targets: ";
327
328 if (!targets.empty())
329 {
330 FunctionSet::const_iterator fit = targets.begin();
331 FunctionSet::const_iterator feit = targets.end();
332 for (; fit != feit; ++fit)
333 {
334 const FunObjVar* callee = *fit;
335 outs() << "\n\t" << callee->getName();
336 }
337 }
338 else
339 {
340 outs() << "\n\tNo Targets!";
341 }
342
343 outs() << "\n";
344}
345
350{
351 outs() << "==================Function Pointer Targets==================\n";
353 CallEdgeMap::const_iterator it = callEdges.begin();
354 CallEdgeMap::const_iterator eit = callEdges.end();
355 for (; it != eit; ++it)
356 {
357 const CallICFGNode* cs = it->first;
358 const FunctionSet& targets = it->second;
360 }
361
363 CallSiteToFunPtrMap::const_iterator csIt = indCS.begin();
364 CallSiteToFunPtrMap::const_iterator csEit = indCS.end();
365 for (; csIt != csEit; ++csIt)
366 {
367 const CallICFGNode* cs = csIt->first;
368 if (hasIndCSCallees(cs) == false)
369 {
370 outs() << "\nNodeID: " << csIt->second;
371 outs() << "\nCallSite: ";
372 outs() << cs->toString();
373 outs() << "\tLocation: " << cs->getSourceLoc();
374 outs() << "\n\t!!!has no targets!!!\n";
375 }
376 }
377}
378
379
380
385{
386
387 assert(pag->isIndirectCallSites(cs) && "not an indirect callsite?");
389 for (PointsTo::iterator ii = target.begin(), ie = target.end();
390 ii != ie; ii++)
391 {
392
394 {
395 writeWrnMsg("Resolved Indirect Call Edges are Out-Of-Budget, please increase the limit");
396 return;
397 }
398
399 if(const ObjVar* objPN = pag->getObjVar(*ii))
400 {
401 const BaseObjVar* obj = pag->getBaseObject(objPN->getId());
402
403 if(obj->isFunction())
404 {
405 const FunObjVar* calleefun = SVFUtil::cast<FunObjVar>(obj)->getFunction();
407
408 if(SVFUtil::matchArgs(cs, callee) == false)
409 continue;
410
411 if(0 == getIndCallMap()[cs].count(callee))
412 {
413 newEdges[cs].insert(callee);
414 getIndCallMap()[cs].insert(callee);
415
417 // FIXME: do we need to update llvm call graph here?
418 // The indirect call is maintained by ourself, We may update llvm's when we need to
419 //PTACallGraphNode* callgraphNode = callgraph->getOrInsertFunction(cs.getCaller());
420 //callgraphNode->addCalledFunction(cs,callgraph->getOrInsertFunction(callee));
421 }
422 }
423 }
424 }
425}
426
427/*
428 * Get virtual functions "vfns" based on CHA
429 */
435
436/*
437 * Get virtual functions "vfns" from PoninsTo set "target" for callsite "cs"
438 */
440{
441
443 {
446 for (PointsTo::iterator it = target.begin(), eit = target.end(); it != eit; ++it)
447 {
448 const SVFVar* ptdnode = pag->getSVFVar(*it);
449 const GlobalObjVar* pVar = nullptr;
451 {
453
454 }
455 else if (isa<ValVar>(ptdnode) &&
457 pag->getBaseValVar(ptdnode->getId())))
458 {
461 pag->getBaseValVar(ptdnode->getId()))));
462 }
463
464 if (pVar && chaVtbls.find(pVar) != chaVtbls.end())
465 vtbls.insert(pVar);
466 }
468 }
469}
470
471/*
472 * Connect callsite "cs" to virtual functions in "vfns"
473 */
475{
477 for (VFunSet::const_iterator fit = vfns.begin(),
478 feit = vfns.end(); fit != feit; ++fit)
479 {
480 const FunObjVar* callee = *fit;
482 if (getIndCallMap()[cs].count(callee) > 0)
483 continue;
484 if(cs->arg_size() == callee->arg_size() ||
485 (cs->isVarArg() && callee->isVarArg()))
486 {
487 newEdges[cs].insert(callee);
488 getIndCallMap()[cs].insert(callee);
489 const CallICFGNode* callBlockNode = cs;
490 callgraph->addIndirectCallGraphEdge(callBlockNode, cs->getCaller(),callee);
491 }
492 }
493}
494
497{
498 assert(cs->isVirtualCall() && "not cpp virtual call");
499
502 getVFnsFromCHA(cs, vfns);
503 else
504 getVFnsFromPts(cs, target, vfns);
506}
507
513{
514 // check for must alias cases, whether our alias analysis produce the correct results
515 if (const FunObjVar* checkFun = pag->getFunObjVar(fun))
516 {
517 if(!checkFun->isUncalledFunction())
518 outs() << "[" << this->PTAName() << "] Checking " << fun << "\n";
519
520 for(const CallICFGNode* callNode : pag->getCallSiteSet())
521 {
522 if (callNode->getCalledFunction() == checkFun)
523 {
524 assert(callNode->getNumArgOperands() == 2
525 && "arguments should be two pointers!!");
526 const SVFVar* V1 = callNode->getArgument(0);
527 const SVFVar* V2 = callNode->getArgument(1);
528 AliasResult aliasRes = alias(V1->getId(), V2->getId());
529
530 bool checkSuccessful = false;
531 if (fun == aliasTestMayAlias || fun == aliasTestMayAliasMangled)
532 {
534 checkSuccessful = true;
535 }
536 else if (fun == aliasTestNoAlias || fun == aliasTestNoAliasMangled)
537 {
539 checkSuccessful = true;
540 }
541 else if (fun == aliasTestMustAlias || fun == aliasTestMustAliasMangled)
542 {
543 // change to must alias when our analysis support it
545 checkSuccessful = true;
546 }
547 else if (fun == aliasTestPartialAlias || fun == aliasTestPartialAliasMangled)
548 {
549 // change to partial alias when our analysis support it
551 checkSuccessful = true;
552 }
553 else
554 assert(false && "not supported alias check!!");
555
556 NodeID id1 = V1->getId();
557 NodeID id2 = V2->getId();
558
559 if (checkSuccessful)
560 outs() << sucMsg("\t SUCCESS :") << fun << " check <id:" << id1 << ", id:" << id2 << "> at ("
561 << callNode->getSourceLoc() << ")\n";
562 else
563 {
564 SVFUtil::errs() << errMsg("\t FAILURE :") << fun
565 << " check <id:" << id1 << ", id:" << id2
566 << "> at (" << callNode->getSourceLoc() << ")\n";
567 assert(false && "test case failed!");
568 }
569 }
570 }
571 }
572}
573
578{
579
580 if (const FunObjVar* checkFun = pag->getFunObjVar(fun))
581 {
582 if(!checkFun->isUncalledFunction())
583 outs() << "[" << this->PTAName() << "] Checking " << fun << "\n";
584
585 for(const CallICFGNode* callNode : pag->getCallSiteSet())
586 {
587 if (callNode->getCalledFunction() == checkFun)
588 {
589 assert(callNode->arg_size() == 2
590 && "arguments should be two pointers!!");
591 const SVFVar* V1 = callNode->getArgument(0);
592 const SVFVar* V2 = callNode->getArgument(1);
593 AliasResult aliasRes = alias(V1->getId(), V2->getId());
594
595 bool expectedFailure = false;
597 {
598 // change to must alias when our analysis support it
600 expectedFailure = true;
601 }
602 else if (fun == aliasTestFailNoAlias || fun == aliasTestFailNoAliasMangled)
603 {
604 // change to partial alias when our analysis support it
606 expectedFailure = true;
607 }
608 else
609 assert(false && "not supported alias check!!");
610
611 NodeID id1 = V1->getId();
612 NodeID id2 = V2->getId();
613
614 if (expectedFailure)
615 outs() << sucMsg("\t EXPECTED-FAILURE :") << fun << " check <id:" << id1 << ", id:" << id2 << "> at ("
616 << callNode->getSourceLoc() << ")\n";
617 else
618 {
619 SVFUtil::errs() << errMsg("\t UNEXPECTED FAILURE :") << fun << " check <id:" << id1 << ", id:" << id2 << "> at ("
620 << callNode->getSourceLoc() << ")\n";
621 assert(false && "test case failed!");
622 }
623 }
624 }
625 }
626}
cJSON * p
Definition cJSON.cpp:2559
newitem type
Definition cJSON.cpp:2739
int count
Definition cJSON.h:216
void addIndirectCallGraphEdge(const CallICFGNode *cs, const FunObjVar *callerFun, const FunObjVar *calleeFun)
Add indirect call edges.
void dump(const std::string &filename)
Dump the graph.
void verifyCallGraph()
Issue a warning if the function which has indirect call sites can not be reached from program entry.
const std::string toString() const override
Definition ICFG.cpp:129
bool isVarArg() const
Definition ICFGNode.h:506
const std::string getSourceLoc() const override
Definition ICFGNode.h:571
bool isVirtualCall() const
Definition ICFGNode.h:510
const FunObjVar * getCaller() const
Return callsite.
Definition ICFGNode.h:453
u32_t arg_size() const
Definition ICFGNode.h:488
virtual const VFunSet & getCSVFsBasedonCHA(const CallICFGNode *cs)=0
virtual bool csHasVFnsBasedonCHA(const CallICFGNode *cs)=0
virtual const VTableSet & getCSVtblsBasedonCHA(const CallICFGNode *cs)=0
virtual void getVFnsFromVtbls(const CallICFGNode *cs, const VTableSet &vtbls, VFunSet &virtualFunctions)=0
virtual bool csHasVtblsBasedonCHA(const CallICFGNode *cs)=0
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
const FunObjVar * getDefFunForMultipleModule() const
iterator begin()
Iterators.
IDToNodeMapTy::iterator iterator
Node Iterators.
void printFlattenFields(const SVFType *type)
Debug method.
Definition IRGraph.cpp:77
bool isBuiltFromFile()
Whether this SVFIR built from a txt file.
Definition IRGraph.h:149
static const Option< bool > CallGraphDotGraph
Definition Options.h:122
static const Option< bool > EnableThreadCallGraph
Definition Options.h:128
static const Option< bool > PTSPrint
Definition Options.h:112
static const Option< bool > EnableAliasCheck
Definition Options.h:126
static const Option< bool > PTSAllPrint
Definition Options.h:113
static const Option< bool > TypePrint
Definition Options.h:110
static Option< bool > UsePreCompFieldSensitive
Definition Options.h:125
static const Option< u32_t > IndirectCallLimit
Definition Options.h:124
static const Option< bool > FuncPointerPrint
Definition Options.h:111
static const Option< bool > ConnectVCallOnCHA
Definition Options.h:129
static const Option< bool > PStat
Definition Options.h:115
static const Option< u32_t > StatBudget
Definition Options.h:116
void performStat() override
Definition PTAStat.cpp:53
virtual NodeBS getMayAliases(NodeID node)
void getVFnsFromPts(const CallICFGNode *cs, const PointsTo &target, VFunSet &vfns)
void destroy()
Release the memory.
virtual void validateTests()
Alias check functions to verify correctness of pointer analysis.
CommonCHGraph * chgraph
CHGraph.
static const std::string aliasTestNoAliasMangled
bool isLocalVarInRecursiveFun(NodeID id) const
Whether a local variable is in function recursions.
virtual void finalize()
Finalization of a pointer analysis, including checking alias correctness.
static const std::string aliasTestMayAliasMangled
static const std::string aliasTestFailNoAlias
virtual void dumpPts(NodeID ptr, const PointsTo &pts)
static const std::string aliasTestFailMayAlias
bool print_stat
User input flags.
OrderedMap< const CallICFGNode *, FunctionSet > CallEdgeMap
Set< const GlobalObjVar * > VTableSet
virtual void initialize()
Initialization of a pointer analysis, including building symbol table and SVFIR etc.
virtual ~PointerAnalysis()
Destructor.
PTAImplTy ptaImplTy
PTA implementation type.
PTAStat * stat
Statistics.
virtual void dumpTopLevelPtsTo()
static const std::string aliasTestFailMayAliasMangled
SVFIR * getPAG() const
void connectVCallToVFns(const CallICFGNode *cs, const VFunSet &vfns, CallEdgeMap &newEdges)
CallGraph * getCallGraph() const
Return call graph.
OrderedNodeSet & getAllValidPtrs()
Get all Valid Pointers for resolution.
void resetObjFieldSensitive()
Reset all object node as field-sensitive.
static const std::string aliasTestMustAlias
static const std::string aliasTestMayAlias
Set< const FunObjVar * > FunctionSet
virtual void validateSuccessTests(std::string fun)
const CallSiteToFunPtrMap & getIndirectCallsites() const
Return all indirect callsites.
static const std::string aliasTestPartialAlias
virtual void dumpAllPts()
virtual AliasResult alias(const SVFVar *V1, const SVFVar *V2)=0
Interface exposed to users of our pointer analysis, given Value infos.
virtual void resolveIndCalls(const CallICFGNode *cs, const PointsTo &target, CallEdgeMap &newEdges)
Resolve indirect call edges.
CallGraph * callgraph
Call graph used for pointer analysis.
PointerAnalysis(SVFIR *pag, PTATY ty=PTATY::Default_PTA, bool alias_check=true)
Constructor.
bool alias_validation
Flag for validating points-to/alias results.
void callGraphSCCDetection()
PTACallGraph SCC related methods.
void dumpStat()
Dump the statistics.
virtual void validateExpectedFailureTests(std::string fun)
bool hasIndCSCallees(const CallICFGNode *cs) const
virtual void resolveCPPIndCalls(const CallICFGNode *cs, const PointsTo &target, CallEdgeMap &newEdges)
Resolve cpp indirect call edges.
CallEdgeMap & getIndCallMap()
Get callees from an indirect callsite.
static const std::string aliasTestNoAlias
static const std::string aliasTestPartialAliasMangled
u32_t getNumOfResolvedIndCallEdge() const
Return number of resolved indirect call edges.
SVFIR::CallSiteToFunPtrMap CallSiteToFunPtrMap
NodeID getFunPtr(const CallICFGNode *cs) const
Return function pointer PAGNode at a callsite cs.
static SVFIR * pag
SVFIR.
void getVFnsFromCHA(const CallICFGNode *cs, VFunSet &vfns)
CallGraphSCC * callGraphSCC
SCC for PTACallGraph.
static const std::string aliasTestMustAliasMangled
virtual const std::string PTAName() const
Return PTA name.
static const std::string aliasTestFailNoAliasMangled
Set< const FunObjVar * > VFunSet
u32_t OnTheFlyIterBudgetForStat
Flag for iteration budget for on-the-fly statistics.
const_iterator end() const
Definition PointsTo.h:133
const_iterator begin() const
Definition PointsTo.h:129
const CallSiteSet & getCallSiteSet() const
Get all callsites.
Definition SVFIR.h:351
bool isIndirectCallSites(const CallICFGNode *cs) const
Definition SVFIR.h:469
static bool pagReadFromTXT()
Definition SVFIR.h:280
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:498
const FunObjVar * getFunObjVar(const std::string &name)
Definition SVFIR.cpp:48
const ObjVar * getObjVar(NodeID id) const
Definition SVFIR.h:149
CommonCHGraph * getCHG()
Definition SVFIR.h:241
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:135
const ValVar * getBaseValVar(NodeID id) const
Definition SVFIR.h:508
NodeID getId() const
Get ID.
Definition SVFValue.h:158
virtual const SVFType * getType() const
Definition SVFValue.h:169
virtual const std::string getSourceLoc() const
Definition SVFValue.h:194
virtual const std::string & getName() const
Definition SVFValue.h:184
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition SVFUtil.cpp:59
const ObjVar * getObjVarOfValVar(const ValVar *valVar)
Definition SVFUtil.cpp:435
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:82
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
bool matchArgs(const CallICFGNode *cs, const FunObjVar *callee)
Definition SVFUtil.cpp:312
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
Definition SVFUtil.cpp:72
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:70
@ BaseImpl
Represents PointerAnalaysis.
Definition PTATY.h:41
PTATY
Pointer analysis type list.
Definition PTATY.h:9
u32_t NodeID
Definition GeneralType.h:76
AliasResult
Definition SVFType.h:619
@ PartialAlias
Definition SVFType.h:623
@ MustAlias
Definition SVFType.h:622
@ MayAlias
Definition SVFType.h:621
@ NoAlias
Definition SVFType.h:620
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76