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
30#include "Util/Options.h"
31#include "MTA/LockAnalysis.h"
32#include "MTA/MTA.h"
33#include "MTA/MTASlicer.h"
34#include "Util/SVFUtil.h"
35#include "Util/PTAStat.h"
37#include "SVFIR/SVFIR.h"
38#include "Graphs/SlicedGraphs.h"
39
40using namespace SVF;
41using namespace SVFUtil;
42
43
44
45template<class ICFGGraph, class CGGraph>
47{
50
51 DOTIMESTAT(double lockStart = PTAStat::getClk(true));
52
53 DBOUT(DGENERAL, outs() << "\tIntra-procedural LockAnalysis\n");
54 DBOUT(DMTA, outs() << "\tIntra-procedural LockAnalysis\n");
56
57 DBOUT(DGENERAL, outs() << "\tCollect context-sensitive locks\n");
58 DBOUT(DMTA, outs() << "\tCollect context-sensitive locks\n");
59 collectCxtLock(icfg, cg);
60
61 DBOUT(DGENERAL, outs() << "\tInter-procedural LockAnalysis\n");
62 DBOUT(DMTA, outs() << "\tInter-procedural LockAnalysis\n");
64
65 DOTIMESTAT(double lockEnd = PTAStat::getClk(true));
67}
68
69
73template<class ICFGGraph, class CGGraph>
75{
77
79 for (auto nodeIt = CGTraits::nodes_begin(cg),
80 nodeEnd = CGTraits::nodes_end(cg); nodeIt != nodeEnd; ++nodeIt)
81 {
82 const FunObjVar* F = CGTraits::getRawNode(*nodeIt)->getFunction();
83 for (auto it : *F)
84 {
85 const SVFBasicBlock* bb = it.second;
86 for (const ICFGNode* icfgNode : bb->getICFGNodeList())
87 {
89 continue;
90 if (isa<CallICFGNode>(icfgNode) && tcg->getThreadAPI()->isTDRelease(cast<CallICFGNode>(icfgNode)))
91 {
92 unlockSites.insert(icfgNode);
93 }
94 if (isa<CallICFGNode>(icfgNode) && tcg->getThreadAPI()->isTDAcquire(cast<CallICFGNode>(icfgNode)))
95 {
96 lockSites.insert(icfgNode);
97 }
98 }
99 }
100 }
101}
102
106template<class CGGraph>
108{
109
111
112 TCT::PTACGNodeSet visited;
114
115 for (InstSet::iterator it = lockSites.begin(), eit = lockSites.end(); it != eit; ++it)
116 {
117 const FunObjVar* fun=(*it)->getFun();
119 if (visited.find(cgnode) == visited.end())
120 {
121 worklist.push(cgnode);
122 visited.insert(cgnode);
123 }
124 }
125 for (InstSet::iterator it = unlockSites.begin(), eit = unlockSites.end(); it != eit; ++it)
126 {
127 const FunObjVar* fun = (*it)->getFun();
129 if (visited.find(cgnode) == visited.end())
130 {
131 worklist.push(cgnode);
132 visited.insert(cgnode);
133 }
134 }
135 while (!worklist.empty())
136 {
137 const CallGraphNode* node = worklist.pop();
138 lockCandidateFuncSet.insert(node->getFunction());
139 std::vector<const CallGraphEdge*> inEdges;
141 for (const CallGraphEdge* edge : inEdges)
142 {
143 const CallGraphNode* srcNode = edge->getSrcNode();
144 if (visited.find(srcNode) == visited.end())
145 {
146 visited.insert(srcNode);
147 worklist.push(srcNode);
148 }
149 }
150 }
151}
152
157template<class ICFGGraph>
159{
160
161 // Identify the protected Instructions.
162 for (InstSet::const_iterator it = lockSites.begin(), ie = lockSites.end(); it != ie; ++it)
163 {
164 const ICFGNode* lockSite = *it;
165 assert(isCallSite(lockSite) && "Lock acquire instruction must be a CallSite");
166
167 // Perform forward traversal
171
175 icfg, unlockSet, backwardInsts);
176
178 if(forward && backward)
180 else if(forward && !backward)
182 }
183}
184
188template<class ICFGGraph>
192{
193
194 const FunObjVar* svfFun = lockSite->getFun();
195
196 InstVec worklist;
197 worklist.push_back(lockSite);
198 while (!worklist.empty())
199 {
200 const ICFGNode *I = worklist.back();
201 worklist.pop_back();
202 const ICFGNode* exitInst =
204 if (exitInst == nullptr)
205 return false;
206 if(exitInst == I)
207 return false;
208
209 // Skip the visited Instructions.
210 if (forwardInsts.find(I)!=forwardInsts.end())
211 continue;
212 forwardInsts.insert(I);
213
214 if (isTDRelease(I) && isAliasedLocks(lockSite, I))
215 {
216 unlockSet.insert(I);
217 DBOUT(DMTA, outs() << "LockAnalysis ci lock -- " << lockSite->getSourceLoc()<<"\n");
218 DBOUT(DMTA, outs() << "LockAnalysis ci unlock -- " << I->getSourceLoc()<<"\n");
219 continue;
220 }
221
222 std::vector<const ICFGNode*> succ;
224 for (const ICFGNode* dst : succ)
225 {
226 if(dst->getFun() == I->getFun())
227 {
228 worklist.push_back(dst);
229 }
230 }
231 }
232
233 return true;
234}
235
236
240template<class ICFGGraph>
243{
244
245 InstVec worklist;
246 for(InstSet::const_iterator it = unlockSet.begin(), eit = unlockSet.end(); it!=eit; ++it)
247 {
248 const ICFGNode* unlockSite = *it;
250 worklist.push_back(*it);
251
252 while (!worklist.empty())
253 {
254 const ICFGNode *I = worklist.back();
255 worklist.pop_back();
256
257 if(entryInst == I)
258 return false;
259
260 // Skip the visited Instructions.
261 if (backwardInsts.find(I)!=backwardInsts.end())
262 continue;
263 backwardInsts.insert(I);
264
266 {
267 DBOUT(DMTA, outs() << "LockAnalysis ci lock -- " << I->getSourceLoc()<<"\n");
268 DBOUT(DMTA, outs() << "LockAnalysis ci unlock -- " << unlockSite->getSourceLoc()<<"\n");
269 continue;
270 }
271
272 std::vector<const ICFGNode*> pred;
274 for (const ICFGNode* src : pred)
275 {
276 if(src->getFun() == I->getFun())
277 {
278 worklist.push_back(src);
279 }
280 }
281 }
282 }
283
284 return true;
285}
286
287
288template<class ICFGGraph, class CGGraph>
290{
291 const TCT::FunSet& entryFuncSet = tct->getEntryProcs();
292 for (TCT::FunSet::const_iterator it = entryFuncSet.begin(), eit = entryFuncSet.end(); it != eit; ++it)
293 {
294 if (!isLockCandidateFun(*it))
295 continue;
296 CallStrCxt cxt;
297 CxtLockProc t(cxt, *it);
299 }
300
301 while (!clpList.empty())
302 {
304 CallGraphNode* cgNode = getTCG()->getCallGraphNode(clp.getProc());
305 if (!isLockCandidateFun(cgNode->getFunction()))
306 continue;
307
308 std::vector<const CallGraphEdge*> outEdges;
310 for (const CallGraphEdge* cgEdge : outEdges)
311 {
312 std::vector<const CallICFGNode*> directCalls;
314 cg, cgEdge, directCalls);
315 for (const CallICFGNode* callSite : directCalls)
316 {
317 DBOUT(DMTA,
318 outs() << "\nCollecting CxtLocks: handling direct call:" << *callSite << "\t" << cgEdge->getSrcNode()->getFunction()->getName()
319 << "-->" << cgEdge->getDstNode()->getFunction()->getName() << "\n");
321 }
322 std::vector<const CallICFGNode*> indirectCalls;
324 cg, cgEdge, indirectCalls);
325 for (const CallICFGNode* callSite : indirectCalls)
326 {
327 DBOUT(DMTA,
328 outs() << "\nCollecting CxtLocks: handling indirect call:" << *callSite << "\t"
329 << cgEdge->getSrcNode()->getFunction()->getName() << "-->" << cgEdge->getDstNode()->getFunction()->getName()
330 << "\n");
332 }
333 }
334 }
335}
336
337
341template<class ICFGGraph, class CGGraph>
343{
344
345 CallStrCxt cxt(clp.getContext());
346 const ICFGNode* curNode = cs;
348 return;
349 if (isTDAcquire(curNode))
350 {
351 addCxtLock(cxt,curNode);
352 return;
353 }
354 const FunObjVar* svfcallee = cgEdge->getDstNode()->getFunction();
355 pushCxt(cxt, SVFUtil::cast<CallICFGNode>(curNode), svfcallee);
356
359 {
360 DBOUT(DMTA, outs() << "LockAnalysis Process CallRet old clp --"; clp.dump());
361 DBOUT(DMTA, outs() << "LockAnalysis Process CallRet new clp --"; newclp.dump());
362 }
363
364}
365
367{
368 // Lock matching is conservative: may-alias lock objects are treated as the
369 // same lock, consistent with the existing MTA lock semantics.
370 return tct->getPTA()->alias(getLockVal(i1)->getId(), getLockVal(i2)->getId());
371}
372
373template<class ICFGGraph, class CGGraph>
375{
376
377 const TCT::FunSet& entryFuncSet = tct->getEntryProcs();
378 for (TCT::FunSet::const_iterator it = entryFuncSet.begin(), eit = entryFuncSet.end(); it != eit; ++it)
379 {
380 if (!isLockCandidateFun(*it))
381 continue;
382 CallStrCxt cxt;
385 continue;
388 }
389
390 while (!cxtStmtList.empty())
391 {
393
395 const ICFGNode* curInst = cts.getStmt();
397 continue;
398 const bool firstContextVisit = instToCxtStmtSet[curInst].insert(cts).second;
400 indexCallsiteContext(curInst, cts.getContext());
401 DBOUT(DMTA, outs() << "\nVisit cxtStmt: ");
402 DBOUT(DMTA, cts.dump());
403
404 DBOUT(DMTA, outs() << "\nIts cxt lock sets: ");
406
407 if (isTDFork(curInst))
408 {
409 handleFork(icfg, cg, cts);
410 }
411 else if (isTDAcquire(curInst))
412 {
413 // Context truncation can merge a path into a lock context that the
414 // call-graph pre-collection did not enumerate. The propagation is
415 // authoritative: register that reachable lock before constructing
416 // its span. Release builds already constructed the same span; this
417 // keeps the canonical lock registry consistent as well.
418 if (!hasCxtLock(cts))
419 addCxtLock(cts.getContext(), curInst);
421 handleIntra(icfg, cg, cts);
422 }
423 else if (isTDRelease(curInst))
424 {
426 handleIntra(icfg, cg, cts);
427 }
428 else if (isCallSite(curInst) && !isExtCall(curInst))
429 {
430 handleCall(icfg, cg, cts);
431 }
432 else if (SVFUtil::dyn_cast<FunExitICFGNode>(curInst))
433 {
434 handleRet(icfg, cg, cts);
435 }
436 else
437 {
438 handleIntra(icfg, cg, cts);
439 }
440
441 }
442
443}
444
445
450{
452 outs() << "\nlock sets size = " << lockset.size() << "\n";
453 for (CxtLockSet::const_iterator it = lockset.begin(), eit = lockset.end(); it != eit; ++it)
454 {
455 (*it).dump();
456 }
457}
458
459
460
462template<class ICFGGraph, class CGGraph>
464{
465 const CallStrCxt& curCxt = cts.getContext();
466 const CallICFGNode* call = SVFUtil::dyn_cast<CallICFGNode>(cts.getStmt());
468 std::vector<const CallGraphEdge*> outEdges;
470 for (const CallGraphEdge* edge : outEdges)
471 {
472 if (!SVFUtil::isa<ThreadForkEdge>(edge) ||
474 continue;
475 const FunObjVar* svfcallee = edge->getDstNode()->getFunction();
477 pushCxt(newCxt, call, svfcallee);
478 const ICFGNode* svfInst =
480 if (svfInst == nullptr)
481 continue;
484 }
485 handleIntra(icfg, cg, cts);
486}
487
489template<class ICFGGraph, class CGGraph>
491{
492
493 const CallStrCxt& curCxt = cts.getContext();
494 const CallICFGNode* call = SVFUtil::dyn_cast<CallICFGNode>(cts.getStmt());
496 std::vector<const CallGraphEdge*> outEdges;
498 for (const CallGraphEdge* edge : outEdges)
499 {
500 if (edge->getEdgeKind() != CallGraphEdge::CallRetEdge ||
502 continue;
503 const FunObjVar* svfcallee = edge->getDstNode()->getFunction();
505 continue;
507 pushCxt(newCxt, call, svfcallee);
508 const ICFGNode* svfInst =
510 if (svfInst == nullptr)
511 continue;
514
515 // Return-flow rendezvous (see MHP::handleCall): forward an already
516 // computed callee-exit lockset to this callsite's return site.
517 if (svfcallee->hasBasicBlock())
518 {
519 const ICFGNode* exitInst =
521 if (exitInst == nullptr)
522 continue;
525 {
526 const ICFGNode* retNode = call->getRetICFGNode();
528 {
531 }
532 }
533 }
534 }
535}
536
538 const CxtStmt& exitCxtStmt, const FunObjVar* callee,
539 const ICFGNode* callsite, const std::vector<const ICFGNode*>& successors)
540{
541 CallStrCxt callerCxt = exitCxtStmt.getContext();
542 const CallICFGNode* call = SVFUtil::cast<CallICFGNode>(callsite);
543 if (!matchCxt(callerCxt, call, callee))
544 return;
545
546 for (const ICFGNode* successor : successors)
547 {
548 if (successor->getFun() != callsite->getFun())
549 continue;
550
553 if (matchingContexts == nullptr)
554 continue;
555
557 {
560 }
561 }
562}
563
565template<class ICFGGraph, class CGGraph>
567{
568
569 const ICFGNode* curInst = cts.getStmt();
570 const FunObjVar* svffun = curInst->getFun();
572
573 std::vector<const ICFGNode*> succ;
575
576 std::vector<const CallGraphEdge*> inEdges;
578 for (const CallGraphEdge* edgeConst : inEdges)
579 {
580 if (SVFUtil::isa<ThreadForkEdge, ThreadJoinEdge>(edgeConst))
581 continue;
582 std::vector<const CallICFGNode*> directCalls;
584 cg, edgeConst, directCalls);
585 for (const CallICFGNode* callSite : directCalls)
587 cts, curFunNode->getFunction(), callSite, succ);
588
589 std::vector<const CallICFGNode*> indirectCalls;
591 cg, edgeConst, indirectCalls);
592 for (const CallICFGNode* callSite : indirectCalls)
594 cts, curFunNode->getFunction(), callSite, succ);
595 }
596}
597
599template<class ICFGGraph, class CGGraph>
601{
602
603 const ICFGNode* curInst = cts.getStmt();
604 const CallStrCxt& curCxt = cts.getContext();
605
606 std::vector<const ICFGNode*> succ;
608 for (const ICFGNode* dst : succ)
609 {
610 if(dst->getFun() == curInst->getFun())
611 {
612 CxtStmt newCts(curCxt, dst);
614 }
615 }
616}
617
619{
620 tct->pushCxt(cxt,call,callee);
621}
622
624{
625 const FunObjVar* svfcaller = call->getFun();
626 CallSiteID csId = getTCG()->getCallSiteID(call, callee);
627
628// /// handle calling context for candidate functions only
629// if (isLockCandidateFun(caller) == false)
630// return true;
631
633 if (cxt.empty())
634 return true;
635
636 if (tct->inSameCallGraphSCC(getTCG()->getCallGraphNode(svfcaller), getTCG()->getCallGraphNode(callee)) == false)
637 {
638 if (cxt.back() == csId)
639 cxt.pop_back();
640 else
641 return false;
642 DBOUT(DMTA, tct->dumpCxt(cxt));
643 }
644 return true;
645}
646
648{
649 return tct->isContextSuffix(lhs,call);
650}
651
652
669
674{
675
677 {
680 for (InstSet::const_iterator cil1 = lockset1.begin(), ecil1 = lockset1.end(); cil1!=ecil1; ++cil1)
681 {
682 for (InstSet::const_iterator cil2=lockset2.begin(), ecil2=lockset2.end(); cil2!=ecil2; ++cil2)
683 {
684 if (isAliasedLocks(*cil1, *cil2))
685 return true;
686 }
687 }
688 }
689 return false;
690}
691
703
708{
710 return false;
713 for (CxtStmtSet::const_iterator cts1 = ctsset1.begin(), ects1 = ctsset1.end(); cts1 != ects1; cts1++)
714 {
715 const CxtStmt& cxtStmt1 = *cts1;
716 for (CxtStmtSet::const_iterator cts2 = ctsset2.begin(), ects2 = ctsset2.end(); cts2 != ects2; cts2++)
717 {
718 const CxtStmt& cxtStmt2 = *cts2;
719 if(cxtStmt1==cxtStmt2)
720 {
721 // i1==i2 under the same context: a self-race between two dynamic
722 // instances of one statement (e.g. a thread forked in a loop).
723 // This is the ONLY pair the loop produces for such a query, so
724 // skipping it would fall through to the vacuous "protected" return
725 // below and drop a real race. The two instances are mutually
726 // excluded only if this context actually holds a (non-empty) lock.
728 return false;
729 continue;
730 }
732 return false;
733 }
734 }
735 return true;
736}
737
738
743{
744 DOTIMESTAT(double queryStart = PTAStat::getClk(true));
745
746 bool sameSpan = false;
749 else
751
752 DOTIMESTAT(double queryEnd = PTAStat::getClk(true));
754 return sameSpan;
755}
756
761{
763 {
766 for (InstSet::const_iterator cil1 = lockset1.begin(), ecil1 = lockset1.end(); cil1!=ecil1; ++cil1)
767 {
768 for (InstSet::const_iterator cil2=lockset2.begin(), ecil2=lockset2.end(); cil2!=ecil2; ++cil2)
769 {
770 if (*cil1==*cil2)
771 return true;
772 }
773 }
774 }
775 return false;
776}
777
793{
795 return false;
798
799 for (CxtStmtSet::const_iterator cts1 = ctsset1.begin(), ects1 = ctsset1.end(); cts1 != ects1; cts1++)
800 {
801 const CxtStmt& cxtStmt1 = *cts1;
802 for (CxtStmtSet::const_iterator cts2 = ctsset2.begin(), ects2 = ctsset2.end(); cts2 != ects2; cts2++)
803 {
804 const CxtStmt& cxtStmt2 = *cts2;
805 if(cxtStmt1==cxtStmt2) continue;
807 return false;
808 }
809 }
810 return true;
811}
812
813// The two graphs the lock analysis runs on; the algorithm above is written once
814// and instantiated for both (all internal templates instantiate transitively).
815template void LockAnalysis::analyze<ICFG*, CallGraph*>(ICFG*, CallGraph*);
816template 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
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
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 intraBackwardTraverse(ICFGGraph icfg, const InstSet &unlockSet, InstSet &backwardInsts)
bool isProtectedByCommonLock(const ICFGNode *i1, const ICFGNode *i2)
bool isInSameSpan(const ICFGNode *I1, const ICFGNode *I2)
void markCxtStmtFlag(const CxtStmt &tgr, const CxtStmt &src)
Mark thread flags for cxtStmt.
bool isExtCall(const ICFGNode *inst)
Whether it is calling an external function.
Set< CxtStmt > CxtStmtSet
void handleReturnAtCallsite(const CxtStmt &exitCxtStmt, const FunObjVar *callee, const ICFGNode *callsite, const std::vector< const ICFGNode * > &successors)
Propagate a callee-exit lock state to one matching callsite context.
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()
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.
void analyzeLockSpanCxtStmt(ICFGGraph icfg, CGGraph cg)
FunSet lockCandidateFuncSet
Candidate functions which relevant to locks/unlocks.
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 ...
Set< CallStrCxt > CallStrCxtSet
void pushCxt(CallStrCxt &cxt, const CallICFGNode *call, const FunObjVar *callee)
Context helper functions.
bool intraForwardTraverse(ICFGGraph icfg, const ICFGNode *lock, InstSet &unlockSet, InstSet &forwardInsts)
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.
InstSet lockSites
Record all visited clps.
bool isTDFork(const ICFGNode *call)
Whether it is a lock site.
void handleRet(ICFGGraph icfg, CGGraph cg, const CxtStmt &cts)
Handle return.
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.
const CxtLockSet & getCxtLockFromCxtStmt(const CxtStmt &cts) const
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
const CallStrCxtSet * getCallsiteContextsWithSuffix(const ICFGNode *inst, const CallStrCxt &suffix) const
bool isLockCandidateFun(const FunObjVar *fun) const
Return true if it is a candidate function.
void analyzeIntraProceduralLock(ICFGGraph icfg)
void buildCandidateFuncSetForLock(CGGraph cg)
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 collectLockUnlockSites(ICFGGraph icfg, CGGraph cg)
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.
bool hasCxtLockFromCxtStmt(const CxtStmt &cts) const
InstToCxtStmtSet instToCxtStmtSet
Map a statement to all its context-sensitive statements.
TCT::InstVec InstVec
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.
void indexCallsiteContext(const ICFGNode *inst, const CallStrCxt &cxt)
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:531
OrderedSet< const FunObjVar *, FunObjVarIdCmp > FunSet
Definition TCT.h:173
PointerAnalysis * getPTA() const
Get PTA.
Definition TCT.h:204
Set< const CallGraphNode * > PTACGNodeSet
Definition TCT.h:176
ThreadCallGraph * getThreadCallGraph() const
Get TCG.
Definition TCT.h:199
bool inSameCallGraphSCC(const CallGraphNode *src, const CallGraphNode *dst)
Whether two functions in the same callgraph scc.
Definition TCT.h:309
void dumpCxt(CallStrCxt &cxt)
Dump calling context.
Definition TCT.cpp:551
const FunSet & getEntryProcs() const
Get marked candidate functions.
Definition TCT.h:245
virtual void pushCxt(CallStrCxt &cxt, const CallICFGNode *call, const FunObjVar *callee)
Context helper functions.
Definition TCT.cpp:483
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