Static Value-Flow Analysis
Loading...
Searching...
No Matches
LockAnalysis.cpp
Go to the documentation of this file.
1//===- LockAnalysis.cpp -- Analysis of locksets-------------//
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 * LocksetAnalysis.cpp
25 *
26 * Created on: 26 Aug 2015
27 * Author: pengd
28 *
29 * Lock analysis. One implementation runs on the whole program or a slice via
30 * the templated analyze() (GraphT = SVFIR* or const SlicedSVFIRView*), as used
31 * by "Multi-Stage On-Demand Program Slicing for Modular Analysis of
32 * Multi-Threaded Programs" (ISSTA 2026).
33 */
34
35#include "Util/Options.h"
36#include "MTA/LockAnalysis.h"
37#include "MTA/MTA.h"
38#include "MTA/MTASlicer.h"
39#include "Util/SVFUtil.h"
40#include "Util/PTAStat.h"
42#include "SVFIR/SVFIR.h"
43#include "Graphs/SlicedGraphs.h"
44
45
46using namespace SVF;
47using namespace SVFUtil;
48
49
50
51template<class ICFGGraph, class CGGraph>
53{
54
57
58 DOTIMESTAT(double lockStart = PTAStat::getClk(true));
59
60 DBOUT(DGENERAL, outs() << "\tIntra-procedural LockAnalysis\n");
61 DBOUT(DMTA, outs() << "\tIntra-procedural LockAnalysis\n");
63
64 DBOUT(DGENERAL, outs() << "\tCollect context-sensitive locks\n");
65 DBOUT(DMTA, outs() << "\tCollect context-sensitive locks\n");
66 collectCxtLock(icfg, cg);
67
68 DBOUT(DGENERAL, outs() << "\tInter-procedural LockAnalysis\n");
69 DBOUT(DMTA, outs() << "\tInter-procedural LockAnalysis\n");
71
72 DOTIMESTAT(double lockEnd = PTAStat::getClk(true));
74}
75
76
80template<class ICFGGraph, class CGGraph>
82{
84
86 {
87 const FunObjVar* F = item.second->getFunction();
88 for (auto it : *F)
89 {
90 const SVFBasicBlock* bb = it.second;
91 for (const ICFGNode* icfgNode : bb->getICFGNodeList())
92 {
94 continue;
95 if (isa<CallICFGNode>(icfgNode) && tcg->getThreadAPI()->isTDRelease(cast<CallICFGNode>(icfgNode)))
96 {
97 unlocksites.insert(icfgNode);
98 }
99 if (isa<CallICFGNode>(icfgNode) && tcg->getThreadAPI()->isTDAcquire(cast<CallICFGNode>(icfgNode)))
100 {
101 locksites.insert(icfgNode);
102 }
103 }
104 }
105 }
106}
107
112{
113
115
116 TCT::PTACGNodeSet visited;
118
119 for (InstSet::iterator it = locksites.begin(), eit = locksites.end(); it != eit; ++it)
120 {
121 const FunObjVar* fun=(*it)->getFun();
123 if (visited.find(cgnode) == visited.end())
124 {
125 worklist.push(cgnode);
126 visited.insert(cgnode);
127 }
128 }
129 for (InstSet::iterator it = unlocksites.begin(), eit = unlocksites.end(); it != eit; ++it)
130 {
131 const FunObjVar* fun = (*it)->getFun();
133 if (visited.find(cgnode) == visited.end())
134 {
135 worklist.push(cgnode);
136 visited.insert(cgnode);
137 }
138 }
139 while (!worklist.empty())
140 {
141 const CallGraphNode* node = worklist.pop();
142 lockcandidateFuncSet.insert(node->getFunction());
143 for (CallGraphNode::const_iterator nit = node->InEdgeBegin(), neit = node->InEdgeEnd(); nit != neit; nit++)
144 {
145 const CallGraphNode* srcNode = (*nit)->getSrcNode();
146 if (visited.find(srcNode) == visited.end())
147 {
148 visited.insert(srcNode);
149 worklist.push(srcNode);
150 }
151 }
152 }
153}
154
159template<class ICFGGraph, class CGGraph>
161{
162
163 // Identify the protected Instructions.
164 for (InstSet::const_iterator it = locksites.begin(), ie = locksites.end(); it != ie; ++it)
165 {
166 const ICFGNode* lockSite = *it;
167 assert(isCallSite(lockSite) && "Lock acquire instruction must be a CallSite");
168
169 // Perform forward traversal
173
176
178 if(forward && backward)
180 else if(forward && !backward)
182 }
183}
184
188template<class ICFGGraph, class CGGraph>
190{
191
192 const FunObjVar* svfFun = lockSite->getFun();
193
194 InstVec worklist;
195 worklist.push_back(lockSite);
196 while (!worklist.empty())
197 {
198 const ICFGNode *I = worklist.back();
199 worklist.pop_back();
200 const ICFGNode* exitInst = svfFun->getExitBB()->back();
201 if(exitInst == I)
202 return false;
203
204 // Skip the visited Instructions.
205 if (forwardInsts.find(I)!=forwardInsts.end())
206 continue;
207 forwardInsts.insert(I);
208
209 if (isTDRelease(I) && isAliasedLocks(lockSite, I))
210 {
211 unlockSet.insert(I);
212 DBOUT(DMTA, outs() << "LockAnalysis ci lock -- " << lockSite->getSourceLoc()<<"\n");
213 DBOUT(DMTA, outs() << "LockAnalysis ci unlock -- " << I->getSourceLoc()<<"\n");
214 continue;
215 }
216
217 std::vector<const ICFGNode*> succ;
219 for (const ICFGNode* dst : succ)
220 {
221 if(dst->getFun() == I->getFun())
222 {
223 worklist.push_back(dst);
224 }
225 }
226 }
227
228 return true;
229}
230
231
235template<class ICFGGraph, class CGGraph>
237{
238
239 InstVec worklist;
240 for(InstSet::const_iterator it = unlockSet.begin(), eit = unlockSet.end(); it!=eit; ++it)
241 {
242 const ICFGNode* unlockSite = *it;
244 worklist.push_back(*it);
245
246 while (!worklist.empty())
247 {
248 const ICFGNode *I = worklist.back();
249 worklist.pop_back();
250
251 if(entryInst == I)
252 return false;
253
254 // Skip the visited Instructions.
255 if (backwardInsts.find(I)!=backwardInsts.end())
256 continue;
257 backwardInsts.insert(I);
258
260 {
261 DBOUT(DMTA, outs() << "LockAnalysis ci lock -- " << I->getSourceLoc()<<"\n");
262 DBOUT(DMTA, outs() << "LockAnalysis ci unlock -- " << unlockSite->getSourceLoc()<<"\n");
263 continue;
264 }
265
266 std::vector<const ICFGNode*> pred;
268 for (const ICFGNode* src : pred)
269 {
270 if(src->getFun() == I->getFun())
271 {
272 worklist.push_back(src);
273 }
274 }
275 }
276 }
277
278 return true;
279}
280
281
282template<class ICFGGraph, class CGGraph>
284{
285 const TCT::FunSet& entryFuncSet = tct->getEntryProcs();
286 for (TCT::FunSet::const_iterator it = entryFuncSet.begin(), eit = entryFuncSet.end(); it != eit; ++it)
287 {
288 if (!isLockCandidateFun(*it))
289 continue;
290 CallStrCxt cxt;
291 CxtLockProc t(cxt, *it);
293 }
294
295 while (!clpList.empty())
296 {
298 CallGraphNode* cgNode = getTCG()->getCallGraphNode(clp.getProc());
299 // lzh TODO.
300 if (!isLockCandidateFun(cgNode->getFunction()))
301 continue;
302
303 for (CallGraphNode::const_iterator nit = cgNode->OutEdgeBegin(), neit = cgNode->OutEdgeEnd(); nit != neit; nit++)
304 {
305 const CallGraphEdge* cgEdge = (*nit);
306
307 for (CallGraphEdge::CallInstSet::const_iterator cit = cgEdge->directCallsBegin(), ecit = cgEdge->directCallsEnd();
308 cit != ecit; ++cit)
309 {
310 DBOUT(DMTA,
311 outs() << "\nCollecting CxtLocks: handling direct call:" << **cit << "\t" << cgEdge->getSrcNode()->getFunction()->getName()
312 << "-->" << cgEdge->getDstNode()->getFunction()->getName() << "\n");
314 }
315 for (CallGraphEdge::CallInstSet::const_iterator ind = cgEdge->indirectCallsBegin(), eind = cgEdge->indirectCallsEnd();
316 ind != eind; ++ind)
317 {
318 DBOUT(DMTA,
319 outs() << "\nCollecting CxtLocks: handling indirect call:" << **ind << "\t"
320 << cgEdge->getSrcNode()->getFunction()->getName() << "-->" << cgEdge->getDstNode()->getFunction()->getName()
321 << "\n");
323 }
324 }
325 }
326}
327
328
332template<class ICFGGraph, class CGGraph>
334{
335
336 CallStrCxt cxt(clp.getContext());
337 const ICFGNode* curNode = cs;
339 return;
340 if (isTDAcquire(curNode))
341 {
342 addCxtLock(cxt,curNode);
343 return;
344 }
345 const FunObjVar* svfcallee = cgEdge->getDstNode()->getFunction();
346 pushCxt(cxt, SVFUtil::cast<CallICFGNode>(curNode), svfcallee);
347
350 {
351 DBOUT(DMTA, outs() << "LockAnalysis Process CallRet old clp --"; clp.dump());
352 DBOUT(DMTA, outs() << "LockAnalysis Process CallRet new clp --"; newclp.dump());
353 }
354
355}
356
358{
360 return tct->getPTA()->alias(getLockVal(i1)->getId(), getLockVal(i2)->getId());
361}
362
363template<class ICFGGraph, class CGGraph>
365{
366
367 const TCT::FunSet& entryFuncSet = tct->getEntryProcs();
368 for (TCT::FunSet::const_iterator it = entryFuncSet.begin(), eit = entryFuncSet.end(); it != eit; ++it)
369 {
370 if (!isLockCandidateFun(*it))
371 continue;
372 CallStrCxt cxt;
375 continue;
378 }
379
380 while (!cxtStmtList.empty())
381 {
383
385 const ICFGNode* curInst = cts.getStmt();
387 continue;
389
390 DBOUT(DMTA, outs() << "\nVisit cxtStmt: ");
391 DBOUT(DMTA, cts.dump());
392
393 DBOUT(DMTA, outs() << "\nIts cxt lock sets: ");
395
396 if (isTDFork(curInst))
397 {
398 handleFork(icfg, cg, cts);
399 }
400 else if (isTDAcquire(curInst))
401 {
402 assert(hasCxtLock(cts) && "context-sensitive lock not found!!");
404 handleIntra(icfg, cg, cts);
405 }
406 else if (isTDRelease(curInst))
407 {
409 handleIntra(icfg, cg, cts);
410 }
411 else if (isCallSite(curInst) && !isExtCall(curInst))
412 {
413 handleCall(icfg, cg, cts);
414 }
415 else if (SVFUtil::dyn_cast<FunExitICFGNode>(curInst))
416 {
417 handleRet(icfg, cg, cts);
418 }
419 else
420 {
421 handleIntra(icfg, cg, cts);
422 }
423
424 }
425
426}
427
428
433{
435 outs() << "\nlock sets size = " << lockset.size() << "\n";
436 for (CxtLockSet::const_iterator it = lockset.begin(), eit = lockset.end(); it != eit; ++it)
437 {
438 (*it).dump();
439 }
440}
441
442
443
445template<class ICFGGraph, class CGGraph>
447{
448 const CallStrCxt& curCxt = cts.getContext();
449 const CallICFGNode* call = SVFUtil::dyn_cast<CallICFGNode>(cts.getStmt());
450 if(getTCG()->hasThreadForkEdge(call))
451 {
452 for (ThreadCallGraph::ForkEdgeSet::const_iterator cgIt = getTCG()->getForkEdgeBegin(call),
453 ecgIt = getTCG()->getForkEdgeEnd(call); cgIt != ecgIt; ++cgIt)
454 {
455 const FunObjVar* svfcallee = (*cgIt)->getDstNode()->getFunction();
460 continue;
463 }
464 }
465 handleIntra(icfg, cg, cts);
466}
467
469template<class ICFGGraph, class CGGraph>
471{
472
473 const CallStrCxt& curCxt = cts.getContext();
474 const CallICFGNode* call = SVFUtil::dyn_cast<CallICFGNode>(cts.getStmt());
475 if (getTCG()->hasCallGraphEdge(call))
476 {
477 for (CallGraph::CallGraphEdgeSet::const_iterator cgIt = getTCG()->getCallEdgeBegin(call), ecgIt = getTCG()->getCallEdgeEnd(call);
478 cgIt != ecgIt; ++cgIt)
479 {
480 const FunObjVar* svfcallee = (*cgIt)->getDstNode()->getFunction();
482 continue;
484 pushCxt(newCxt, call, svfcallee);
487 continue;
490
491 // Return-flow rendezvous (see MHP::handleCall): forward an already
492 // computed callee-exit lockset to this callsite's return site.
493 if (svfcallee->hasBasicBlock())
494 {
495 const ICFGNode* exitInst = svfcallee->getExitBB()->back();
498 {
499 const ICFGNode* retNode = call->getRetICFGNode();
501 {
504 }
505 }
506 }
507 }
508 }
509}
510
512template<class ICFGGraph, class CGGraph>
514{
515
516 const ICFGNode* curInst = cts.getStmt();
517 const CallStrCxt& curCxt = cts.getContext();
518 const FunObjVar* svffun = curInst->getFun();
520
521 std::vector<const CallGraphEdge*> inEdges;
523 for (const CallGraphEdge* edgeConst : inEdges)
524 {
525 if (SVFUtil::isa<ThreadForkEdge, ThreadJoinEdge>(edgeConst))
526 continue;
527 // Need non-const for directCallsBegin/End
528 CallGraphEdge* edge = const_cast<CallGraphEdge*>(edgeConst);
529 for (CallGraphEdge::CallInstSet::const_iterator cit = (edge)->directCallsBegin(), ecit = (edge)->directCallsEnd(); cit != ecit;
530 ++cit)
531 {
533 const ICFGNode* inst = *cit;
534 if (matchCxt(newCxt, SVFUtil::cast<CallICFGNode>(inst), curFunNode->getFunction()))
535 {
536 std::vector<const ICFGNode*> succ;
538 for (const ICFGNode* dst : succ)
539 {
540 if(dst->getFun() == inst->getFun())
541 {
542 // Iterate over callSite's call string context and use as the successor's context
543 if (!hasCxtStmtFromInst(*cit))
544 continue;
545 for (const CxtStmt& cxtStmt: getCxtStmtsFromInst(*cit))
546 {
547 CallStrCxt callSiteCxt = cxtStmt.getContext();
548 // If new context is a suffix of the call site context
550 {
553 }
554 }
555 }
556 }
557 }
558 }
559 for (CallGraphEdge::CallInstSet::const_iterator cit = (edge)->indirectCallsBegin(), ecit = (edge)->indirectCallsEnd();
560 cit != ecit; ++cit)
561 {
563 const ICFGNode* inst = *cit;
564 if (matchCxt(newCxt, SVFUtil::cast<CallICFGNode>(inst), curFunNode->getFunction()))
565 {
566 std::vector<const ICFGNode*> succ;
568 for (const ICFGNode* dst : succ)
569 {
570 if(dst->getFun() == inst->getFun())
571 {
572 // Iterate over callSite's call string context and use as the successor's context
573 if (!hasCxtStmtFromInst(*cit))
574 continue;
575 for (const CxtStmt& cxtStmt: getCxtStmtsFromInst(*cit))
576 {
577 CallStrCxt callSiteCxt = cxtStmt.getContext();
578 // If new context is a suffix of the call site context
580 {
583 }
584 }
585 }
586 }
587 }
588 }
589 }
590}
591
593template<class ICFGGraph, class CGGraph>
595{
596
597 const ICFGNode* curInst = cts.getStmt();
598 const CallStrCxt& curCxt = cts.getContext();
599
600 std::vector<const ICFGNode*> succ;
602 for (const ICFGNode* dst : succ)
603 {
604 if(dst->getFun() == curInst->getFun())
605 {
606 CxtStmt newCts(curCxt, dst);
608 }
609 }
610}
611
613{
614 tct->pushCxt(cxt,call,callee);
615}
616
618{
619 const FunObjVar* svfcaller = call->getFun();
620 CallSiteID csId = getTCG()->getCallSiteID(call, callee);
621
622// /// handle calling context for candidate functions only
623// if (isLockCandidateFun(caller) == false)
624// return true;
625
627 if (cxt.empty())
628 return true;
629
630 if (tct->inSameCallGraphSCC(getTCG()->getCallGraphNode(svfcaller), getTCG()->getCallGraphNode(callee)) == false)
631 {
632 if (cxt.back() == csId)
633 cxt.pop_back();
634 else
635 return false;
636 DBOUT(DMTA, tct->dumpCxt(cxt));
637 }
638 return true;
639}
640
642{
643 return tct->isContextSuffix(lhs,call);
644}
645
646
663
668{
669
671 {
674 for (InstSet::const_iterator cil1 = lockset1.begin(), ecil1 = lockset1.end(); cil1!=ecil1; ++cil1)
675 {
676 for (InstSet::const_iterator cil2=lockset2.begin(), ecil2=lockset2.end(); cil2!=ecil2; ++cil2)
677 {
678 if (isAliasedLocks(*cil1, *cil2))
679 return true;
680 }
681 }
682 }
683 return false;
684}
685
697
702{
704 return false;
707 for (CxtStmtSet::const_iterator cts1 = ctsset1.begin(), ects1 = ctsset1.end(); cts1 != ects1; cts1++)
708 {
709 const CxtStmt& cxtStmt1 = *cts1;
710 for (CxtStmtSet::const_iterator cts2 = ctsset2.begin(), ects2 = ctsset2.end(); cts2 != ects2; cts2++)
711 {
712 const CxtStmt& cxtStmt2 = *cts2;
713 if(cxtStmt1==cxtStmt2)
714 {
715 // i1==i2 under the same context: a self-race between two dynamic
716 // instances of one statement (e.g. a thread forked in a loop).
717 // This is the ONLY pair the loop produces for such a query, so
718 // skipping it would fall through to the vacuous "protected" return
719 // below and drop a real race. The two instances are mutually
720 // excluded only if this context actually holds a (non-empty) lock.
722 return false;
723 continue;
724 }
726 return false;
727 }
728 }
729 return true;
730}
731
732
737{
738 DOTIMESTAT(double queryStart = PTAStat::getClk(true));
739
740 bool sameSpan = false;
743 else
745
746 DOTIMESTAT(double queryEnd = PTAStat::getClk(true));
748 return sameSpan;
749}
750
755{
757 {
760 for (InstSet::const_iterator cil1 = lockset1.begin(), ecil1 = lockset1.end(); cil1!=ecil1; ++cil1)
761 {
762 for (InstSet::const_iterator cil2=lockset2.begin(), ecil2=lockset2.end(); cil2!=ecil2; ++cil2)
763 {
764 if (*cil1==*cil2)
765 return true;
766 }
767 }
768 }
769 return false;
770}
771
787{
789 return false;
792
793 for (CxtStmtSet::const_iterator cts1 = ctsset1.begin(), ects1 = ctsset1.end(); cts1 != ects1; cts1++)
794 {
795 const CxtStmt& cxtStmt1 = *cts1;
796 for (CxtStmtSet::const_iterator cts2 = ctsset2.begin(), ects2 = ctsset2.end(); cts2 != ects2; cts2++)
797 {
798 const CxtStmt& cxtStmt2 = *cts2;
799 if(cxtStmt1==cxtStmt2) continue;
801 return false;
802 }
803 }
804 return true;
805}
806
807// The two graphs the lock analysis runs on; the algorithm above is written once
808// and instantiated for both (all internal templates instantiate transitively).
809template void LockAnalysis::analyze<ICFG*, CallGraph*>(ICFG*, CallGraph*);
810template void LockAnalysis::analyze<const SlicedICFGView*, const SlicedThreadCallGraphView*>(const SlicedICFGView*, const SlicedThreadCallGraphView*);
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition SVFType.h:576
#define TIMEINTERVAL
Definition SVFType.h:604
#define DMTA
Definition SVFType.h:597
#define DGENERAL
Definition SVFType.h:582
#define DOTIMESTAT(X)
Definition SVFType.h:578
cJSON * item
Definition cJSON.h:222
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
const CallGraphNode * getCallGraphNode(const std::string &name) const
Get call graph node.
CallSiteID getCallSiteID(const CallICFGNode *cs, const FunObjVar *callee) const
Get CallSiteID.
Definition CallGraph.h:389
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition ICFGNode.h:440
bool push(const Data &data)
Definition WorkList.h:180
bool empty() const
Definition WorkList.h:161
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
const SVFBasicBlock * getEntryBlock() const
iterator OutEdgeEnd()
iterator OutEdgeBegin()
iterators
GEdgeSetTy::const_iterator const_iterator
iterator InEdgeBegin()
iterator InEdgeEnd()
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
Definition ICFGNode.h:75
Set< CxtLock > CxtLockSet
void analyze(ICFGGraph icfg, CGGraph cg)
bool removeCxtStmtToSpan(CxtStmt &cts, const CxtLock &cl)
Add context-sensitive statement.
CxtStmtWorkList cxtStmtList
context-sensitive statement worklist
bool isProtectedByCommonCILock(const ICFGNode *i1, const ICFGNode *i2)
void handleIntra(ICFGGraph icfg, CGGraph cg, const CxtStmt &cts)
Handle intra.
bool isInSameCSSpan(const ICFGNode *i1, const ICFGNode *i2) const
bool isProtectedByCommonLock(const ICFGNode *i1, const ICFGNode *i2)
bool isInSameSpan(const ICFGNode *I1, const ICFGNode *I2)
bool intraBackwardTraverse(ICFGGraph icfg, CGGraph cg, const InstSet &unlockset, InstSet &backwardInsts)
void buildCandidateFuncSetforLock()
void markCxtStmtFlag(const CxtStmt &tgr, const CxtStmt &src)
Mark thread flags for cxtStmt.
bool hasCxtLockfromCxtStmt(const CxtStmt &cts) const
bool isExtCall(const ICFGNode *inst)
Whether it is calling an external function.
void collectLockUnlocksites(ICFGGraph icfg, CGGraph cg)
Set< CxtStmt > CxtStmtSet
bool alias(const CxtLockSet &lockset1, const CxtLockSet &lockset2)
Return true if two locksets has at least one alias lock.
void handleFork(ICFGGraph icfg, CGGraph cg, const CxtStmt &cts)
Handle fork.
CxtStmt popFromCTSWorkList()
FunSet lockcandidateFuncSet
Candidate functions which relevant to locks/unlocks.
bool isInsideIntraLock(const ICFGNode *stmt) const
Return true if a statement is inside an intra-procedural lock.
const SVFVar * getLockVal(const ICFGNode *call)
Get lock value.
bool intraForwardTraverse(ICFGGraph icfg, CGGraph cg, const ICFGNode *lock, InstSet &unlockset, InstSet &forwardInsts)
void analyzeLockSpanCxtStmt(ICFGGraph icfg, CGGraph cg)
ThreadCallGraph * getTCG() const
ThreadCallGraph.
bool isInsideCondIntraLock(const ICFGNode *stmt) const
Return true if a statement is inside a partial lock/unlock pair (conditional lock with unconditional ...
void pushCxt(CallStrCxt &cxt, const CallICFGNode *call, const FunObjVar *callee)
Context helper functions.
void addCondIntraLock(const ICFGNode *lockSite, const InstSet &stmts)
Add intra-procedural lock.
bool hasCxtLock(const CxtLock &cxtLock) const
Get context-sensitive lock.
bool isTDRelease(const ICFGNode *call)
Whether it is a unlock site.
bool addCxtStmtToSpan(const CxtStmt &cts, const CxtLock &cl)
Add context-sensitive statement.
bool isTDFork(const ICFGNode *call)
Whether it is a lock site.
void handleRet(ICFGGraph icfg, CGGraph cg, const CxtStmt &cts)
Handle return.
InstSet locksites
Record all visited clps.
void analyzeIntraProcedualLock(ICFGGraph icfg, CGGraph cg)
bool isProtectedByCommonCxtLock(const ICFGNode *i1, const ICFGNode *i2)
bool pushToCTPWorkList(const CxtLockProc &clp)
WorkList helper functions.
const InstSet & getIntraLockSet(const ICFGNode *stmt) const
void handleCall(ICFGGraph icfg, CGGraph cg, const CxtStmt &cts)
Handle call.
bool hasCxtStmtFromInst(const ICFGNode *inst) const
Context-sensitive statement and lock spans.
bool pushToCTSWorkList(const CxtStmt &cs)
Worklist operations.
void addIntraLock(const ICFGNode *lockSite, const InstSet &stmts)
Add intra-procedural lock.
void touchCxtStmt(CxtStmt &cts)
Touch this context statement.
Set< const ICFGNode * > InstSet
bool isLockCandidateFun(const FunObjVar *fun) const
Return true if it is a candidate function.
void printLocks(const CxtStmt &cts)
Print locks and spans.
bool isContextSuffix(const CallStrCxt &lhs, const CallStrCxt &call)
If lhs is a suffix of rhs, including equal.
CxtLockProc popFromCTPWorkList()
bool matchCxt(CallStrCxt &cxt, const CallICFGNode *call, const FunObjVar *callee)
Match context.
void handleCallRelation(ICFGGraph icfg, CGGraph cg, CxtLockProc &clp, const CallGraphEdge *cgEdge, const CallICFGNode *call)
Handle call relations.
const CxtStmtSet & getCxtStmtsFromInst(const ICFGNode *inst) const
bool isInSameCISpan(const ICFGNode *i1, const ICFGNode *i2) const
void collectCxtLock(ICFGGraph icfg, CGGraph cg)
bool isAliasedLocks(const CxtLock &cl1, const CxtLock &cl2)
Return true it a lock matches an unlock.
InstToCxtStmtSet instToCxtStmtSet
Map a statement to all its context-sensitive statements.
TCT::InstVec InstVec
const CxtLockSet & getCxtLockfromCxtStmt(const CxtStmt &cts) const
void addCxtLock(const CallStrCxt &cxt, const ICFGNode *inst)
Context-sensitive locks.
bool intersects(const CxtLockSet &lockset1, const CxtLockSet &lockset2) const
Return true if the intersection of two locksets is not empty.
bool isCallSite(const ICFGNode *inst)
Whether it is a callsite.
CxtLockProcVec clpList
Following data structures are used for collecting context-sensitive locks.
bool isTDAcquire(const ICFGNode *call)
Whether it is a lock site.
virtual AliasResult alias(const SVFVar *V1, const SVFVar *V2)=0
Interface exposed to users of our pointer analysis, given Value infos.
const std::vector< const ICFGNode * > & getICFGNodeList() const
const ICFGNode * back() const
static double getClk(bool mark=false)
Definition SVFStat.cpp:51
virtual const std::string getSourceLoc() const
Definition SVFValue.h:194
bool isContextSuffix(const CallStrCxt &lhs, const CallStrCxt &call)
If lhs is a suffix of rhs, including equal.
Definition TCT.cpp:521
OrderedSet< const FunObjVar *, FunObjVarIdCmp > FunSet
Definition TCT.h:172
PointerAnalysis * getPTA() const
Get PTA.
Definition TCT.h:198
Set< const CallGraphNode * > PTACGNodeSet
Definition TCT.h:175
ThreadCallGraph * getThreadCallGraph() const
Get TCG.
Definition TCT.h:193
bool inSameCallGraphSCC(const CallGraphNode *src, const CallGraphNode *dst)
Whether two functions in the same callgraph scc.
Definition TCT.h:303
void dumpCxt(CallStrCxt &cxt)
Dump calling context.
Definition TCT.cpp:541
const FunSet & getEntryProcs() const
Get marked candidate functions.
Definition TCT.h:239
virtual void pushCxt(CallStrCxt &cxt, const CallICFGNode *call, const FunObjVar *callee)
Context helper functions.
Definition TCT.cpp:473
bool isTDRelease(const CallICFGNode *inst) const
Return true if this call release a lock.
bool isTDAcquire(const CallICFGNode *inst) const
Return true if this call acquire a lock.
ThreadAPI * getThreadAPI() const
Thread API.
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:441
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:70
unsigned CallSiteID
Definition GeneralType.h:78
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
std::vector< u32_t > CallStrCxt
Definition GeneralType.h:96