@@ -101,17 +101,22 @@ class FactEntry : public CapabilityExpr {
101
101
LockKind LKind; // /< exclusive or shared
102
102
SourceLocation AcquireLoc; // /< where it was acquired.
103
103
bool Asserted; // /< true if the lock was asserted
104
+ bool Declared; // /< true if the lock was declared
104
105
105
106
public:
106
107
FactEntry (const CapabilityExpr &CE, LockKind LK, SourceLocation Loc,
107
- bool Asrt)
108
- : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt) {}
108
+ bool Asrt, bool Declrd = false )
109
+ : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt),
110
+ Declared (Declrd) {}
109
111
110
112
virtual ~FactEntry () {}
111
113
112
- LockKind kind () const { return LKind; }
114
+ LockKind kind () const { return LKind; }
113
115
SourceLocation loc () const { return AcquireLoc; }
114
116
bool asserted () const { return Asserted; }
117
+ bool declared () const { return Declared; }
118
+
119
+ void setDeclared (bool D) { Declared = D; }
115
120
116
121
virtual void
117
122
handleRemovalFromIntersection (const FactSet &FSet, FactManager &FactMan,
@@ -231,14 +236,56 @@ class FactSet {
231
236
232
237
FactEntry *findPartialMatch (FactManager &FM,
233
238
const CapabilityExpr &CapE) const {
234
- auto I = std::find_if (begin (), end (), [&](FactID ID) {
239
+ auto I = std::find_if (begin (), end (), [&](FactID ID) -> bool {
235
240
return FM[ID].partiallyMatches (CapE);
236
241
});
237
242
return I != end () ? &FM[*I] : nullptr ;
238
243
}
244
+
245
+ bool containsMutexDecl (FactManager &FM, const ValueDecl* Vd) const {
246
+ auto I = std::find_if (begin (), end (), [&](FactID ID) -> bool {
247
+ return FM[ID].valueDecl () == Vd;
248
+ });
249
+ return I != end ();
250
+ }
251
+ };
252
+
253
+
254
+ class ThreadSafetyAnalyzer ;
255
+
256
+
257
+ class BeforeSet {
258
+ private:
259
+ typedef SmallVector<const ValueDecl*, 4 > BeforeVect;
260
+
261
+ struct BeforeInfo {
262
+ BeforeInfo () : Vect(nullptr ), Visited(false ) { }
263
+
264
+ std::unique_ptr<BeforeVect> Vect;
265
+ int Visited;
266
+ };
267
+
268
+ typedef llvm::DenseMap<const ValueDecl*, BeforeInfo> BeforeMap;
269
+ typedef llvm::DenseMap<const ValueDecl*, bool > CycleMap;
270
+
271
+ public:
272
+ BeforeSet () { }
273
+
274
+ BeforeInfo* insertAttrExprs (const ValueDecl* Vd,
275
+ ThreadSafetyAnalyzer& Analyzer);
276
+
277
+ void checkBeforeAfter (const ValueDecl* Vd,
278
+ const FactSet& FSet,
279
+ ThreadSafetyAnalyzer& Analyzer,
280
+ SourceLocation Loc, StringRef CapKind);
281
+
282
+ private:
283
+ BeforeMap BMap;
284
+ CycleMap CycMap;
239
285
};
240
286
241
287
288
+
242
289
typedef llvm::ImmutableMap<const NamedDecl*, unsigned > LocalVarContext;
243
290
class LocalVariableMap ;
244
291
@@ -853,6 +900,7 @@ class ScopedLockableFactEntry : public FactEntry {
853
900
// / \brief Class which implements the core thread safety analysis routines.
854
901
class ThreadSafetyAnalyzer {
855
902
friend class BuildLockset ;
903
+ friend class BeforeSet ;
856
904
857
905
llvm::BumpPtrAllocator Bpa;
858
906
threadSafety::til::MemRegionRef Arena;
@@ -864,9 +912,11 @@ class ThreadSafetyAnalyzer {
864
912
FactManager FactMan;
865
913
std::vector<CFGBlockInfo> BlockInfo;
866
914
915
+ BeforeSet* GlobalBeforeSet;
916
+
867
917
public:
868
- ThreadSafetyAnalyzer (ThreadSafetyHandler &H)
869
- : Arena(&Bpa), SxBuilder(Arena), Handler(H) {}
918
+ ThreadSafetyAnalyzer (ThreadSafetyHandler &H, BeforeSet* Bset )
919
+ : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}
870
920
871
921
bool inCurrentScope (const CapabilityExpr &CapE);
872
922
@@ -907,6 +957,136 @@ class ThreadSafetyAnalyzer {
907
957
void runAnalysis (AnalysisDeclContext &AC);
908
958
};
909
959
960
+
961
+
962
+ // / Process acquired_before and acquired_after attributes on Vd.
963
+ BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs (const ValueDecl* Vd,
964
+ ThreadSafetyAnalyzer& Analyzer) {
965
+ // Create a new entry for Vd.
966
+ auto & Entry = BMap.FindAndConstruct (Vd);
967
+ BeforeInfo* Info = &Entry.second ;
968
+ BeforeVect* Bv = nullptr ;
969
+
970
+ const AttrVec &ArgAttrs = Vd->getAttrs ();
971
+ for (Attr* At : ArgAttrs) {
972
+ switch (At->getKind ()) {
973
+ case attr::AcquiredBefore: {
974
+ auto *A = cast<AcquiredBeforeAttr>(At);
975
+
976
+ // Create a new BeforeVect for Vd if necessary.
977
+ if (!Bv) {
978
+ Bv = new BeforeVect;
979
+ Info->Vect .reset (Bv);
980
+ }
981
+ // Read exprs from the attribute, and add them to BeforeVect.
982
+ for (const auto *Arg : A->args ()) {
983
+ CapabilityExpr Cp =
984
+ Analyzer.SxBuilder .translateAttrExpr (Arg, nullptr );
985
+ if (const ValueDecl *Cpvd = Cp.valueDecl ()) {
986
+ Bv->push_back (Cpvd);
987
+ auto It = BMap.find (Cpvd);
988
+ if (It == BMap.end ())
989
+ insertAttrExprs (Cpvd, Analyzer);
990
+ }
991
+ }
992
+ break ;
993
+ }
994
+ case attr::AcquiredAfter: {
995
+ auto *A = cast<AcquiredAfterAttr>(At);
996
+
997
+ // Read exprs from the attribute, and add them to BeforeVect.
998
+ for (const auto *Arg : A->args ()) {
999
+ CapabilityExpr Cp =
1000
+ Analyzer.SxBuilder .translateAttrExpr (Arg, nullptr );
1001
+ if (const ValueDecl *ArgVd = Cp.valueDecl ()) {
1002
+ // Get entry for mutex listed in attribute
1003
+ BeforeInfo* ArgInfo;
1004
+ auto It = BMap.find (ArgVd);
1005
+ if (It == BMap.end ())
1006
+ ArgInfo = insertAttrExprs (ArgVd, Analyzer);
1007
+ else
1008
+ ArgInfo = &It->second ;
1009
+
1010
+ // Create a new BeforeVect if necessary.
1011
+ BeforeVect* ArgBv = ArgInfo->Vect .get ();
1012
+ if (!ArgBv) {
1013
+ ArgBv = new BeforeVect;
1014
+ ArgInfo->Vect .reset (ArgBv);
1015
+ }
1016
+ ArgBv->push_back (Vd);
1017
+ }
1018
+ }
1019
+ break ;
1020
+ }
1021
+ default :
1022
+ break ;
1023
+ }
1024
+ }
1025
+
1026
+ return Info;
1027
+ }
1028
+
1029
+
1030
+ // / Return true if any mutexes in FSet are in the acquired_before set of Vd.
1031
+ void BeforeSet::checkBeforeAfter (const ValueDecl* StartVd,
1032
+ const FactSet& FSet,
1033
+ ThreadSafetyAnalyzer& Analyzer,
1034
+ SourceLocation Loc, StringRef CapKind) {
1035
+ SmallVector<BeforeInfo*, 8 > InfoVect;
1036
+
1037
+ // Do a depth-first traversal of Vd.
1038
+ // Return true if there are cycles.
1039
+ std::function<bool (const ValueDecl*)> traverse = [&](const ValueDecl* Vd) {
1040
+ if (!Vd)
1041
+ return false ;
1042
+
1043
+ BeforeSet::BeforeInfo* Info;
1044
+ auto It = BMap.find (Vd);
1045
+ if (It == BMap.end ())
1046
+ Info = insertAttrExprs (Vd, Analyzer);
1047
+ else
1048
+ Info = &It->second ;
1049
+
1050
+ if (Info->Visited == 1 )
1051
+ return true ;
1052
+
1053
+ if (Info->Visited == 2 )
1054
+ return false ;
1055
+
1056
+ BeforeVect* Bv = Info->Vect .get ();
1057
+ if (!Bv)
1058
+ return false ;
1059
+
1060
+ InfoVect.push_back (Info);
1061
+ Info->Visited = 1 ;
1062
+ for (auto *Vdb : *Bv) {
1063
+ // Exclude mutexes in our immediate before set.
1064
+ if (FSet.containsMutexDecl (Analyzer.FactMan , Vdb)) {
1065
+ StringRef L1 = StartVd->getName ();
1066
+ StringRef L2 = Vdb->getName ();
1067
+ Analyzer.Handler .handleLockAcquiredBefore (CapKind, L1, L2, Loc);
1068
+ }
1069
+ // Transitively search other before sets, and warn on cycles.
1070
+ if (traverse (Vdb)) {
1071
+ if (CycMap.find (Vd) == CycMap.end ()) {
1072
+ CycMap.insert (std::make_pair (Vd, true ));
1073
+ StringRef L1 = Vd->getName ();
1074
+ Analyzer.Handler .handleBeforeAfterCycle (L1, Vd->getLocation ());
1075
+ }
1076
+ }
1077
+ }
1078
+ Info->Visited = 2 ;
1079
+ return false ;
1080
+ };
1081
+
1082
+ traverse (StartVd);
1083
+
1084
+ for (auto * Info : InfoVect)
1085
+ Info->Visited = 0 ;
1086
+ }
1087
+
1088
+
1089
+
910
1090
// / \brief Gets the value decl pointer from DeclRefExprs or MemberExprs.
911
1091
static const ValueDecl *getValueDecl (const Expr *Exp) {
912
1092
if (const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))
@@ -1020,7 +1200,13 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet,
1020
1200
}
1021
1201
}
1022
1202
1023
- // FIXME: deal with acquired before/after annotations.
1203
+ // Check before/after constraints
1204
+ if (Handler.issueBetaWarnings () &&
1205
+ !Entry->asserted () && !Entry->declared ()) {
1206
+ GlobalBeforeSet->checkBeforeAfter (Entry->valueDecl (), FSet, *this ,
1207
+ Entry->loc (), DiagKind);
1208
+ }
1209
+
1024
1210
// FIXME: Don't always warn when we have support for reentrant locks.
1025
1211
if (FSet.findLock (FactMan, *Entry)) {
1026
1212
if (!Entry->asserted ())
@@ -1979,14 +2165,16 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
1979
2165
}
1980
2166
1981
2167
// FIXME -- Loc can be wrong here.
1982
- for (const auto &Mu : ExclusiveLocksToAdd)
1983
- addLock (InitialLockset,
1984
- llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc),
1985
- CapDiagKind, true );
1986
- for (const auto &Mu : SharedLocksToAdd)
1987
- addLock (InitialLockset,
1988
- llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc),
1989
- CapDiagKind, true );
2168
+ for (const auto &Mu : ExclusiveLocksToAdd) {
2169
+ auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc);
2170
+ Entry->setDeclared (true );
2171
+ addLock (InitialLockset, std::move (Entry), CapDiagKind, true );
2172
+ }
2173
+ for (const auto &Mu : SharedLocksToAdd) {
2174
+ auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc);
2175
+ Entry->setDeclared (true );
2176
+ addLock (InitialLockset, std::move (Entry), CapDiagKind, true );
2177
+ }
1990
2178
}
1991
2179
1992
2180
for (const auto *CurrBlock : *SortedGraph) {
@@ -2180,11 +2368,20 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
2180
2368
// / at the end of each block, and issue warnings for thread safety violations.
2181
2369
// / Each block in the CFG is traversed exactly once.
2182
2370
void runThreadSafetyAnalysis (AnalysisDeclContext &AC,
2183
- ThreadSafetyHandler &Handler) {
2184
- ThreadSafetyAnalyzer Analyzer (Handler);
2371
+ ThreadSafetyHandler &Handler,
2372
+ BeforeSet **BSet) {
2373
+ if (!*BSet)
2374
+ *BSet = new BeforeSet;
2375
+ ThreadSafetyAnalyzer Analyzer (Handler, *BSet);
2185
2376
Analyzer.runAnalysis (AC);
2186
2377
}
2187
2378
2379
+
2380
+ void threadSafetyCleanup (BeforeSet* Cache) {
2381
+ delete Cache;
2382
+ }
2383
+
2384
+
2188
2385
// / \brief Helper function that returns a LockKind required for the given level
2189
2386
// / of access.
2190
2387
LockKind getLockKindFromAccessKind (AccessKind AK) {
0 commit comments