Static Value-Flow Analysis
Loading...
Searching...
No Matches
LockAnalysis.h
Go to the documentation of this file.
1//===- LockAnalysis.h -- 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 * LockAnalysis.h
25 *
26 * Created on: 26 Aug 2015
27 * Author: pengd
28 *
29 * Lock analysis. One implementation runs on the whole program or a slice:
30 * analyze() is templated on the graph handle (SVFIR* or const SlicedSVFIRView*),
31 * as used by "Multi-Stage On-Demand Program Slicing for Modular Analysis of
32 * Multi-Threaded Programs" (ISSTA 2026).
33 */
34
35#ifndef INCLUDE_MTA_LockAnalysis_H_
36#define INCLUDE_MTA_LockAnalysis_H_
37
41#include "MTA/TCT.h"
42
43#include <memory>
44#include <vector>
45
46namespace SVF
47{
48
49// Forward declaration for the sliced-graph handle analyze() can run on.
50class SlicedSVFIRView;
51
56{
57
58public:
61 {
62 Empty, // initial(dummy) state
63 TDLocked, // stmt is locked
64 TDUnlocked, // stmt is unlocked
65 };
66
69
70 typedef NodeBS LockSet;
73 typedef InstSet CISpan;
82
90
94
95 ~LockAnalysis() = default;
96
103 template<class ICFGGraph, class CGGraph> void analyze(ICFGGraph icfg, CGGraph cg);
104 template<class ICFGGraph, class CGGraph> void analyzeIntraProcedualLock(ICFGGraph icfg, CGGraph cg);
105 template<class ICFGGraph, class CGGraph> bool intraForwardTraverse(ICFGGraph icfg, CGGraph cg, const ICFGNode* lock, InstSet& unlockset, InstSet& forwardInsts);
106 template<class ICFGGraph, class CGGraph> bool intraBackwardTraverse(ICFGGraph icfg, CGGraph cg, const InstSet& unlockset, InstSet& backwardInsts);
107
108 template<class ICFGGraph, class CGGraph> void collectCxtLock(ICFGGraph icfg, CGGraph cg);
109 template<class ICFGGraph, class CGGraph> void analyzeLockSpanCxtStmt(ICFGGraph icfg, CGGraph cg);
110
111 template<class ICFGGraph, class CGGraph> void collectLockUnlocksites(ICFGGraph icfg, CGGraph cg);
113
115
116
117 inline bool isIntraLock(const ICFGNode* lock) const
118 {
119 assert(locksites.find(lock)!=locksites.end() && "not a lock site?");
120 return ciLocktoSpan.find(lock)!=ciLocktoSpan.end();
121 }
122
124 inline void addIntraLock(const ICFGNode* lockSite, const InstSet& stmts)
125 {
126 for(InstSet::const_iterator it = stmts.begin(), eit = stmts.end(); it!=eit; ++it)
127 {
128 instCILocksMap[*it].insert(lockSite);
129 ciLocktoSpan[lockSite].insert(*it);
130 }
131 }
132
134 inline void addCondIntraLock(const ICFGNode* lockSite, const InstSet& stmts)
135 {
136 for(InstSet::const_iterator it = stmts.begin(), eit = stmts.end(); it!=eit; ++it)
137 {
138 instTocondCILocksMap[*it].insert(lockSite);
139 }
140 }
141
143 inline bool isInsideIntraLock(const ICFGNode* stmt) const
144 {
145 return instCILocksMap.find(stmt)!=instCILocksMap.end() || isInsideCondIntraLock(stmt);
146 }
147
149 inline bool isInsideCondIntraLock(const ICFGNode* stmt) const
150 {
151 return instTocondCILocksMap.find(stmt)!=instTocondCILocksMap.end();
152 }
153
157 inline bool hasIntraLockSet(const ICFGNode* stmt) const
158 {
159 return instCILocksMap.find(stmt)!=instCILocksMap.end();
160 }
161
162 inline const InstSet& getIntraLockSet(const ICFGNode* stmt) const
163 {
164 InstToInstSetMap::const_iterator it = instCILocksMap.find(stmt);
165 assert(it!=instCILocksMap.end() && "intralock not found!");
166 return it->second;
167 }
169
171
172
173 inline void addCxtLock(const CallStrCxt& cxt,const ICFGNode* inst)
174 {
175 CxtLock cxtlock(cxt,inst);
176 cxtLockset.insert(cxtlock);
177 DBOUT(DMTA, SVFUtil::outs() << "LockAnalysis Process new lock "; cxtlock.dump());
178 }
179
181 inline bool hasCxtLock(const CxtLock& cxtLock) const
182 {
183 return cxtLockset.find(cxtLock)!=cxtLockset.end();
184 }
185
187 inline bool intersects(const CxtLockSet& lockset1,const CxtLockSet& lockset2) const
188 {
189 for(CxtLockSet::const_iterator it = lockset1.begin(), eit = lockset1.end(); it!=eit; ++it)
190 {
191 const CxtLock& lock = *it;
192 for(CxtLockSet::const_iterator lit = lockset2.begin(), elit = lockset2.end(); lit!=elit; ++lit)
193 {
194 if(lock==*lit)
195 return true;
196 }
197 }
198 return false;
199 }
201 inline bool alias(const CxtLockSet& lockset1,const CxtLockSet& lockset2)
202 {
203 for(CxtLockSet::const_iterator it = lockset1.begin(), eit = lockset1.end(); it!=eit; ++it)
204 {
205 const CxtLock& lock = *it;
206 for(CxtLockSet::const_iterator lit = lockset2.begin(), elit = lockset2.end(); lit!=elit; ++lit)
207 {
209 return true;
210 }
211 }
212 return false;
213 }
215
217 inline bool isLockCandidateFun(const FunObjVar* fun) const
218 {
219 return lockcandidateFuncSet.find(fun)!=lockcandidateFuncSet.end();
220 }
221
223
224
225 inline bool hasCxtStmtFromInst(const ICFGNode* inst) const
226 {
227 InstToCxtStmtSet::const_iterator it = instToCxtStmtSet.find(inst);
228 return (it != instToCxtStmtSet.end());
229 }
230 inline const CxtStmtSet& getCxtStmtsFromInst(const ICFGNode* inst) const
231 {
232 InstToCxtStmtSet::const_iterator it = instToCxtStmtSet.find(inst);
233 assert(it != instToCxtStmtSet.end());
234 return it->second;
235 }
236 inline bool hasCxtLockfromCxtStmt(const CxtStmt& cts) const
237 {
238 CxtStmtToCxtLockSet::const_iterator it = cxtStmtToCxtLockSet.find(cts);
239 return (it != cxtStmtToCxtLockSet.end());
240 }
241 inline const CxtLockSet& getCxtLockfromCxtStmt(const CxtStmt& cts) const
242 {
243 CxtStmtToCxtLockSet::const_iterator it = cxtStmtToCxtLockSet.find(cts);
244 assert(it != cxtStmtToCxtLockSet.end());
245 return it->second;
246 }
248 {
249 CxtStmtToCxtLockSet::iterator it = cxtStmtToCxtLockSet.find(cts);
250 assert(it != cxtStmtToCxtLockSet.end());
251 return it->second;
252 }
254 inline bool addCxtStmtToSpan(const CxtStmt& cts, const CxtLock& cl)
255 {
256 cxtLocktoSpan[cl].insert(cts);
257 return cxtStmtToCxtLockSet[cts].insert(cl).second;
258 }
261 {
262 bool find = cxtStmtToCxtLockSet[cts].find(cl)!=cxtStmtToCxtLockSet[cts].end();
263 if(find)
264 {
265 cxtStmtToCxtLockSet[cts].erase(cl);
266 cxtLocktoSpan[cl].erase(cts);
267 }
268 return find;
269 }
270
277 {
279 }
280 inline bool hasSpanfromCxtLock(const CxtLock& cl)
281 {
282 return cxtLocktoSpan.find(cl) != cxtLocktoSpan.end();
283 }
285 {
286 assert(cxtLocktoSpan.find(cl) != cxtLocktoSpan.end());
287 return cxtLocktoSpan[cl];
288 }
290
292 inline bool hasOneCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
293 {
294 if(!hasCxtStmtFromInst(I))
295 return false;
297 for (LockSpan::const_iterator cts = ctsset.begin(), ects = ctsset.end(); cts != ects; cts++)
298 {
299 if(lspan.find(*cts) != lspan.end())
300 {
301 return true;
302 }
303 }
304 return false;
305 }
306
307 inline bool hasAllCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
308 {
309 if(!hasCxtStmtFromInst(I))
310 return false;
312 for (LockSpan::const_iterator cts = ctsset.begin(), ects = ctsset.end(); cts != ects; cts++)
313 {
314 if (lspan.find(*cts) == lspan.end())
315 {
316 return false;
317 }
318 }
319 return true;
320 }
321
325 bool isProtectedByCommonLock(const ICFGNode *i1, const ICFGNode *i2);
326 bool isProtectedByCommonCxtLock(const ICFGNode *i1, const ICFGNode *i2);
328 bool isProtectedByCommonCILock(const ICFGNode *i1, const ICFGNode *i2);
329
330 bool isInSameSpan(const ICFGNode *I1, const ICFGNode *I2);
331 bool isInSameCSSpan(const ICFGNode *i1, const ICFGNode *i2) const;
332 bool isInSameCSSpan(const CxtStmt& cxtStmt1, const CxtStmt& cxtStmt2) const;
333 bool isInSameCISpan(const ICFGNode *i1, const ICFGNode *i2) const;
334
336 {
337 return cxtLockset.size();
338 }
340 void printLocks(const CxtStmt& cts);
341
344 {
345 return tct;
346 }
347protected:
349 template<class ICFGGraph, class CGGraph> void handleFork(ICFGGraph icfg, CGGraph cg, const CxtStmt& cts);
350
352 template<class ICFGGraph, class CGGraph> void handleCall(ICFGGraph icfg, CGGraph cg, const CxtStmt& cts);
353
355 template<class ICFGGraph, class CGGraph> void handleRet(ICFGGraph icfg, CGGraph cg, const CxtStmt& cts);
356
358 template<class ICFGGraph, class CGGraph> void handleIntra(ICFGGraph icfg, CGGraph cg, const CxtStmt& cts);
359
361 template<class ICFGGraph, class CGGraph> void handleCallRelation(ICFGGraph icfg, CGGraph cg, CxtLockProc& clp, const CallGraphEdge* cgEdge, const CallICFGNode* call);
362
364 bool isAliasedLocks(const CxtLock& cl1, const CxtLock& cl2)
365 {
366 return isAliasedLocks(cl1.getStmt(), cl2.getStmt());
367 }
368 bool isAliasedLocks(const ICFGNode* i1, const ICFGNode* i2);
369
371
372
373 void markCxtStmtFlag(const CxtStmt& tgr, const CxtStmt& src)
374 {
376 if(hasCxtLockfromCxtStmt(tgr)== false)
377 {
378 for(CxtLockSet::const_iterator it = srclockset.begin(), eit = srclockset.end(); it!=eit; ++it)
379 {
381 }
383 }
384 else
385 {
388 }
389 }
391 {
393 for(CxtLockSet::const_iterator it = tgrlockset.begin(), eit = tgrlockset.end(); it!=eit; ++it)
394 {
395 if(srclockset.find(*it)==srclockset.end())
396 toBeDeleted.insert(*it);
397 }
398 for(CxtLockSet::const_iterator it = toBeDeleted.begin(), eit = toBeDeleted.end(); it!=eit; ++it)
399 {
400 tgrlockset.erase(*it);
401 }
402 return !toBeDeleted.empty();
403 }
404
406 inline void clearFlagMap()
407 {
409 }
411
413
415 {
416 if (isVisitedCTPs(clp) == false)
417 {
418 visitedCTPs.insert(clp);
419 return clpList.push(clp);
420 }
421 return false;
422 }
424 {
426 return clp;
427 }
428 inline bool isVisitedCTPs(const CxtLockProc& clp) const
429 {
430 return visitedCTPs.find(clp) != visitedCTPs.end();
431 }
433
435
436 inline bool pushToCTSWorkList(const CxtStmt& cs)
437 {
438 return cxtStmtList.push(cs);
439 }
441 {
443 return clp;
444 }
446
448
449
450 void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
452 bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
454 bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt& call);
456
458 inline bool isTDFork(const ICFGNode* call)
459 {
460 if(SVFUtil::isa<CallICFGNode>(call) == false)
461 return false;
462 return getTCG()->getThreadAPI()->isTDFork(SVFUtil::cast<CallICFGNode>(call));
463 }
465 inline bool isTDAcquire(const ICFGNode* call)
466 {
467 if(SVFUtil::isa<CallICFGNode>(call) == false)
468 return false;
469 return getTCG()->getThreadAPI()->isTDAcquire(SVFUtil::cast<CallICFGNode>(call));
470 }
472 inline bool isTDRelease(const ICFGNode* call)
473 {
474 if(SVFUtil::isa<CallICFGNode>(call) == false)
475 return false;
476 return getTCG()->getThreadAPI()->isTDRelease(SVFUtil::cast<CallICFGNode>(call));
477 }
479 inline bool isCallSite(const ICFGNode* inst)
480 {
481 return tct->isCallSite(inst);
482 }
484 inline bool isExtCall(const ICFGNode* inst)
485 {
486 return tct->isExtCall(inst);
487 }
489 inline const SVFVar* getLockVal(const ICFGNode* call)
490 {
491 return getTCG()->getThreadAPI()->getLockVal(call);
492 }
494 inline ThreadCallGraph* getTCG() const
495 {
496 return tct->getThreadCallGraph();
497 }
498
501
504
507
510
513
517
519
523
525
529
531
534
536
541
542public:
543 double lockTime;
547};
548
549} // End namespace SVF
550
551#endif /* INCLUDE_MTA_LockAnalysis_H_ */
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition SVFType.h:576
#define DMTA
Definition SVFType.h:597
bool push(const Data &data)
Definition WorkList.h:180
FIFOWorkList< CxtLockProc > CxtLockProcVec
Set< CxtLock > CxtLockSet
void analyze(ICFGGraph icfg, CGGraph cg)
Set< CxtStmt > LockSpan
bool hasIntraLockSet(const ICFGNode *stmt) const
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()
InstToInstSetMap instCILocksMap
CxtLockToSpan cxtLocktoSpan
CxtLockSet cxtLockset
Context-sensitive locks.
bool hasOneCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
Check if one instruction's context stmt is in a lock span.
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)
bool isIntraLock(const ICFGNode *lock) const
Intraprocedural locks.
TCT * getTCT()
Get tct.
Set< CxtStmt > CxtStmtSet
bool alias(const CxtLockSet &lockset1, const CxtLockSet &lockset2)
Return true if two locksets has at least one alias lock.
Map< CxtStmt, ValDomain > CxtStmtToLockFlagMap
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.
InstToInstSetMap instTocondCILocksMap
bool isInsideCondIntraLock(const ICFGNode *stmt) const
Return true if a statement is inside a partial lock/unlock pair (conditional lock with unconditional ...
CxtLockSet & getCxtLockfromCxtStmt(const CxtStmt &cts)
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.
Map< CxtStmt, CxtLockSet > CxtStmtToCxtLockSet
bool isTDRelease(const ICFGNode *call)
Whether it is a unlock site.
bool addCxtStmtToSpan(const CxtStmt &cts, const CxtLock &cl)
Add context-sensitive statement.
Map< CxtLock, LockSpan > CxtLockToSpan
Set< CxtLockProc > CxtLockProcSet
bool isTDFork(const ICFGNode *call)
Whether it is a lock site.
void handleRet(ICFGGraph icfg, CGGraph cg, const CxtStmt &cts)
Handle return.
CxtStmtToCxtLockSet getCSTCLS()
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.
Map< const ICFGNode *, CxtStmtSet > InstToCxtStmtSet
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.
CxtLockProcSet visitedCTPs
CxtLockProc List.
void touchCxtStmt(CxtStmt &cts)
Touch this context statement.
Set< const ICFGNode * > InstSet
bool hasAllCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
bool isLockCandidateFun(const FunObjVar *fun) const
Return true if it is a candidate function.
LockSpan & getSpanfromCxtLock(const CxtLock &cl)
Map< CxtLock, NodeBS > CxtLockToLockSet
~LockAnalysis()=default
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.
ValDomain
semilattice Empty==>TDUnlocked==>TDLocked
CxtLockProc popFromCTPWorkList()
bool matchCxt(CallStrCxt &cxt, const CallICFGNode *call, const FunObjVar *callee)
Match context.
Map< const ICFGNode *, InstSet > InstToInstSetMap
Set< const FunObjVar * > FunSet
void handleCallRelation(ICFGGraph icfg, CGGraph cg, CxtLockProc &clp, const CallGraphEdge *cgEdge, const CallICFGNode *call)
Handle call relations.
Map< const ICFGNode *, NodeBS > LockSiteToLockSet
const CxtStmtSet & getCxtStmtsFromInst(const ICFGNode *inst) const
Map< const ICFGNode *, CISpan > CILockToSpan
bool isInSameCISpan(const ICFGNode *i1, const ICFGNode *i2) const
bool isVisitedCTPs(const CxtLockProc &clp) const
void collectCxtLock(ICFGGraph icfg, CGGraph cg)
bool isAliasedLocks(const CxtLock &cl1, const CxtLock &cl2)
Return true it a lock matches an unlock.
void clearFlagMap()
Clear flags.
FIFOWorkList< CxtStmt > CxtStmtWorkList
CxtStmtToCxtLockSet cxtStmtToCxtLockSet
InstToCxtStmtSet instToCxtStmtSet
Map a statement to all its context-sensitive statements.
bool intersect(CxtLockSet &tgrlockset, const CxtLockSet &srclockset)
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.
bool hasSpanfromCxtLock(const CxtLock &cl)
CILockToSpan ciLocktoSpan
Used for context-insensitive intra-procedural locks.
CxtLockProcVec clpList
Following data structures are used for collecting context-sensitive locks.
bool isTDAcquire(const ICFGNode *call)
Whether it is a lock site.
bool isCallSite(const ICFGNode *inst)
Whether it is a callsite.
Definition TCT.h:268
ThreadCallGraph * getThreadCallGraph() const
Get TCG.
Definition TCT.h:193
std::vector< const ICFGNode * > InstVec
Definition TCT.h:173
bool isExtCall(const ICFGNode *inst)
Whether it is calling an external function.
Definition TCT.h:261
bool isTDFork(const CallICFGNode *inst) const
Return true if this call create a new thread.
bool isTDRelease(const CallICFGNode *inst) const
Return true if this call release a lock.
const SVFVar * getLockVal(const ICFGNode *inst) const
Return lock value.
bool isTDAcquire(const CallICFGNode *inst) const
Return true if this call acquire a lock.
ThreadAPI * getThreadAPI() const
Thread API.
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:70
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
std::vector< u32_t > CallStrCxt
Definition GeneralType.h:96
unsigned u32_t
Definition GeneralType.h:67