35 #include "llvm/ADT/BitVector.h"
36 #include "llvm/ADT/FoldingSet.h"
37 #include "llvm/ADT/ImmutableMap.h"
38 #include "llvm/ADT/PostOrderIterator.h"
39 #include "llvm/ADT/SmallVector.h"
40 #include "llvm/ADT/StringRef.h"
41 #include "llvm/Support/raw_ostream.h"
47 using namespace clang;
48 using namespace threadSafety;
61 const Expr *DeclExp, StringRef
Kind) {
73 class CapExprSet :
public SmallVector<CapabilityExpr, 4> {
106 bool Asrt,
bool Declrd =
false)
110 virtual ~FactEntry() {}
114 bool asserted()
const {
return Asserted; }
115 bool declared()
const {
return Declared; }
117 void setDeclared(
bool D) { Declared = D; }
120 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
123 virtual void handleUnlock(FactSet &FSet, FactManager &FactMan,
126 StringRef DiagKind)
const = 0;
135 typedef unsigned short FactID;
141 std::vector<std::unique_ptr<FactEntry>> Facts;
144 FactID newFact(std::unique_ptr<FactEntry> Entry) {
145 Facts.push_back(std::move(Entry));
146 return static_cast<unsigned short>(Facts.size() - 1);
149 const FactEntry &operator[](FactID F)
const {
return *Facts[F]; }
150 FactEntry &operator[](FactID F) {
return *Facts[F]; }
169 typedef FactVec::const_iterator const_iterator;
172 const_iterator
begin()
const {
return FactIDs.begin(); }
175 const_iterator
end()
const {
return FactIDs.end(); }
177 bool isEmpty()
const {
return FactIDs.size() == 0; }
180 bool isEmpty(FactManager &FactMan)
const {
181 for (FactID FID : *
this) {
182 if (!FactMan[FID].negative())
188 void addLockByID(FactID
ID) { FactIDs.push_back(ID); }
190 FactID addLock(FactManager &FM, std::unique_ptr<FactEntry> Entry) {
191 FactID F = FM.newFact(std::move(Entry));
192 FactIDs.push_back(F);
197 unsigned n = FactIDs.size();
201 for (
unsigned i = 0; i < n-1; ++i) {
202 if (FM[FactIDs[i]].
matches(CapE)) {
203 FactIDs[i] = FactIDs[n-1];
208 if (FM[FactIDs[n-1]].
matches(CapE)) {
216 return std::find_if(
begin(),
end(), [&](FactID ID) {
217 return FM[
ID].matches(CapE);
221 FactEntry *findLock(FactManager &FM,
const CapabilityExpr &CapE)
const {
222 auto I = std::find_if(
begin(),
end(), [&](FactID ID) {
223 return FM[
ID].matches(CapE);
225 return I !=
end() ? &FM[*
I] :
nullptr;
228 FactEntry *findLockUniv(FactManager &FM,
const CapabilityExpr &CapE)
const {
229 auto I = std::find_if(
begin(),
end(), [&](FactID ID) ->
bool {
230 return FM[
ID].matchesUniv(CapE);
232 return I !=
end() ? &FM[*
I] :
nullptr;
235 FactEntry *findPartialMatch(FactManager &FM,
237 auto I = std::find_if(
begin(),
end(), [&](FactID ID) ->
bool {
238 return FM[
ID].partiallyMatches(CapE);
240 return I !=
end() ? &FM[*
I] :
nullptr;
243 bool containsMutexDecl(FactManager &FM,
const ValueDecl* Vd)
const {
244 auto I = std::find_if(
begin(),
end(), [&](FactID ID) ->
bool {
245 return FM[
ID].valueDecl() == Vd;
251 class ThreadSafetyAnalyzer;
255 namespace threadSafety {
261 BeforeInfo() : Visited(0) {}
262 BeforeInfo(BeforeInfo &&O) : Vect(std::move(O.Vect)), Visited(O.Visited) {}
268 typedef llvm::DenseMap<const ValueDecl *, std::unique_ptr<BeforeInfo>>
270 typedef llvm::DenseMap<const ValueDecl*, bool> CycleMap;
275 BeforeInfo* insertAttrExprs(
const ValueDecl* Vd,
276 ThreadSafetyAnalyzer& Analyzer);
278 BeforeInfo *getBeforeInfoForDecl(
const ValueDecl *Vd,
279 ThreadSafetyAnalyzer &Analyzer);
281 void checkBeforeAfter(
const ValueDecl* Vd,
283 ThreadSafetyAnalyzer& Analyzer,
295 class LocalVariableMap;
303 struct CFGBlockInfo {
306 LocalVarContext EntryContext;
307 LocalVarContext ExitContext;
314 return Side == CBS_Entry ? EntrySet : ExitSet;
317 return Side == CBS_Entry ? EntryLoc : ExitLoc;
321 CFGBlockInfo(LocalVarContext EmptyCtx)
322 : EntryContext(EmptyCtx), ExitContext(EmptyCtx), Reachable(
false)
326 static CFGBlockInfo getEmptyBlockInfo(LocalVariableMap &M);
344 class LocalVariableMap {
346 typedef LocalVarContext
Context;
352 struct VarDefinition {
354 friend class LocalVariableMap;
361 bool isReference() {
return !Exp; }
366 : Dec(D), Exp(E), Ref(0), Ctx(C)
371 : Dec(D), Exp(nullptr), Ref(R), Ctx(C)
376 Context::Factory ContextFactory;
377 std::vector<VarDefinition> VarDefinitions;
378 std::vector<unsigned> CtxIndices;
379 std::vector<std::pair<Stmt*, Context> > SavedContexts;
384 VarDefinitions.push_back(VarDefinition(
nullptr, 0u, getEmptyContext()));
389 const unsigned *i = Ctx.lookup(D);
392 assert(*i < VarDefinitions.size());
393 return &VarDefinitions[*i];
400 const unsigned *
P = Ctx.lookup(D);
406 if (VarDefinitions[i].Exp) {
407 Ctx = VarDefinitions[i].Ctx;
408 return VarDefinitions[i].Exp;
410 i = VarDefinitions[i].Ref;
415 Context getEmptyContext() {
return ContextFactory.getEmptyMap(); }
421 if (SavedContexts[CtxIndex+1].first == S) {
429 void dumpVarDefinitionName(
unsigned i) {
431 llvm::errs() <<
"Undefined";
434 const NamedDecl *Dec = VarDefinitions[i].Dec;
436 llvm::errs() <<
"<<NULL>>";
440 llvm::errs() <<
"." << i <<
" " << ((
const void*) Dec);
445 for (
unsigned i = 1, e = VarDefinitions.size(); i < e; ++i) {
446 const Expr *Exp = VarDefinitions[i].Exp;
447 unsigned Ref = VarDefinitions[i].Ref;
449 dumpVarDefinitionName(i);
450 llvm::errs() <<
" = ";
451 if (Exp) Exp->dump();
453 dumpVarDefinitionName(Ref);
454 llvm::errs() <<
"\n";
464 const unsigned *i = C.lookup(D);
465 llvm::errs() <<
" -> ";
466 dumpVarDefinitionName(*i);
467 llvm::errs() <<
"\n";
473 std::vector<CFGBlockInfo> &BlockInfo);
477 unsigned getContextIndex() {
return SavedContexts.size()-1; }
481 SavedContexts.push_back(std::make_pair(S,C));
487 assert(!Ctx.contains(D));
488 unsigned newID = VarDefinitions.size();
489 Context NewCtx = ContextFactory.add(Ctx, D, newID);
490 VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
496 unsigned newID = VarDefinitions.size();
497 Context NewCtx = ContextFactory.add(Ctx, D, newID);
498 VarDefinitions.push_back(VarDefinition(D, i, Ctx));
505 if (Ctx.contains(D)) {
506 unsigned newID = VarDefinitions.size();
507 Context NewCtx = ContextFactory.remove(Ctx, D);
508 NewCtx = ContextFactory.add(NewCtx, D, newID);
509 VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
519 if (NewCtx.contains(D)) {
520 NewCtx = ContextFactory.remove(NewCtx, D);
521 NewCtx = ContextFactory.add(NewCtx, D, 0);
529 if (NewCtx.contains(D)) {
530 NewCtx = ContextFactory.remove(NewCtx, D);
539 friend class VarMapBuilder;
544 CFGBlockInfo CFGBlockInfo::getEmptyBlockInfo(LocalVariableMap &M) {
545 return CFGBlockInfo(M.getEmptyContext());
550 class VarMapBuilder :
public StmtVisitor<VarMapBuilder> {
552 LocalVariableMap* VMap;
553 LocalVariableMap::Context Ctx;
555 VarMapBuilder(LocalVariableMap *VM, LocalVariableMap::Context C)
556 : VMap(VM), Ctx(C) {}
564 void VarMapBuilder::VisitDeclStmt(
DeclStmt *S) {
565 bool modifiedCtx =
false;
567 for (
const auto *D : DGrp) {
568 if (
const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
569 const Expr *
E = VD->getInit();
574 Ctx = VMap->addDefinition(VD, E, Ctx);
580 VMap->saveContext(S, Ctx);
591 if (
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHSExp)) {
593 if (Ctx.lookup(VDec)) {
595 Ctx = VMap->updateDefinition(VDec, BO->
getRHS(), Ctx);
598 Ctx = VMap->clearDefinition(VDec, Ctx);
599 VMap->saveContext(BO, Ctx);
608 LocalVariableMap::Context
611 for (
const auto &P : C1) {
613 const unsigned *i2 = C2.lookup(Dec);
615 Result = removeDefinition(Dec, Result);
616 else if (*i2 != P.second)
617 Result = clearDefinition(Dec, Result);
625 LocalVariableMap::Context LocalVariableMap::createReferenceContext(
Context C) {
626 Context Result = getEmptyContext();
627 for (
const auto &P : C)
628 Result = addReference(P.first, P.second, Result);
635 void LocalVariableMap::intersectBackEdge(
Context C1,
Context C2) {
636 for (
const auto &P : C1) {
637 unsigned i1 = P.second;
638 VarDefinition *VDef = &VarDefinitions[i1];
639 assert(VDef->isReference());
641 const unsigned *i2 = C2.lookup(P.first);
642 if (!i2 || (*i2 != i1))
686 void LocalVariableMap::traverseCFG(
CFG *CFGraph,
688 std::vector<CFGBlockInfo> &BlockInfo) {
693 for (
const auto *CurrBlock : *SortedGraph) {
694 int CurrBlockID = CurrBlock->getBlockID();
695 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
697 VisitedBlocks.insert(CurrBlock);
700 bool HasBackEdges =
false;
703 PE = CurrBlock->pred_end(); PI != PE; ++PI) {
705 if (*PI ==
nullptr || !VisitedBlocks.alreadySet(*PI)) {
710 int PrevBlockID = (*PI)->getBlockID();
711 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
714 CurrBlockInfo->EntryContext = PrevBlockInfo->ExitContext;
718 CurrBlockInfo->EntryContext =
719 intersectContexts(CurrBlockInfo->EntryContext,
720 PrevBlockInfo->ExitContext);
727 CurrBlockInfo->EntryContext =
728 createReferenceContext(CurrBlockInfo->EntryContext);
731 saveContext(
nullptr, CurrBlockInfo->EntryContext);
732 CurrBlockInfo->EntryIndex = getContextIndex();
735 VarMapBuilder VMapBuilder(
this, CurrBlockInfo->EntryContext);
737 BE = CurrBlock->end(); BI != BE; ++BI) {
738 switch (BI->getKind()) {
741 VMapBuilder.Visit(const_cast<Stmt*>(CS.
getStmt()));
748 CurrBlockInfo->ExitContext = VMapBuilder.Ctx;
752 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
754 if (*SI ==
nullptr || !VisitedBlocks.alreadySet(*SI))
759 Context LoopEnd = CurrBlockInfo->ExitContext;
760 intersectBackEdge(LoopBegin, LoopEnd);
766 saveContext(
nullptr, BlockInfo[exitID].ExitContext);
771 static void findBlockLocations(
CFG *CFGraph,
773 std::vector<CFGBlockInfo> &BlockInfo) {
774 for (
const auto *CurrBlock : *SortedGraph) {
775 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
779 if (
const Stmt *S = CurrBlock->getTerminator()) {
780 CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = S->
getLocStart();
783 BE = CurrBlock->rend(); BI != BE; ++BI) {
786 CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart();
792 if (CurrBlockInfo->ExitLoc.isValid()) {
796 BE = CurrBlock->end(); BI != BE; ++BI) {
799 CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart();
803 }
else if (CurrBlock->pred_size() == 1 && *CurrBlock->pred_begin() &&
804 CurrBlock != &CFGraph->
getExit()) {
807 CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc =
808 BlockInfo[(*CurrBlock->pred_begin())->getBlockID()].ExitLoc;
813 class LockableFactEntry :
public FactEntry {
819 bool Mng =
false,
bool Asrt =
false)
820 : FactEntry(CE, LK, Loc, Asrt), Managed(Mng) {}
823 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
826 if (!Managed && !asserted() && !negative() && !isUniversal()) {
832 void handleUnlock(FactSet &FSet, FactManager &FactMan,
835 StringRef DiagKind)
const override {
836 FSet.removeLock(FactMan, Cp);
838 FSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
844 class ScopedLockableFactEntry :
public FactEntry {
850 const CapExprSet &Excl,
const CapExprSet &Shrd)
852 for (
const auto &M : Excl)
853 UnderlyingMutexes.push_back(M.sexpr());
854 for (
const auto &M : Shrd)
855 UnderlyingMutexes.push_back(M.sexpr());
859 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
862 for (
const til::SExpr *UnderlyingMutex : UnderlyingMutexes) {
863 if (FSet.findLock(FactMan,
CapabilityExpr(UnderlyingMutex,
false))) {
867 "mutex",
sx::toString(UnderlyingMutex), loc(), JoinLoc, LEK);
872 void handleUnlock(FactSet &FSet, FactManager &FactMan,
875 StringRef DiagKind)
const override {
876 assert(!Cp.
negative() &&
"Managing object cannot be negative.");
877 for (
const til::SExpr *UnderlyingMutex : UnderlyingMutexes) {
879 auto UnderEntry = llvm::make_unique<LockableFactEntry>(
885 if (FSet.findLock(FactMan, UnderCp)) {
886 FSet.removeLock(FactMan, UnderCp);
887 FSet.addLock(FactMan, std::move(UnderEntry));
892 if (!FSet.findLock(FactMan, UnderCp)) {
896 FSet.removeLock(FactMan, UnderCp);
897 FSet.addLock(FactMan, std::move(UnderEntry));
901 FSet.removeLock(FactMan, Cp);
906 class ThreadSafetyAnalyzer {
907 friend class BuildLockset;
910 llvm::BumpPtrAllocator Bpa;
916 LocalVariableMap LocalVarMap;
918 std::vector<CFGBlockInfo> BlockInfo;
924 : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}
928 void addLock(FactSet &FSet, std::unique_ptr<FactEntry> Entry,
929 StringRef DiagKind,
bool ReqAttr =
false);
934 template <
typename AttrType>
935 void getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
Expr *Exp,
938 template <
class AttrType>
939 void getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
Expr *Exp,
942 Expr *BrE,
bool Neg);
944 const CallExpr* getTrylockCallExpr(
const Stmt *Cond, LocalVarContext C,
947 void getEdgeLockset(FactSet &Result,
const FactSet &ExitSet,
951 void intersectAndWarn(FactSet &FSet1,
const FactSet &FSet2,
956 void intersectAndWarn(FactSet &FSet1,
const FactSet &FSet2,
959 intersectAndWarn(FSet1, FSet2, JoinLoc, LEK1, LEK1, Modify);
968 ThreadSafetyAnalyzer& Analyzer) {
970 BeforeInfo *Info =
nullptr;
974 std::unique_ptr<BeforeInfo> &InfoPtr = BMap[Vd];
976 InfoPtr.reset(
new BeforeInfo());
977 Info = InfoPtr.get();
980 for (
Attr* At : Vd->attrs()) {
981 switch (At->getKind()) {
982 case attr::AcquiredBefore: {
983 auto *A = cast<AcquiredBeforeAttr>(At);
986 for (
const auto *Arg : A->args()) {
988 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
990 Info->Vect.push_back(Cpvd);
991 auto It = BMap.find(Cpvd);
992 if (It == BMap.end())
998 case attr::AcquiredAfter: {
999 auto *A = cast<AcquiredAfterAttr>(At);
1002 for (
const auto *Arg : A->args()) {
1004 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
1008 ArgInfo->Vect.push_back(Vd);
1021 BeforeSet::BeforeInfo *
1023 ThreadSafetyAnalyzer &Analyzer) {
1024 auto It = BMap.find(Vd);
1025 BeforeInfo *Info =
nullptr;
1026 if (It == BMap.end())
1029 Info = It->second.get();
1030 assert(Info &&
"BMap contained nullptr?");
1036 const FactSet& FSet,
1037 ThreadSafetyAnalyzer& Analyzer,
1043 std::function<bool (const ValueDecl*)> traverse = [&](
const ValueDecl* Vd) {
1049 if (Info->Visited == 1)
1052 if (Info->Visited == 2)
1055 if (Info->Vect.empty())
1058 InfoVect.push_back(Info);
1060 for (
auto *Vdb : Info->Vect) {
1062 if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {
1063 StringRef L1 = StartVd->
getName();
1064 StringRef L2 = Vdb->getName();
1065 Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc);
1068 if (traverse(Vdb)) {
1069 if (CycMap.find(Vd) == CycMap.end()) {
1070 CycMap.insert(std::make_pair(Vd,
true));
1072 Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->getLocation());
1082 for (
auto* Info : InfoVect)
1090 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))
1093 if (
const auto *DR = dyn_cast<DeclRefExpr>(Exp))
1094 return DR->getDecl();
1096 if (
const auto *ME = dyn_cast<MemberExpr>(Exp))
1097 return ME->getMemberDecl();
1103 template <
typename Ty>
1104 class has_arg_iterator_range {
1105 typedef char yes[1];
1108 template <
typename Inner>
1109 static yes& test(Inner *
I, decltype(I->args()) * =
nullptr);
1112 static no& test(...);
1115 static const bool value =
sizeof(test<Ty>(
nullptr)) ==
sizeof(yes);
1120 return A->getName();
1128 if (
const auto *RD = RT->getDecl())
1129 if (
const auto *CA = RD->getAttr<CapabilityAttr>())
1132 if (
const auto *TD = TT->getDecl())
1133 if (
const auto *CA = TD->getAttr<CapabilityAttr>())
1142 assert(VD &&
"No ValueDecl passed");
1148 template <
typename AttrTy>
1149 static typename std::enable_if<!has_arg_iterator_range<AttrTy>::value,
1157 template <
typename AttrTy>
1158 static typename std::enable_if<has_arg_iterator_range<AttrTy>::value,
1161 for (
const auto *Arg : A->args()) {
1169 inline bool ThreadSafetyAnalyzer::inCurrentScope(
const CapabilityExpr &CapE) {
1172 if (
auto *P = dyn_cast_or_null<til::Project>(CapE.
sexpr())) {
1173 auto *VD = P->clangDecl();
1175 return VD->getDeclContext() == CurrentMethod->getDeclContext();
1183 void ThreadSafetyAnalyzer::addLock(FactSet &FSet,
1184 std::unique_ptr<FactEntry> Entry,
1185 StringRef DiagKind,
bool ReqAttr) {
1186 if (Entry->shouldIgnore())
1189 if (!ReqAttr && !Entry->negative()) {
1192 FactEntry *Nen = FSet.findLock(FactMan, NegC);
1194 FSet.removeLock(FactMan, NegC);
1197 if (inCurrentScope(*Entry) && !Entry->asserted())
1205 !Entry->asserted() && !Entry->declared()) {
1206 GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *
this,
1207 Entry->loc(), DiagKind);
1211 if (FSet.findLock(FactMan, *Entry)) {
1212 if (!Entry->asserted())
1215 FSet.addLock(FactMan, std::move(Entry));
1222 void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
const CapabilityExpr &Cp,
1224 bool FullyRemove,
LockKind ReceivedKind,
1225 StringRef DiagKind) {
1229 const FactEntry *LDat = FSet.findLock(FactMan, Cp);
1237 if (ReceivedKind !=
LK_Generic && LDat->kind() != ReceivedKind) {
1239 LDat->kind(), ReceivedKind, UnlockLoc);
1242 LDat->handleUnlock(FSet, FactMan, Cp, UnlockLoc, FullyRemove, Handler,
1249 template <
typename AttrType>
1250 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
1253 if (Attr->args_size() == 0) {
1255 CapabilityExpr Cp = SxBuilder.translateAttrExpr(
nullptr, D, Exp, SelfDecl);
1262 Mtxs.push_back_nodup(Cp);
1266 for (
const auto *Arg : Attr->args()) {
1267 CapabilityExpr Cp = SxBuilder.translateAttrExpr(Arg, D, Exp, SelfDecl);
1274 Mtxs.push_back_nodup(Cp);
1282 template <
class AttrType>
1283 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr,
1287 Expr *BrE,
bool Neg) {
1289 bool branch =
false;
1291 branch = BLE->getValue();
1292 else if (
IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE))
1293 branch = ILE->getValue().getBoolValue();
1295 int branchnum = branch ? 0 : 1;
1297 branchnum = !branchnum;
1302 SE = PredBlock->
succ_end(); SI != SE && i < 2; ++SI, ++i) {
1303 if (*SI == CurrBlock && i == branchnum)
1304 getMutexIDs(Mtxs, Attr, Exp, D);
1309 if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) {
1313 TCond = BLE->getValue();
1316 TCond = ILE->getValue().getBoolValue();
1328 const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(
const Stmt *Cond,
1334 if (
const CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) {
1337 else if (
const ParenExpr *PE = dyn_cast<ParenExpr>(Cond)) {
1338 return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
1341 return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
1344 return getTrylockCallExpr(EWC->getSubExpr(), C, Negate);
1346 else if (
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) {
1347 const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
1348 return getTrylockCallExpr(E, C, Negate);
1350 else if (
const UnaryOperator *UOP = dyn_cast<UnaryOperator>(Cond)) {
1351 if (UOP->getOpcode() == UO_LNot) {
1353 return getTrylockCallExpr(UOP->getSubExpr(), C, Negate);
1357 else if (
const BinaryOperator *BOP = dyn_cast<BinaryOperator>(Cond)) {
1358 if (BOP->getOpcode() == BO_EQ || BOP->getOpcode() == BO_NE) {
1359 if (BOP->getOpcode() == BO_NE)
1364 if (!TCond) Negate = !Negate;
1365 return getTrylockCallExpr(BOP->getLHS(), C, Negate);
1369 if (!TCond) Negate = !Negate;
1370 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1374 if (BOP->getOpcode() == BO_LAnd) {
1376 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1378 if (BOP->getOpcode() == BO_LOr) {
1379 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1390 void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
1391 const FactSet &ExitSet,
1400 bool Negate =
false;
1401 const CFGBlockInfo *PredBlockInfo = &BlockInfo[PredBlock->
getBlockID()];
1402 const LocalVarContext &LVarCtx = PredBlockInfo->ExitContext;
1403 StringRef CapDiagKind =
"mutex";
1406 const_cast<CallExpr*
>(getTrylockCallExpr(Cond, LVarCtx, Negate));
1411 if(!FunDecl || !FunDecl->hasAttrs())
1414 CapExprSet ExclusiveLocksToAdd;
1415 CapExprSet SharedLocksToAdd;
1418 for (
auto *Attr : FunDecl->attrs()) {
1419 switch (Attr->getKind()) {
1420 case attr::ExclusiveTrylockFunction: {
1421 ExclusiveTrylockFunctionAttr *A =
1422 cast<ExclusiveTrylockFunctionAttr>(Attr);
1423 getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl,
1424 PredBlock, CurrBlock, A->getSuccessValue(), Negate);
1428 case attr::SharedTrylockFunction: {
1429 SharedTrylockFunctionAttr *A =
1430 cast<SharedTrylockFunctionAttr>(Attr);
1431 getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl,
1432 PredBlock, CurrBlock, A->getSuccessValue(), Negate);
1443 for (
const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
1444 addLock(Result, llvm::make_unique<LockableFactEntry>(ExclusiveLockToAdd,
1447 for (
const auto &SharedLockToAdd : SharedLocksToAdd)
1448 addLock(Result, llvm::make_unique<LockableFactEntry>(SharedLockToAdd,
1459 class BuildLockset :
public StmtVisitor<BuildLockset> {
1460 friend class ThreadSafetyAnalyzer;
1462 ThreadSafetyAnalyzer *Analyzer;
1464 LocalVariableMap::Context LVarCtx;
1472 StringRef DiagKind);
1482 BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
1485 FSet(Info.EntrySet),
1486 LVarCtx(Info.EntryContext),
1487 CtxIndex(Info.EntryIndex)
1501 void BuildLockset::warnIfMutexNotHeld(
const NamedDecl *D,
const Expr *Exp,
1507 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1509 warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
1517 FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
1519 Analyzer->Handler.handleFunExcludesLock(
1526 if (!Analyzer->inCurrentScope(Cp))
1530 LDat = FSet.findLock(Analyzer->FactMan, Cp);
1532 Analyzer->Handler.handleMutexNotHeld(
"", D, POK, Cp.
toString(),
1538 FactEntry* LDat = FSet.findLockUniv(Analyzer->FactMan, Cp);
1539 bool NoError =
true;
1542 LDat = FSet.findPartialMatch(Analyzer->FactMan, Cp);
1545 std::string PartMatchStr = LDat->toString();
1546 StringRef PartMatchName(PartMatchStr);
1547 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1548 LK, Loc, &PartMatchName);
1551 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1557 if (NoError && LDat && !LDat->isAtLeast(LK)) {
1558 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1564 void BuildLockset::warnIfMutexHeld(
const NamedDecl *D,
const Expr *Exp,
1565 Expr *MutexExp, StringRef DiagKind) {
1566 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1568 warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
1574 FactEntry* LDat = FSet.findLock(Analyzer->FactMan, Cp);
1576 Analyzer->Handler.handleFunExcludesLock(
1594 while (
const auto *DRE = dyn_cast<DeclRefExpr>(Exp)) {
1595 const auto *VD = dyn_cast<
VarDecl>(DRE->getDecl()->getCanonicalDecl());
1596 if (VD && VD->isLocalVarDecl() && VD->getType()->isReferenceType()) {
1597 if (
const auto *E = VD->getInit()) {
1605 if (
const UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp)) {
1607 if (UO->getOpcode() == clang::UO_Deref)
1608 checkPtAccess(UO->getSubExpr(), AK, POK);
1613 checkPtAccess(AE->getLHS(), AK, POK);
1617 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
1619 checkPtAccess(ME->getBase(), AK, POK);
1621 checkAccess(ME->getBase(), AK, POK);
1625 if (!D || !D->hasAttrs())
1628 if (D->hasAttr<GuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan)) {
1629 Analyzer->Handler.handleNoMutexHeld(
"mutex", D, POK, AK, Loc);
1632 for (
const auto *
I : D->specific_attrs<GuardedByAttr>())
1633 warnIfMutexNotHeld(D, Exp, AK,
I->getArg(), POK,
1643 if (
const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
1644 Exp = PE->getSubExpr();
1647 if (
const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
1648 if (CE->getCastKind() == CK_ArrayToPointerDecay) {
1651 checkAccess(CE->getSubExpr(), AK, POK);
1654 Exp = CE->getSubExpr();
1665 if (!D || !D->hasAttrs())
1668 if (D->hasAttr<PtGuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan))
1669 Analyzer->Handler.handleNoMutexHeld(
"mutex", D, PtPOK, AK,
1672 for (
auto const *
I : D->specific_attrs<PtGuardedByAttr>())
1673 warnIfMutexNotHeld(D, Exp, AK,
I->getArg(), PtPOK,
1689 CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
1690 CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
1691 CapExprSet ScopedExclusiveReqs, ScopedSharedReqs;
1692 StringRef CapDiagKind =
"mutex";
1695 bool isScopedVar =
false;
1699 if (PD && PD->hasAttr<ScopedLockableAttr>())
1704 for(Attr *Atconst : D->attrs()) {
1705 Attr* At =
const_cast<Attr*
>(Atconst);
1709 case attr::AcquireCapability: {
1710 auto *A = cast<AcquireCapabilityAttr>(At);
1711 Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd
1712 : ExclusiveLocksToAdd,
1722 case attr::AssertExclusiveLock: {
1723 AssertExclusiveLockAttr *A = cast<AssertExclusiveLockAttr>(At);
1725 CapExprSet AssertLocks;
1726 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1727 for (
const auto &AssertLock : AssertLocks)
1728 Analyzer->addLock(FSet,
1729 llvm::make_unique<LockableFactEntry>(
1730 AssertLock, LK_Exclusive, Loc,
false,
true),
1734 case attr::AssertSharedLock: {
1735 AssertSharedLockAttr *A = cast<AssertSharedLockAttr>(At);
1737 CapExprSet AssertLocks;
1738 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1739 for (
const auto &AssertLock : AssertLocks)
1740 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1741 AssertLock,
LK_Shared, Loc,
false,
true),
1748 case attr::ReleaseCapability: {
1749 auto *A = cast<ReleaseCapabilityAttr>(At);
1751 Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, VD);
1752 else if (A->isShared())
1753 Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, VD);
1755 Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, VD);
1761 case attr::RequiresCapability: {
1762 RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
1763 for (
auto *Arg : A->args()) {
1769 Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs
1770 : ScopedExclusiveReqs,
1777 case attr::LocksExcluded: {
1778 LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
1779 for (
auto *Arg : A->args())
1791 for (
const auto &M : ExclusiveLocksToAdd)
1792 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1793 M, LK_Exclusive, Loc, isScopedVar),
1795 for (
const auto &M : SharedLocksToAdd)
1796 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1805 CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE,
nullptr);
1807 std::copy(ScopedExclusiveReqs.begin(), ScopedExclusiveReqs.end(),
1808 std::back_inserter(ExclusiveLocksToAdd));
1809 std::copy(ScopedSharedReqs.begin(), ScopedSharedReqs.end(),
1810 std::back_inserter(SharedLocksToAdd));
1811 Analyzer->addLock(FSet,
1812 llvm::make_unique<ScopedLockableFactEntry>(
1813 Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd),
1819 bool Dtor = isa<CXXDestructorDecl>(D);
1820 for (
const auto &M : ExclusiveLocksToRemove)
1821 Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Exclusive, CapDiagKind);
1822 for (
const auto &M : SharedLocksToRemove)
1823 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Shared, CapDiagKind);
1824 for (
const auto &M : GenericLocksToRemove)
1825 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Generic, CapDiagKind);
1834 case clang::UO_PostDec:
1835 case clang::UO_PostInc:
1836 case clang::UO_PreDec:
1837 case clang::UO_PreInc: {
1854 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
1863 void BuildLockset::VisitCastExpr(
CastExpr *CE) {
1870 void BuildLockset::VisitCallExpr(
CallExpr *Exp) {
1871 bool ExamineArgs =
true;
1872 bool OperatorFun =
false;
1881 if (MD->isConst()) {
1882 checkPtAccess(CE->getImplicitObjectArgument(),
AK_Read);
1884 checkPtAccess(CE->getImplicitObjectArgument(),
AK_Read);
1888 checkAccess(CE->getImplicitObjectArgument(),
AK_Read);
1890 checkAccess(CE->getImplicitObjectArgument(),
AK_Read);
1896 auto OEop = OE->getOperator();
1899 ExamineArgs =
false;
1900 const Expr *Target = OE->getArg(0);
1901 const Expr *Source = OE->getArg(1);
1908 case OO_Subscript: {
1909 const Expr *Obj = OE->getArg(0);
1911 if (!(OEop == OO_Star && OE->getNumArgs() > 1)) {
1919 const Expr *Obj = OE->getArg(0);
1935 if (!FD->hasAttr<NoThreadSafetyAnalysisAttr>()) {
1936 unsigned Fn = FD->getNumParams();
1942 if (isa<CXXMethodDecl>(FD)) {
1953 unsigned n = (Fn < Cn) ? Fn : Cn;
1955 for (; i < n; ++i) {
1967 if(!D || !D->hasAttrs())
1981 void BuildLockset::VisitDeclStmt(
DeclStmt *S) {
1983 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
1986 if (
VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) {
1990 E = EWC->getSubExpr();
1993 NamedDecl *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor());
1994 if (!CtorD || !CtorD->hasAttrs())
1996 handleCall(CE, CtorD, VD);
2018 void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
2019 const FactSet &FSet2,
2024 FactSet FSet1Orig = FSet1;
2027 for (
const auto &Fact : FSet2) {
2028 const FactEntry *LDat1 =
nullptr;
2029 const FactEntry *LDat2 = &FactMan[Fact];
2030 FactSet::iterator Iter1 = FSet1.findLockIter(FactMan, *LDat2);
2031 if (Iter1 != FSet1.end()) LDat1 = &FactMan[*Iter1];
2034 if (LDat1->kind() != LDat2->kind()) {
2036 LDat2->loc(), LDat1->loc());
2042 else if (Modify && LDat1->asserted() && !LDat2->asserted()) {
2047 LDat2->handleRemovalFromIntersection(FSet2, FactMan, JoinLoc, LEK1,
2053 for (
const auto &Fact : FSet1Orig) {
2054 const FactEntry *LDat1 = &FactMan[Fact];
2055 const FactEntry *LDat2 = FSet2.findLock(FactMan, *LDat1);
2058 LDat1->handleRemovalFromIntersection(FSet1Orig, FactMan, JoinLoc, LEK2,
2061 FSet1.removeLock(FactMan, *LDat1);
2076 if (isa<CXXThrowExpr>(S->getStmt()))
2092 if (!walker.
init(AC))
2103 if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
2110 if (isa<CXXConstructorDecl>(D))
2112 if (isa<CXXDestructorDecl>(D))
2118 CFGBlockInfo::getEmptyBlockInfo(LocalVarMap));
2130 LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
2133 findBlockLocations(CFGraph, SortedGraph, BlockInfo);
2135 CapExprSet ExclusiveLocksAcquired;
2136 CapExprSet SharedLocksAcquired;
2137 CapExprSet LocksReleased;
2142 if (!SortedGraph->
empty() && D->hasAttrs()) {
2144 FactSet &InitialLockset = BlockInfo[FirstBlock->
getBlockID()].EntrySet;
2146 CapExprSet ExclusiveLocksToAdd;
2147 CapExprSet SharedLocksToAdd;
2148 StringRef CapDiagKind =
"mutex";
2151 for (
const auto *Attr : D->attrs()) {
2152 Loc = Attr->getLocation();
2153 if (
const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
2154 getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
2157 }
else if (
const auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
2160 if (A->args_size() == 0)
2163 getMutexIDs(ExclusiveLocksToAdd, A,
nullptr, D);
2164 getMutexIDs(LocksReleased, A,
nullptr, D);
2166 }
else if (
const auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
2167 if (A->args_size() == 0)
2169 getMutexIDs(A->isShared() ? SharedLocksAcquired
2170 : ExclusiveLocksAcquired,
2173 }
else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) {
2176 }
else if (isa<SharedTrylockFunctionAttr>(Attr)) {
2183 for (
const auto &Mu : ExclusiveLocksToAdd) {
2184 auto Entry = llvm::make_unique<LockableFactEntry>(Mu,
LK_Exclusive, Loc);
2185 Entry->setDeclared(
true);
2186 addLock(InitialLockset, std::move(Entry), CapDiagKind,
true);
2188 for (
const auto &Mu : SharedLocksToAdd) {
2189 auto Entry = llvm::make_unique<LockableFactEntry>(Mu,
LK_Shared, Loc);
2190 Entry->setDeclared(
true);
2191 addLock(InitialLockset, std::move(Entry), CapDiagKind,
true);
2195 for (
const auto *CurrBlock : *SortedGraph) {
2197 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
2200 VisitedBlocks.insert(CurrBlock);
2215 bool LocksetInitialized =
false;
2218 PE = CurrBlock->
pred_end(); PI != PE; ++PI) {
2221 if (*PI ==
nullptr || !VisitedBlocks.alreadySet(*PI))
2224 int PrevBlockID = (*PI)->getBlockID();
2225 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
2232 CurrBlockInfo->Reachable =
true;
2238 if (
const Stmt *Terminator = (*PI)->getTerminator()) {
2239 if (isa<ContinueStmt>(Terminator) || isa<BreakStmt>(Terminator)) {
2240 SpecialBlocks.push_back(*PI);
2245 FactSet PrevLockset;
2246 getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
2248 if (!LocksetInitialized) {
2249 CurrBlockInfo->EntrySet = PrevLockset;
2250 LocksetInitialized =
true;
2252 intersectAndWarn(CurrBlockInfo->EntrySet, PrevLockset,
2253 CurrBlockInfo->EntryLoc,
2259 if (!CurrBlockInfo->Reachable)
2264 for (
const auto *PrevBlock : SpecialBlocks) {
2265 int PrevBlockID = PrevBlock->getBlockID();
2266 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
2268 if (!LocksetInitialized) {
2269 CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet;
2270 LocksetInitialized =
true;
2277 const Stmt *Terminator = PrevBlock->getTerminator();
2278 bool IsLoop = Terminator && isa<ContinueStmt>(Terminator);
2280 FactSet PrevLockset;
2281 getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet,
2282 PrevBlock, CurrBlock);
2285 intersectAndWarn(CurrBlockInfo->EntrySet, PrevLockset,
2286 PrevBlockInfo->ExitLoc,
2293 BuildLockset LocksetBuilder(
this, *CurrBlockInfo);
2297 BE = CurrBlock->
end(); BI != BE; ++BI) {
2298 switch (BI->getKind()) {
2301 LocksetBuilder.Visit(const_cast<Stmt*>(CS.
getStmt()));
2309 if (!DD->hasAttrs())
2316 LocksetBuilder.handleCall(&DRE, DD);
2323 CurrBlockInfo->ExitSet = LocksetBuilder.FSet;
2330 SE = CurrBlock->
succ_end(); SI != SE; ++SI) {
2333 if (*SI ==
nullptr || !VisitedBlocks.alreadySet(*SI))
2337 CFGBlockInfo *PreLoop = &BlockInfo[FirstLoopBlock->
getBlockID()];
2338 CFGBlockInfo *LoopEnd = &BlockInfo[CurrBlockID];
2339 intersectAndWarn(LoopEnd->ExitSet, PreLoop->EntrySet,
2350 if (!Final->Reachable)
2354 FactSet ExpectedExitSet = Initial->EntrySet;
2360 for (
const auto &Lock : ExclusiveLocksAcquired)
2361 ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
2362 Lock, LK_Exclusive, D->getLocation()));
2363 for (
const auto &Lock : SharedLocksAcquired)
2364 ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
2365 Lock, LK_Shared, D->getLocation()));
2366 for (
const auto &Lock : LocksReleased)
2367 ExpectedExitSet.removeLock(FactMan, Lock);
2370 intersectAndWarn(ExpectedExitSet, Final->ExitSet,
2390 ThreadSafetyAnalyzer Analyzer(Handler, *BSet);
2391 Analyzer.runAnalysis(AC);
2405 llvm_unreachable(
"Unknown AccessKind");
A call to an overloaded operator written using operator syntax.
CastKind getCastKind() const
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Passing a guarded variable by reference.
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
ASTContext & getASTContext() const
const DeclGroupRef getDeclGroup() const
A (possibly-)qualified type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
succ_iterator succ_begin()
virtual void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc)
Warn about unlock function calls that do not have a prior matching lock expression.
static StringRef ClassifyDiagnostic(const CapabilityAttr *A)
Defines the SourceManager interface.
ParenExpr - This represents a parethesized expression, e.g.
TypePropertyCache< Private > Cache
bool isCopyConstructor(unsigned &TypeQuals) const
Whether this constructor is a copy constructor (C++ [class.copy]p2, which can be used to copy the cla...
const Expr * getInit() const
Represents a call to a C++ constructor.
LockKind getLockKindFromAccessKind(AccessKind AK)
Helper function that returns a LockKind required for the given level of access.
Represents a C++ constructor within a class.
Exclusive/writer lock of a mutex.
ProtectedOperationKind
This enum distinguishes between different kinds of operations that may need to be protected by locks...
VarDecl - An instance of this class is created to represent a variable declaration or definition...
bool equals(const CapabilityExpr &other) const
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
static bool isAssignmentOp(Opcode Opc)
ParmVarDecl - Represents a parameter to a function.
Defines the clang::Expr interface and subclasses for C++ expressions.
const ValueDecl * valueDecl() const
void threadSafetyCleanup(BeforeSet *Cache)
static const ValueDecl * getValueDecl(const Expr *Exp)
Gets the value decl pointer from DeclRefExprs or MemberExprs.
LockKind
This enum distinguishes between different kinds of lock actions.
CFGBlockSide
A side (entry or exit) of a CFG node.
bool isReferenceType() const
AnalysisDeclContext contains the context data for the function or method under analysis.
CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated for automatic object or t...
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type...
static bool neverReturns(const CFGBlock *B)
virtual void enterFunction(const FunctionDecl *FD)
Called by the analysis when starting analysis of a function.
virtual void handleInvalidLockExp(StringRef Kind, SourceLocation Loc)
Warn about lock expressions which fail to resolve to lockable objects.
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
const VarDecl * getVarDecl() const
Implements a set of CFGBlocks using a BitVector.
ElementList::const_iterator const_iterator
A builtin binary operation expression such as "x + y" or "x <= y".
bool shouldIgnore() const
const NamedDecl * getDecl() const
std::string getNameAsString() const
getNameAsString - Get a human-readable name for the declaration, even if it is one of the special kin...
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
bool isTrivialType(const ASTContext &Context) const
Return true if this is a trivial type per (C++0x [basic.types]p9)
virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, SourceLocation Loc)
Warn when acquiring a lock that the negative capability is not held.
detail::InMemoryDirectory::const_iterator I
const Stmt * getTriggerStmt() const
Shared/reader lock of a mutex.
virtual ~ThreadSafetyHandler()
Passing a pt-guarded variable by reference.
bool init(AnalysisDeclContext &AC)
Handler class for thread safety warnings.
CFGBlock - Represents a single basic block in a source-level CFG.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Dereferencing a variable (e.g. p in *p = 5;)
ValueDecl - Represent the declaration of a variable (in which case it is an lvalue) a function (in wh...
Expr - This represents one expression.
Stmt * getTerminatorCondition(bool StripParens=true)
CFG - Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
Represents a C++ destructor within a class.
Defines an enumeration for C++ overloaded operators.
void checkBeforeAfter(const ValueDecl *Vd, const FactSet &FSet, ThreadSafetyAnalyzer &Analyzer, SourceLocation Loc, StringRef CapKind)
Return true if any mutexes in FSet are in the acquired_before set of Vd.
AdjacentBlocks::const_iterator const_pred_iterator
Expr * getSubExpr() const
virtual void handleIncorrectUnlockKind(StringRef Kind, Name LockName, LockKind Expected, LockKind Received, SourceLocation Loc)
Warn about an unlock function call that attempts to unlock a lock with the incorrect lock kind...
DeclContext * getParent()
getParent - Returns the containing DeclContext.
unsigned getBlockID() const
AccessKind
This enum distinguishes between different ways to access (read or write) a variable.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
Making a function call (e.g. fool())
std::string toString() const
const PostOrderCFGView * getSortedGraph() const
The result type of a method or function.
const til::SExpr * sexpr() const
bool hasNoReturnElement() const
Reading or writing a variable (e.g. x in x = 5;)
BeforeInfo * insertAttrExprs(const ValueDecl *Vd, ThreadSafetyAnalyzer &Analyzer)
Process acquired_before and acquired_after attributes on Vd.
Encodes a location in the source.
const TemplateArgument * iterator
bool isValid() const
Return true if this is a valid SourceLocation object.
Represents a call to a member function that may be written either with member call syntax (e...
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
void printName(raw_ostream &os) const
Represents a static or instance method of a struct/union/class.
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
const Stmt * getStmt() const
const CFG * getGraph() const
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
static bool getStaticBooleanValue(Expr *E, bool &TCond)
AdjacentBlocks::const_iterator const_succ_iterator
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
attr::Kind getKind() const
Represents a template argument.
pred_iterator pred_begin()
SourceLocation getLocStart() const LLVM_READONLY
BeforeInfo * getBeforeInfoForDecl(const ValueDecl *Vd, ThreadSafetyAnalyzer &Analyzer)
void runThreadSafetyAnalysis(AnalysisDeclContext &AC, ThreadSafetyHandler &Handler, BeforeSet **Bset)
Check a function's CFG for thread-safety violations.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
detail::InMemoryDirectory::const_iterator E
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
std::string toString(const til::SExpr *E)
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
const T * getAs() const
Member-template getAs<specific type>'.
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Expr * getArg(unsigned Arg)
Return the specified argument.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
virtual void handleExclusiveAndShared(StringRef Kind, Name LockName, SourceLocation Loc1, SourceLocation Loc2)
Warn when a mutex is held exclusively and shared at the same point.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
virtual void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc)
Warn about lock function calls for locks which are already held.
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ struct/union/class.
CFGElement - Represents a top-level expression in a basic block.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
virtual void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, SourceLocation LocLocked, SourceLocation LocEndOfScope, LockErrorKind LEK)
Warn about situations where a mutex is sometimes held and sometimes not.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A reference to a declared variable, function, enum, etc.
Base class for AST nodes in the typed intermediate language.
const FunctionDecl * CurrentFunction
virtual void leaveFunction(const FunctionDecl *FD)
Called by the analysis when finishing analysis of a function.
bool matches(const til::SExpr *E1, const til::SExpr *E2)
An l-value expression is a reference to an object with independent storage.
NamedDecl - This represents a decl with a name.
A boolean literal, per ([C++ lex.bool] Boolean literals).
unsigned getNumBlockIDs() const
getNumBlockIDs - Returns the total number of BlockIDs allocated (which start at 0).
Optional< T > getAs() const
Convert to the specified CFGElement type, returning None if this CFGElement is not of the desired typ...
Attr - This represents one attribute.
bool isPointerType() const
Can be either Shared or Exclusive.