40 #include "llvm/ADT/ArrayRef.h"
41 #include "llvm/ADT/DenseMap.h"
42 #include "llvm/ADT/ImmutableMap.h"
43 #include "llvm/ADT/Optional.h"
44 #include "llvm/ADT/STLExtras.h"
45 #include "llvm/ADT/SmallVector.h"
46 #include "llvm/ADT/StringRef.h"
47 #include "llvm/Support/Allocator.h"
48 #include "llvm/Support/Casting.h"
49 #include "llvm/Support/ErrorHandling.h"
50 #include "llvm/Support/raw_ostream.h"
57 #include <type_traits>
61 using namespace clang;
62 using namespace threadSafety;
70 const Expr *DeclExp, StringRef
Kind) {
84 class CapExprSet :
public SmallVector<CapabilityExpr, 4> {
119 SourceKind Source : 8;
128 virtual ~FactEntry() =
default;
133 bool asserted()
const {
return Source == Asserted; }
134 bool declared()
const {
return Source == Declared; }
135 bool managed()
const {
return Source == Managed; }
138 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
141 virtual void handleLock(FactSet &FSet, FactManager &FactMan,
142 const FactEntry &entry,
144 virtual void handleUnlock(FactSet &FSet, FactManager &FactMan,
155 using FactID =
unsigned short;
161 std::vector<std::unique_ptr<const FactEntry>> Facts;
164 FactID newFact(std::unique_ptr<FactEntry> Entry) {
165 Facts.push_back(std::move(Entry));
166 return static_cast<unsigned short>(Facts.size() - 1);
169 const FactEntry &operator[](FactID F)
const {
return *Facts[F]; }
186 using iterator = FactVec::iterator;
187 using const_iterator = FactVec::const_iterator;
189 iterator begin() {
return FactIDs.begin(); }
190 const_iterator begin()
const {
return FactIDs.begin(); }
192 iterator end() {
return FactIDs.end(); }
193 const_iterator end()
const {
return FactIDs.end(); }
195 bool isEmpty()
const {
return FactIDs.size() == 0; }
198 bool isEmpty(FactManager &FactMan)
const {
199 for (
const auto FID : *
this) {
200 if (!FactMan[FID].negative())
206 void addLockByID(FactID
ID) { FactIDs.push_back(
ID); }
208 FactID addLock(FactManager &FM, std::unique_ptr<FactEntry> Entry) {
209 FactID F = FM.newFact(std::move(Entry));
210 FactIDs.push_back(F);
215 unsigned n = FactIDs.size();
219 for (
unsigned i = 0; i < n-1; ++i) {
220 if (FM[FactIDs[i]].
matches(CapE)) {
221 FactIDs[i] = FactIDs[n-1];
226 if (FM[FactIDs[n-1]].
matches(CapE)) {
233 iterator findLockIter(FactManager &FM,
const CapabilityExpr &CapE) {
234 return std::find_if(begin(), end(), [&](FactID
ID) {
235 return FM[
ID].matches(CapE);
239 const FactEntry *findLock(FactManager &FM,
const CapabilityExpr &CapE)
const {
240 auto I = std::find_if(begin(), end(), [&](FactID
ID) {
241 return FM[
ID].matches(CapE);
243 return I != end() ? &FM[*I] :
nullptr;
246 const FactEntry *findLockUniv(FactManager &FM,
248 auto I = std::find_if(begin(), end(), [&](FactID
ID) ->
bool {
249 return FM[
ID].matchesUniv(CapE);
251 return I != end() ? &FM[*I] :
nullptr;
254 const FactEntry *findPartialMatch(FactManager &FM,
256 auto I = std::find_if(begin(), end(), [&](FactID
ID) ->
bool {
257 return FM[
ID].partiallyMatches(CapE);
259 return I != end() ? &FM[*I] :
nullptr;
262 bool containsMutexDecl(FactManager &FM,
const ValueDecl* Vd)
const {
263 auto I = std::find_if(begin(), end(), [&](FactID
ID) ->
bool {
264 return FM[
ID].valueDecl() == Vd;
270 class ThreadSafetyAnalyzer;
275 namespace threadSafety {
285 BeforeInfo() =
default;
286 BeforeInfo(BeforeInfo &&) =
default;
290 llvm::DenseMap<const ValueDecl *, std::unique_ptr<BeforeInfo>>;
291 using CycleMap = llvm::DenseMap<const ValueDecl *, bool>;
296 BeforeInfo* insertAttrExprs(
const ValueDecl* Vd,
297 ThreadSafetyAnalyzer& Analyzer);
299 BeforeInfo *getBeforeInfoForDecl(
const ValueDecl *Vd,
300 ThreadSafetyAnalyzer &Analyzer);
302 void checkBeforeAfter(
const ValueDecl* Vd,
304 ThreadSafetyAnalyzer& Analyzer,
317 class LocalVariableMap;
319 using LocalVarContext = llvm::ImmutableMap<const NamedDecl *, unsigned>;
322 enum CFGBlockSide { CBS_Entry, CBS_Exit };
327 struct CFGBlockInfo {
335 LocalVarContext EntryContext;
338 LocalVarContext ExitContext;
350 bool Reachable =
false;
352 const FactSet &getSet(CFGBlockSide Side)
const {
353 return Side == CBS_Entry ? EntrySet : ExitSet;
357 return Side == CBS_Entry ? EntryLoc : ExitLoc;
361 CFGBlockInfo(LocalVarContext EmptyCtx)
362 : EntryContext(EmptyCtx), ExitContext(EmptyCtx) {}
365 static CFGBlockInfo getEmptyBlockInfo(LocalVariableMap &M);
381 class LocalVariableMap {
383 using Context = LocalVarContext;
389 struct VarDefinition {
391 friend class LocalVariableMap;
397 const Expr *Exp =
nullptr;
405 bool isReference() {
return !Exp; }
410 : Dec(D), Exp(E), Ctx(
C) {}
413 VarDefinition(
const NamedDecl *D,
unsigned R, Context
C)
414 : Dec(D), Ref(R), Ctx(
C) {}
418 Context::Factory ContextFactory;
419 std::vector<VarDefinition> VarDefinitions;
420 std::vector<std::pair<const Stmt *, Context>> SavedContexts;
425 VarDefinitions.push_back(VarDefinition(
nullptr, 0u, getEmptyContext()));
429 const VarDefinition* lookup(
const NamedDecl *D, Context Ctx) {
430 const unsigned *i = Ctx.lookup(D);
433 assert(*i < VarDefinitions.size());
434 return &VarDefinitions[*i];
441 const unsigned *
P = Ctx.lookup(D);
447 if (VarDefinitions[i].Exp) {
448 Ctx = VarDefinitions[i].Ctx;
449 return VarDefinitions[i].Exp;
451 i = VarDefinitions[i].Ref;
456 Context getEmptyContext() {
return ContextFactory.getEmptyMap(); }
461 Context getNextContext(
unsigned &CtxIndex,
const Stmt *S, Context
C) {
462 if (SavedContexts[CtxIndex+1].first == S) {
464 Context Result = SavedContexts[CtxIndex].second;
470 void dumpVarDefinitionName(
unsigned i) {
472 llvm::errs() <<
"Undefined";
475 const NamedDecl *Dec = VarDefinitions[i].Dec;
477 llvm::errs() <<
"<<NULL>>";
481 llvm::errs() <<
"." << i <<
" " << ((
const void*) Dec);
486 for (
unsigned i = 1, e = VarDefinitions.size(); i < e; ++i) {
487 const Expr *Exp = VarDefinitions[i].Exp;
488 unsigned Ref = VarDefinitions[i].Ref;
490 dumpVarDefinitionName(i);
491 llvm::errs() <<
" = ";
492 if (Exp) Exp->
dump();
494 dumpVarDefinitionName(Ref);
495 llvm::errs() <<
"\n";
501 void dumpContext(Context
C) {
502 for (Context::iterator I =
C.begin(), E =
C.end(); I != E; ++I) {
505 const unsigned *i =
C.lookup(D);
506 llvm::errs() <<
" -> ";
507 dumpVarDefinitionName(*i);
508 llvm::errs() <<
"\n";
514 std::vector<CFGBlockInfo> &BlockInfo);
517 friend class VarMapBuilder;
520 unsigned getContextIndex() {
return SavedContexts.size()-1; }
523 void saveContext(
const Stmt *S, Context
C) {
524 SavedContexts.push_back(std::make_pair(S,
C));
529 Context addDefinition(
const NamedDecl *D,
const Expr *Exp, Context Ctx) {
530 assert(!Ctx.contains(D));
531 unsigned newID = VarDefinitions.size();
532 Context NewCtx = ContextFactory.add(Ctx, D, newID);
533 VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
538 Context addReference(
const NamedDecl *D,
unsigned i, Context Ctx) {
539 unsigned newID = VarDefinitions.size();
540 Context NewCtx = ContextFactory.add(Ctx, D, newID);
541 VarDefinitions.push_back(VarDefinition(D, i, Ctx));
547 Context updateDefinition(
const NamedDecl *D,
Expr *Exp, Context Ctx) {
548 if (Ctx.contains(D)) {
549 unsigned newID = VarDefinitions.size();
550 Context NewCtx = ContextFactory.remove(Ctx, D);
551 NewCtx = ContextFactory.add(NewCtx, D, newID);
552 VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
560 Context clearDefinition(
const NamedDecl *D, Context Ctx) {
561 Context NewCtx = Ctx;
562 if (NewCtx.contains(D)) {
563 NewCtx = ContextFactory.remove(NewCtx, D);
564 NewCtx = ContextFactory.add(NewCtx, D, 0);
570 Context removeDefinition(
const NamedDecl *D, Context Ctx) {
571 Context NewCtx = Ctx;
572 if (NewCtx.contains(D)) {
573 NewCtx = ContextFactory.remove(NewCtx, D);
578 Context intersectContexts(Context C1, Context C2);
579 Context createReferenceContext(Context
C);
580 void intersectBackEdge(Context C1, Context C2);
586 CFGBlockInfo CFGBlockInfo::getEmptyBlockInfo(LocalVariableMap &M) {
587 return CFGBlockInfo(M.getEmptyContext());
595 LocalVariableMap* VMap;
596 LocalVariableMap::Context Ctx;
598 VarMapBuilder(LocalVariableMap *VM, LocalVariableMap::Context C)
599 : VMap(VM), Ctx(
C) {}
601 void VisitDeclStmt(
const DeclStmt *S);
608 void VarMapBuilder::VisitDeclStmt(
const DeclStmt *S) {
609 bool modifiedCtx =
false;
611 for (
const auto *D : DGrp) {
612 if (
const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
613 const Expr *E = VD->getInit();
618 Ctx = VMap->addDefinition(VD, E, Ctx);
624 VMap->saveContext(S, Ctx);
628 void VarMapBuilder::VisitBinaryOperator(
const BinaryOperator *BO) {
635 if (
const auto *DRE = dyn_cast<DeclRefExpr>(LHSExp)) {
637 if (Ctx.lookup(VDec)) {
639 Ctx = VMap->updateDefinition(VDec, BO->
getRHS(), Ctx);
642 Ctx = VMap->clearDefinition(VDec, Ctx);
643 VMap->saveContext(BO, Ctx);
651 LocalVariableMap::Context
652 LocalVariableMap::intersectContexts(Context C1, Context C2) {
654 for (
const auto &
P : C1) {
656 const unsigned *i2 = C2.lookup(Dec);
658 Result = removeDefinition(Dec, Result);
659 else if (*i2 !=
P.second)
660 Result = clearDefinition(Dec, Result);
668 LocalVariableMap::Context LocalVariableMap::createReferenceContext(Context C) {
669 Context Result = getEmptyContext();
670 for (
const auto &
P : C)
671 Result = addReference(
P.first,
P.second, Result);
678 void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
679 for (
const auto &
P : C1) {
680 unsigned i1 =
P.second;
681 VarDefinition *VDef = &VarDefinitions[i1];
682 assert(VDef->isReference());
684 const unsigned *i2 = C2.lookup(
P.first);
685 if (!i2 || (*i2 != i1))
727 void LocalVariableMap::traverseCFG(
CFG *CFGraph,
729 std::vector<CFGBlockInfo> &BlockInfo) {
732 for (
const auto *CurrBlock : *SortedGraph) {
733 unsigned CurrBlockID = CurrBlock->getBlockID();
734 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
736 VisitedBlocks.insert(CurrBlock);
739 bool HasBackEdges =
false;
742 PE = CurrBlock->pred_end(); PI != PE; ++PI) {
744 if (*PI ==
nullptr || !VisitedBlocks.alreadySet(*PI)) {
749 unsigned PrevBlockID = (*PI)->getBlockID();
750 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
753 CurrBlockInfo->EntryContext = PrevBlockInfo->ExitContext;
757 CurrBlockInfo->EntryContext =
758 intersectContexts(CurrBlockInfo->EntryContext,
759 PrevBlockInfo->ExitContext);
766 CurrBlockInfo->EntryContext =
767 createReferenceContext(CurrBlockInfo->EntryContext);
770 saveContext(
nullptr, CurrBlockInfo->EntryContext);
771 CurrBlockInfo->EntryIndex = getContextIndex();
774 VarMapBuilder VMapBuilder(
this, CurrBlockInfo->EntryContext);
775 for (
const auto &BI : *CurrBlock) {
776 switch (BI.getKind()) {
779 VMapBuilder.Visit(CS.
getStmt());
786 CurrBlockInfo->ExitContext = VMapBuilder.Ctx;
790 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
792 if (*SI ==
nullptr || !VisitedBlocks.alreadySet(*SI))
796 Context LoopBegin = BlockInfo[FirstLoopBlock->
getBlockID()].EntryContext;
797 Context LoopEnd = CurrBlockInfo->ExitContext;
798 intersectBackEdge(LoopBegin, LoopEnd);
804 saveContext(
nullptr, BlockInfo[exitID].ExitContext);
811 std::vector<CFGBlockInfo> &BlockInfo) {
812 for (
const auto *CurrBlock : *SortedGraph) {
813 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
817 if (
const Stmt *S = CurrBlock->getTerminatorStmt()) {
818 CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = S->getBeginLoc();
821 BE = CurrBlock->rend(); BI != BE; ++BI) {
824 CurrBlockInfo->ExitLoc = CS->getStmt()->getBeginLoc();
830 if (CurrBlockInfo->ExitLoc.isValid()) {
833 for (
const auto &BI : *CurrBlock) {
836 CurrBlockInfo->EntryLoc = CS->getStmt()->getBeginLoc();
840 }
else if (CurrBlock->pred_size() == 1 && *CurrBlock->pred_begin() &&
841 CurrBlock != &CFGraph->
getExit()) {
844 CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc =
845 BlockInfo[(*CurrBlock->pred_begin())->getBlockID()].ExitLoc;
846 }
else if (CurrBlock->succ_size() == 1 && *CurrBlock->succ_begin()) {
849 CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc =
850 BlockInfo[(*CurrBlock->succ_begin())->getBlockID()].EntryLoc;
857 class LockableFactEntry :
public FactEntry {
860 SourceKind Src = Acquired)
861 : FactEntry(CE, LK, Loc, Src) {}
864 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
867 if (!asserted() && !negative() && !isUniversal()) {
873 void handleLock(FactSet &FSet, FactManager &FactMan,
const FactEntry &entry,
879 void handleUnlock(FactSet &FSet, FactManager &FactMan,
883 FSet.removeLock(FactMan, Cp);
885 FSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
891 class ScopedLockableFactEntry :
public FactEntry {
893 enum UnderlyingCapabilityKind {
896 UCK_ReleasedExclusive,
899 struct UnderlyingCapability {
901 UnderlyingCapabilityKind
Kind;
911 UnderlyingMutexes.push_back(UnderlyingCapability{M, UCK_Acquired});
915 UnderlyingMutexes.push_back(UnderlyingCapability{M, UCK_ReleasedExclusive});
919 UnderlyingMutexes.push_back(UnderlyingCapability{M, UCK_ReleasedShared});
923 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
926 for (
const auto &UnderlyingMutex : UnderlyingMutexes) {
927 const auto *Entry = FSet.findLock(FactMan, UnderlyingMutex.Cap);
928 if ((UnderlyingMutex.Kind == UCK_Acquired && Entry) ||
929 (UnderlyingMutex.Kind != UCK_Acquired && !Entry)) {
933 UnderlyingMutex.Cap.toString(), loc(),
939 void handleLock(FactSet &FSet, FactManager &FactMan,
const FactEntry &entry,
941 for (
const auto &UnderlyingMutex : UnderlyingMutexes) {
942 if (UnderlyingMutex.Kind == UCK_Acquired)
943 lock(FSet, FactMan, UnderlyingMutex.Cap, entry.kind(), entry.loc(),
946 unlock(FSet, FactMan, UnderlyingMutex.Cap, entry.loc(), &Handler);
950 void handleUnlock(FactSet &FSet, FactManager &FactMan,
954 assert(!Cp.
negative() &&
"Managing object cannot be negative.");
955 for (
const auto &UnderlyingMutex : UnderlyingMutexes) {
959 if (UnderlyingMutex.Kind == UCK_Acquired) {
960 unlock(FSet, FactMan, UnderlyingMutex.Cap, UnlockLoc, TSHandler);
962 LockKind kind = UnderlyingMutex.Kind == UCK_ReleasedShared
965 lock(FSet, FactMan, UnderlyingMutex.Cap,
kind, UnlockLoc, TSHandler);
969 FSet.removeLock(FactMan, Cp);
973 void lock(FactSet &FSet, FactManager &FactMan,
const CapabilityExpr &Cp,
976 if (
const FactEntry *Fact = FSet.findLock(FactMan, Cp)) {
981 FSet.removeLock(FactMan, !Cp);
982 FSet.addLock(FactMan,
983 std::make_unique<LockableFactEntry>(Cp,
kind, loc, Managed));
987 void unlock(FactSet &FSet, FactManager &FactMan,
const CapabilityExpr &Cp,
989 if (FSet.findLock(FactMan, Cp)) {
990 FSet.removeLock(FactMan, Cp);
991 FSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
993 }
else if (Handler) {
995 if (
const FactEntry *Neg = FSet.findLock(FactMan, !Cp))
996 PrevLoc = Neg->loc();
1003 class ThreadSafetyAnalyzer {
1004 friend class BuildLockset;
1007 llvm::BumpPtrAllocator Bpa;
1013 LocalVariableMap LocalVarMap;
1014 FactManager FactMan;
1015 std::vector<CFGBlockInfo> BlockInfo;
1021 : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}
1025 void addLock(FactSet &FSet, std::unique_ptr<FactEntry> Entry,
1026 bool ReqAttr =
false);
1030 template <
typename AttrType>
1031 void getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
const Expr *Exp,
1034 template <
class AttrType>
1035 void getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
const Expr *Exp,
1038 Expr *BrE,
bool Neg);
1040 const CallExpr* getTrylockCallExpr(
const Stmt *Cond, LocalVarContext
C,
1043 void getEdgeLockset(FactSet &Result,
const FactSet &ExitSet,
1047 bool join(
const FactEntry &a,
const FactEntry &
b,
bool CanModify);
1049 void intersectAndWarn(FactSet &EntrySet,
const FactSet &ExitSet,
1053 void intersectAndWarn(FactSet &EntrySet,
const FactSet &ExitSet,
1055 intersectAndWarn(EntrySet, ExitSet, JoinLoc, LEK, LEK);
1065 ThreadSafetyAnalyzer& Analyzer) {
1067 BeforeInfo *Info =
nullptr;
1071 std::unique_ptr<BeforeInfo> &InfoPtr = BMap[Vd];
1073 InfoPtr.reset(
new BeforeInfo());
1074 Info = InfoPtr.get();
1077 for (
const auto *At : Vd->
attrs()) {
1078 switch (At->getKind()) {
1079 case attr::AcquiredBefore: {
1080 const auto *A = cast<AcquiredBeforeAttr>(At);
1083 for (
const auto *Arg : A->args()) {
1085 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
1087 Info->Vect.push_back(Cpvd);
1088 const auto It = BMap.find(Cpvd);
1089 if (It == BMap.end())
1095 case attr::AcquiredAfter: {
1096 const auto *A = cast<AcquiredAfterAttr>(At);
1099 for (
const auto *Arg : A->args()) {
1101 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
1105 ArgInfo->Vect.push_back(Vd);
1118 BeforeSet::BeforeInfo *
1120 ThreadSafetyAnalyzer &Analyzer) {
1121 auto It = BMap.find(Vd);
1122 BeforeInfo *Info =
nullptr;
1123 if (It == BMap.end())
1126 Info = It->second.get();
1127 assert(Info &&
"BMap contained nullptr?");
1133 const FactSet& FSet,
1134 ThreadSafetyAnalyzer& Analyzer,
1146 if (Info->Visited == 1)
1149 if (Info->Visited == 2)
1152 if (Info->Vect.empty())
1155 InfoVect.push_back(Info);
1157 for (
const auto *Vdb : Info->Vect) {
1159 if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {
1160 StringRef L1 = StartVd->
getName();
1161 StringRef L2 = Vdb->getName();
1162 Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc);
1166 if (CycMap.find(Vd) == CycMap.end()) {
1167 CycMap.insert(std::make_pair(Vd,
true));
1169 Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->
getLocation());
1179 for (
auto *Info : InfoVect)
1185 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))
1188 if (
const auto *DR = dyn_cast<DeclRefExpr>(Exp))
1189 return DR->getDecl();
1191 if (
const auto *ME = dyn_cast<MemberExpr>(Exp))
1192 return ME->getMemberDecl();
1199 template <
typename Ty>
1200 class has_arg_iterator_range {
1201 using yes =
char[1];
1204 template <
typename Inner>
1205 static yes& test(Inner *I, decltype(I->args()) * =
nullptr);
1208 static no& test(...);
1211 static const bool value =
sizeof(test<Ty>(
nullptr)) ==
sizeof(yes);
1216 bool ThreadSafetyAnalyzer::inCurrentScope(
const CapabilityExpr &CapE) {
1218 assert(SExp &&
"Null expressions should be ignored");
1220 if (
const auto *LP = dyn_cast<til::LiteralPtr>(SExp)) {
1233 if (
const auto *
P = dyn_cast<til::Project>(SExp)) {
1245 void ThreadSafetyAnalyzer::addLock(FactSet &FSet,
1246 std::unique_ptr<FactEntry> Entry,
1248 if (Entry->shouldIgnore())
1251 if (!ReqAttr && !Entry->negative()) {
1254 const FactEntry *Nen = FSet.findLock(FactMan, NegC);
1256 FSet.removeLock(FactMan, NegC);
1259 if (inCurrentScope(*Entry) && !Entry->asserted())
1267 !Entry->asserted() && !Entry->declared()) {
1268 GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *
this,
1269 Entry->loc(), Entry->getKind());
1273 if (
const FactEntry *Cp = FSet.findLock(FactMan, *Entry)) {
1274 if (!Entry->asserted())
1275 Cp->handleLock(FSet, FactMan, *Entry, Handler);
1277 FSet.addLock(FactMan, std::move(Entry));
1283 void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
const CapabilityExpr &Cp,
1285 bool FullyRemove,
LockKind ReceivedKind) {
1289 const FactEntry *LDat = FSet.findLock(FactMan, Cp);
1292 if (
const FactEntry *Neg = FSet.findLock(FactMan, !Cp))
1293 PrevLoc = Neg->loc();
1301 if (ReceivedKind !=
LK_Generic && LDat->kind() != ReceivedKind) {
1303 ReceivedKind, LDat->loc(), UnlockLoc);
1306 LDat->handleUnlock(FSet, FactMan, Cp, UnlockLoc, FullyRemove, Handler);
1311 template <
typename AttrType>
1312 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
1315 if (
Attr->args_size() == 0) {
1317 CapabilityExpr Cp = SxBuilder.translateAttrExpr(
nullptr, D, Exp, SelfDecl);
1324 Mtxs.push_back_nodup(Cp);
1328 for (
const auto *Arg :
Attr->args()) {
1329 CapabilityExpr Cp = SxBuilder.translateAttrExpr(Arg, D, Exp, SelfDecl);
1336 Mtxs.push_back_nodup(Cp);
1343 template <
class AttrType>
1344 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
1348 Expr *BrE,
bool Neg) {
1350 bool branch =
false;
1351 if (
const auto *BLE = dyn_cast_or_null<CXXBoolLiteralExpr>(BrE))
1352 branch = BLE->getValue();
1353 else if (
const auto *ILE = dyn_cast_or_null<IntegerLiteral>(BrE))
1354 branch = ILE->getValue().getBoolValue();
1356 int branchnum = branch ? 0 : 1;
1358 branchnum = !branchnum;
1363 SE = PredBlock->
succ_end(); SI != SE && i < 2; ++SI, ++i) {
1364 if (*SI == CurrBlock && i == branchnum)
1365 getMutexIDs(Mtxs,
Attr, Exp, D);
1370 if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) {
1373 }
else if (
const auto *BLE = dyn_cast<CXXBoolLiteralExpr>(E)) {
1374 TCond = BLE->getValue();
1376 }
else if (
const auto *ILE = dyn_cast<IntegerLiteral>(E)) {
1377 TCond = ILE->getValue().getBoolValue();
1379 }
else if (
auto *CE = dyn_cast<ImplicitCastExpr>(E))
1387 const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(
const Stmt *Cond,
1393 if (
const auto *CallExp = dyn_cast<CallExpr>(Cond)) {
1394 if (CallExp->getBuiltinCallee() == Builtin::BI__builtin_expect)
1395 return getTrylockCallExpr(CallExp->getArg(0), C, Negate);
1398 else if (
const auto *PE = dyn_cast<ParenExpr>(Cond))
1399 return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
1400 else if (
const auto *CE = dyn_cast<ImplicitCastExpr>(Cond))
1401 return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
1402 else if (
const auto *FE = dyn_cast<FullExpr>(Cond))
1403 return getTrylockCallExpr(FE->getSubExpr(), C, Negate);
1404 else if (
const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
1405 const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
1406 return getTrylockCallExpr(E, C, Negate);
1408 else if (
const auto *UOP = dyn_cast<UnaryOperator>(Cond)) {
1409 if (UOP->getOpcode() == UO_LNot) {
1411 return getTrylockCallExpr(UOP->getSubExpr(), C, Negate);
1415 else if (
const auto *BOP = dyn_cast<BinaryOperator>(Cond)) {
1416 if (BOP->getOpcode() == BO_EQ || BOP->getOpcode() == BO_NE) {
1417 if (BOP->getOpcode() == BO_NE)
1422 if (!TCond) Negate = !Negate;
1423 return getTrylockCallExpr(BOP->getLHS(), C, Negate);
1427 if (!TCond) Negate = !Negate;
1428 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1432 if (BOP->getOpcode() == BO_LAnd) {
1434 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1436 if (BOP->getOpcode() == BO_LOr)
1437 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1439 }
else if (
const auto *COP = dyn_cast<ConditionalOperator>(Cond)) {
1443 if (TCond && !FCond)
1444 return getTrylockCallExpr(COP->getCond(), C, Negate);
1445 if (!TCond && FCond) {
1447 return getTrylockCallExpr(COP->getCond(), C, Negate);
1457 void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
1458 const FactSet &ExitSet,
1468 bool Negate =
false;
1469 const CFGBlockInfo *PredBlockInfo = &BlockInfo[PredBlock->
getBlockID()];
1470 const LocalVarContext &LVarCtx = PredBlockInfo->ExitContext;
1472 const auto *Exp = getTrylockCallExpr(Cond, LVarCtx, Negate);
1476 auto *FunDecl = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
1477 if(!FunDecl || !FunDecl->hasAttrs())
1480 CapExprSet ExclusiveLocksToAdd;
1481 CapExprSet SharedLocksToAdd;
1484 for (
const auto *
Attr : FunDecl->attrs()) {
1486 case attr::TryAcquireCapability: {
1487 auto *A = cast<TryAcquireCapabilityAttr>(
Attr);
1488 getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
1489 Exp, FunDecl, PredBlock, CurrBlock, A->getSuccessValue(),
1493 case attr::ExclusiveTrylockFunction: {
1494 const auto *A = cast<ExclusiveTrylockFunctionAttr>(
Attr);
1495 getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock,
1496 A->getSuccessValue(), Negate);
1499 case attr::SharedTrylockFunction: {
1500 const auto *A = cast<SharedTrylockFunctionAttr>(
Attr);
1501 getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock,
1502 A->getSuccessValue(), Negate);
1512 for (
const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
1513 addLock(Result, std::make_unique<LockableFactEntry>(ExclusiveLockToAdd,
1515 for (
const auto &SharedLockToAdd : SharedLocksToAdd)
1516 addLock(Result, std::make_unique<LockableFactEntry>(SharedLockToAdd,
1528 friend class ThreadSafetyAnalyzer;
1530 ThreadSafetyAnalyzer *Analyzer;
1532 LocalVariableMap::Context LVarCtx;
1550 bool SkipFirstParam =
false);
1553 BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
1555 LVarCtx(Info.EntryContext), CtxIndex(Info.EntryIndex) {}
1559 void VisitCastExpr(
const CastExpr *CE);
1560 void VisitCallExpr(
const CallExpr *Exp);
1562 void VisitDeclStmt(
const DeclStmt *S);
1569 void BuildLockset::warnIfMutexNotHeld(
const NamedDecl *D,
const Expr *Exp,
1575 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1585 const FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
1587 Analyzer->Handler.handleFunExcludesLock(
1594 if (!Analyzer->inCurrentScope(Cp))
1598 LDat = FSet.findLock(Analyzer->FactMan, Cp);
1600 Analyzer->Handler.handleNegativeNotHeld(D, Cp.
toString(), Loc);
1605 const FactEntry *LDat = FSet.findLockUniv(Analyzer->FactMan, Cp);
1606 bool NoError =
true;
1609 LDat = FSet.findPartialMatch(Analyzer->FactMan, Cp);
1613 StringRef PartMatchName(PartMatchStr);
1614 Analyzer->Handler.handleMutexNotHeld(Cp.
getKind(), D, POK, Cp.
toString(),
1615 LK, Loc, &PartMatchName);
1618 Analyzer->Handler.handleMutexNotHeld(Cp.
getKind(), D, POK, Cp.
toString(),
1624 if (NoError && LDat && !LDat->isAtLeast(LK)) {
1625 Analyzer->Handler.handleMutexNotHeld(Cp.
getKind(), D, POK, Cp.
toString(),
1631 void BuildLockset::warnIfMutexHeld(
const NamedDecl *D,
const Expr *Exp,
1633 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1641 const FactEntry *LDat = FSet.findLock(Analyzer->FactMan, Cp);
1661 while (
const auto *DRE = dyn_cast<DeclRefExpr>(Exp)) {
1662 const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()->getCanonicalDecl());
1664 if (
const auto *E = VD->getInit()) {
1675 if (
const auto *UO = dyn_cast<UnaryOperator>(Exp)) {
1677 if (UO->getOpcode() == UO_Deref)
1678 checkPtAccess(UO->getSubExpr(), AK, POK);
1682 if (
const auto *AE = dyn_cast<ArraySubscriptExpr>(Exp)) {
1683 checkPtAccess(AE->getLHS(), AK, POK);
1687 if (
const auto *ME = dyn_cast<MemberExpr>(Exp)) {
1689 checkPtAccess(ME->getBase(), AK, POK);
1691 checkAccess(ME->getBase(), AK, POK);
1698 if (D->
hasAttr<GuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan)) {
1699 Analyzer->Handler.handleNoMutexHeld(D, POK, AK, Loc);
1703 warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK, Loc);
1711 if (
const auto *PE = dyn_cast<ParenExpr>(Exp)) {
1712 Exp = PE->getSubExpr();
1715 if (
const auto *CE = dyn_cast<CastExpr>(Exp)) {
1716 if (CE->getCastKind() == CK_ArrayToPointerDecay) {
1719 checkAccess(CE->getSubExpr(), AK, POK);
1722 Exp = CE->getSubExpr();
1736 if (D->
hasAttr<PtGuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan))
1737 Analyzer->Handler.handleNoMutexHeld(D, PtPOK, AK, Exp->
getExprLoc());
1740 warnIfMutexNotHeld(D, Exp, AK, I->getArg(), PtPOK, Exp->
getExprLoc());
1753 void BuildLockset::handleCall(
const Expr *Exp,
const NamedDecl *D,
1756 CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
1757 CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
1758 CapExprSet ScopedReqsAndExcludes;
1761 bool isScopedVar =
false;
1763 if (
const auto *CD = dyn_cast<const CXXConstructorDecl>(D)) {
1765 if (PD && PD->
hasAttr<ScopedLockableAttr>())
1771 switch (At->getKind()) {
1774 case attr::AcquireCapability: {
1775 const auto *A = cast<AcquireCapabilityAttr>(At);
1776 Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd
1777 : ExclusiveLocksToAdd,
1785 case attr::AssertExclusiveLock: {
1786 const auto *A = cast<AssertExclusiveLockAttr>(At);
1788 CapExprSet AssertLocks;
1789 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1790 for (
const auto &AssertLock : AssertLocks)
1792 FSet, std::make_unique<LockableFactEntry>(
1796 case attr::AssertSharedLock: {
1797 const auto *A = cast<AssertSharedLockAttr>(At);
1799 CapExprSet AssertLocks;
1800 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1801 for (
const auto &AssertLock : AssertLocks)
1803 FSet, std::make_unique<LockableFactEntry>(
1804 AssertLock,
LK_Shared, Loc, FactEntry::Asserted));
1808 case attr::AssertCapability: {
1809 const auto *A = cast<AssertCapabilityAttr>(At);
1810 CapExprSet AssertLocks;
1811 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1812 for (
const auto &AssertLock : AssertLocks)
1813 Analyzer->addLock(FSet, std::make_unique<LockableFactEntry>(
1816 Loc, FactEntry::Asserted));
1822 case attr::ReleaseCapability: {
1823 const auto *A = cast<ReleaseCapabilityAttr>(At);
1825 Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, VD);
1826 else if (A->isShared())
1827 Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, VD);
1829 Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, VD);
1833 case attr::RequiresCapability: {
1834 const auto *A = cast<RequiresCapabilityAttr>(At);
1835 for (
auto *Arg : A->args()) {
1840 Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, VD);
1845 case attr::LocksExcluded: {
1846 const auto *A = cast<LocksExcludedAttr>(At);
1847 for (
auto *Arg : A->args()) {
1848 warnIfMutexHeld(D, Exp, Arg);
1851 Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, VD);
1864 bool Dtor = isa<CXXDestructorDecl>(D);
1865 for (
const auto &M : ExclusiveLocksToRemove)
1866 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Exclusive);
1867 for (
const auto &M : SharedLocksToRemove)
1868 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Shared);
1869 for (
const auto &M : GenericLocksToRemove)
1870 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Generic);
1873 FactEntry::SourceKind Source =
1874 isScopedVar ? FactEntry::Managed : FactEntry::Acquired;
1875 for (
const auto &M : ExclusiveLocksToAdd)
1876 Analyzer->addLock(FSet, std::make_unique<LockableFactEntry>(M,
LK_Exclusive,
1878 for (
const auto &M : SharedLocksToAdd)
1880 FSet, std::make_unique<LockableFactEntry>(M,
LK_Shared, Loc, Source));
1888 CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE,
nullptr);
1890 auto ScopedEntry = std::make_unique<ScopedLockableFactEntry>(Scp, MLoc);
1891 for (
const auto &M : ExclusiveLocksToAdd)
1892 ScopedEntry->addLock(M);
1893 for (
const auto &M : SharedLocksToAdd)
1894 ScopedEntry->addLock(M);
1895 for (
const auto &M : ScopedReqsAndExcludes)
1896 ScopedEntry->addLock(M);
1897 for (
const auto &M : ExclusiveLocksToRemove)
1898 ScopedEntry->addExclusiveUnlock(M);
1899 for (
const auto &M : SharedLocksToRemove)
1900 ScopedEntry->addSharedUnlock(M);
1901 Analyzer->addLock(FSet, std::move(ScopedEntry));
1908 void BuildLockset::VisitUnaryOperator(
const UnaryOperator *UO) {
1924 void BuildLockset::VisitBinaryOperator(
const BinaryOperator *BO) {
1929 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
1937 void BuildLockset::VisitCastExpr(
const CastExpr *CE) {
1943 void BuildLockset::examineArguments(
const FunctionDecl *FD,
1946 bool SkipFirstParam) {
1956 if (FD->
hasAttr<NoThreadSafetyAnalysisAttr>())
1960 auto Param = Params.begin();
1965 for (
auto Arg = ArgBegin; Param != Params.end() && Arg != ArgEnd;
1973 void BuildLockset::VisitCallExpr(
const CallExpr *Exp) {
1974 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(Exp)) {
1975 const auto *ME = dyn_cast<MemberExpr>(CE->getCallee());
1980 if (ME->isArrow()) {
1982 checkPtAccess(CE->getImplicitObjectArgument(),
AK_Read);
1985 checkAccess(CE->getImplicitObjectArgument(),
AK_Read);
1989 examineArguments(CE->getDirectCallee(), CE->arg_begin(), CE->arg_end());
1990 }
else if (
const auto *OE = dyn_cast<CXXOperatorCallExpr>(Exp)) {
1998 case OO_PercentEqual:
2002 case OO_LessLessEqual:
2003 case OO_GreaterGreaterEqual:
2004 checkAccess(OE->getArg(1),
AK_Read);
2014 if (!(OEop == OO_Star && OE->getNumArgs() > 1)) {
2016 checkPtAccess(OE->getArg(0),
AK_Read);
2021 const Expr *Obj = OE->getArg(0);
2027 examineArguments(FD, std::next(OE->arg_begin()), OE->arg_end(),
2028 !isa<CXXMethodDecl>(FD));
2036 auto *D = dyn_cast_or_null<NamedDecl>(Exp->
getCalleeDecl());
2059 for (
auto *Ctor : RD->
ctors()) {
2060 if (Ctor->isDeleted())
2062 if (Ctor->isMoveConstructor())
2074 CD,
true, Args,
false,
false,
false,
false,
2079 void BuildLockset::VisitDeclStmt(
const DeclStmt *S) {
2081 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
2083 for (
auto *D : S->getDeclGroup()) {
2084 if (
auto *VD = dyn_cast_or_null<VarDecl>(D)) {
2091 if (
auto *EWC = dyn_cast<ExprWithCleanups>(E))
2093 if (
auto *CE = dyn_cast<CastExpr>(E))
2098 if (
auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
2101 if (
const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
2102 const auto *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor());
2103 if (!CtorD || !CtorD->hasAttrs())
2105 handleCall(E, CtorD, VD);
2106 }
else if (isa<CallExpr>(E) && E->
isPRValue()) {
2113 if (!RD || !RD->hasAttr<ScopedLockableAttr>())
2129 bool ThreadSafetyAnalyzer::join(
const FactEntry &A,
const FactEntry &B,
2131 if (A.kind() != B.kind()) {
2134 if ((A.managed() || A.asserted()) && (B.managed() || B.asserted())) {
2136 bool ShouldTakeB = B.kind() ==
LK_Shared;
2137 if (CanModify || !ShouldTakeB)
2146 return CanModify && A.asserted() && !B.asserted();
2164 void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &EntrySet,
2165 const FactSet &ExitSet,
2169 FactSet EntrySetOrig = EntrySet;
2172 for (
const auto &Fact : ExitSet) {
2173 const FactEntry &ExitFact = FactMan[Fact];
2175 FactSet::iterator EntryIt = EntrySet.findLockIter(FactMan, ExitFact);
2176 if (EntryIt != EntrySet.end()) {
2177 if (join(FactMan[*EntryIt], ExitFact,
2180 }
else if (!ExitFact.managed()) {
2181 ExitFact.handleRemovalFromIntersection(ExitSet, FactMan, JoinLoc,
2187 for (
const auto &Fact : EntrySetOrig) {
2188 const FactEntry *EntryFact = &FactMan[Fact];
2189 const FactEntry *ExitFact = ExitSet.findLock(FactMan, *EntryFact);
2193 EntryFact->handleRemovalFromIntersection(EntrySetOrig, FactMan, JoinLoc,
2196 EntrySet.removeLock(FactMan, *EntryFact);
2210 if (isa<CXXThrowExpr>(S->getStmt()))
2225 if (!walker.
init(AC))
2233 const auto *CurrentFunction = dyn_cast<FunctionDecl>(D);
2234 CurrentMethod = dyn_cast<CXXMethodDecl>(D);
2236 if (D->
hasAttr<NoThreadSafetyAnalysisAttr>())
2243 if (isa<CXXConstructorDecl>(D))
2245 if (isa<CXXDestructorDecl>(D))
2251 CFGBlockInfo::getEmptyBlockInfo(LocalVarMap));
2263 LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
2268 CapExprSet ExclusiveLocksAcquired;
2269 CapExprSet SharedLocksAcquired;
2270 CapExprSet LocksReleased;
2277 FactSet &InitialLockset = BlockInfo[FirstBlock->
getBlockID()].EntrySet;
2279 CapExprSet ExclusiveLocksToAdd;
2280 CapExprSet SharedLocksToAdd;
2285 if (
const auto *A = dyn_cast<RequiresCapabilityAttr>(
Attr)) {
2286 getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
2288 }
else if (
const auto *A = dyn_cast<ReleaseCapabilityAttr>(
Attr)) {
2291 if (A->args_size() == 0)
2293 getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
2295 getMutexIDs(LocksReleased, A,
nullptr, D);
2296 }
else if (
const auto *A = dyn_cast<AcquireCapabilityAttr>(
Attr)) {
2297 if (A->args_size() == 0)
2299 getMutexIDs(A->isShared() ? SharedLocksAcquired
2300 : ExclusiveLocksAcquired,
2302 }
else if (isa<ExclusiveTrylockFunctionAttr>(
Attr)) {
2305 }
else if (isa<SharedTrylockFunctionAttr>(
Attr)) {
2308 }
else if (isa<TryAcquireCapabilityAttr>(
Attr)) {
2315 for (
const auto &Mu : ExclusiveLocksToAdd) {
2316 auto Entry = std::make_unique<LockableFactEntry>(Mu,
LK_Exclusive, Loc,
2317 FactEntry::Declared);
2318 addLock(InitialLockset, std::move(Entry),
true);
2320 for (
const auto &Mu : SharedLocksToAdd) {
2321 auto Entry = std::make_unique<LockableFactEntry>(Mu,
LK_Shared, Loc,
2322 FactEntry::Declared);
2323 addLock(InitialLockset, std::move(Entry),
true);
2327 for (
const auto *CurrBlock : *SortedGraph) {
2328 unsigned CurrBlockID = CurrBlock->
getBlockID();
2329 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
2332 VisitedBlocks.insert(CurrBlock);
2347 bool LocksetInitialized =
false;
2349 PE = CurrBlock->
pred_end(); PI != PE; ++PI) {
2351 if (*PI ==
nullptr || !VisitedBlocks.alreadySet(*PI))
2354 unsigned PrevBlockID = (*PI)->getBlockID();
2355 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
2362 CurrBlockInfo->Reachable =
true;
2364 FactSet PrevLockset;
2365 getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
2367 if (!LocksetInitialized) {
2368 CurrBlockInfo->EntrySet = PrevLockset;
2369 LocksetInitialized =
true;
2375 CurrBlockInfo->EntrySet, PrevLockset, CurrBlockInfo->EntryLoc,
2376 isa_and_nonnull<ContinueStmt>((*PI)->getTerminatorStmt())
2383 if (!CurrBlockInfo->Reachable)
2386 BuildLockset LocksetBuilder(
this, *CurrBlockInfo);
2389 for (
const auto &BI : *CurrBlock) {
2390 switch (BI.getKind()) {
2393 LocksetBuilder.Visit(CS.
getStmt());
2400 if (!DD->hasAttrs())
2408 LocksetBuilder.handleCall(&DRE, DD);
2415 CurrBlockInfo->ExitSet = LocksetBuilder.FSet;
2422 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
2424 if (*SI ==
nullptr || !VisitedBlocks.alreadySet(*SI))
2428 CFGBlockInfo *PreLoop = &BlockInfo[FirstLoopBlock->
getBlockID()];
2429 CFGBlockInfo *LoopEnd = &BlockInfo[CurrBlockID];
2430 intersectAndWarn(PreLoop->EntrySet, LoopEnd->ExitSet, PreLoop->EntryLoc,
2439 if (!Final->Reachable)
2443 FactSet ExpectedExitSet = Initial->EntrySet;
2449 for (
const auto &Lock : ExclusiveLocksAcquired)
2450 ExpectedExitSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
2452 for (
const auto &Lock : SharedLocksAcquired)
2453 ExpectedExitSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
2455 for (
const auto &Lock : LocksReleased)
2456 ExpectedExitSet.removeLock(FactMan, Lock);
2459 intersectAndWarn(ExpectedExitSet, Final->ExitSet, Final->ExitLoc,
2475 ThreadSafetyAnalyzer Analyzer(Handler, *BSet);
2476 Analyzer.runAnalysis(AC);
2490 llvm_unreachable(
"Unknown AccessKind");