42
42
#include " llvm/ADT/DenseMap.h"
43
43
#include " llvm/ADT/ImmutableMap.h"
44
44
#include " llvm/ADT/Optional.h"
45
+ #include " llvm/ADT/PointerIntPair.h"
45
46
#include " llvm/ADT/STLExtras.h"
46
47
#include " llvm/ADT/SmallVector.h"
47
48
#include " llvm/ADT/StringRef.h"
@@ -890,46 +891,61 @@ class LockableFactEntry : public FactEntry {
890
891
891
892
class ScopedLockableFactEntry : public FactEntry {
892
893
private:
893
- SmallVector<const til::SExpr *, 4 > UnderlyingMutexes;
894
+ enum UnderlyingCapabilityKind {
895
+ UCK_Acquired, // /< Any kind of acquired capability.
896
+ UCK_ReleasedShared, // /< Shared capability that was released.
897
+ UCK_ReleasedExclusive, // /< Exclusive capability that was released.
898
+ };
899
+
900
+ using UnderlyingCapability =
901
+ llvm::PointerIntPair<const til::SExpr *, 2 , UnderlyingCapabilityKind>;
902
+
903
+ SmallVector<UnderlyingCapability, 4 > UnderlyingMutexes;
894
904
895
905
public:
896
906
ScopedLockableFactEntry (const CapabilityExpr &CE, SourceLocation Loc,
897
- const CapExprSet &Excl, const CapExprSet &Shrd)
907
+ const CapExprSet &Excl, const CapExprSet &Shrd,
908
+ const CapExprSet &ExclRel, const CapExprSet &ShrdRel)
898
909
: FactEntry(CE, LK_Exclusive, Loc, false ) {
899
910
for (const auto &M : Excl)
900
- UnderlyingMutexes.push_back (M.sexpr ());
911
+ UnderlyingMutexes.emplace_back (M.sexpr (), UCK_Acquired );
901
912
for (const auto &M : Shrd)
902
- UnderlyingMutexes.push_back (M.sexpr ());
913
+ UnderlyingMutexes.emplace_back (M.sexpr (), UCK_Acquired);
914
+ for (const auto &M : ExclRel)
915
+ UnderlyingMutexes.emplace_back (M.sexpr (), UCK_ReleasedExclusive);
916
+ for (const auto &M : ShrdRel)
917
+ UnderlyingMutexes.emplace_back (M.sexpr (), UCK_ReleasedShared);
903
918
}
904
919
905
920
void
906
921
handleRemovalFromIntersection (const FactSet &FSet, FactManager &FactMan,
907
922
SourceLocation JoinLoc, LockErrorKind LEK,
908
923
ThreadSafetyHandler &Handler) const override {
909
- for (const auto *UnderlyingMutex : UnderlyingMutexes) {
910
- if (FSet.findLock (FactMan, CapabilityExpr (UnderlyingMutex, false ))) {
924
+ for (const auto &UnderlyingMutex : UnderlyingMutexes) {
925
+ const auto *Entry = FSet.findLock (
926
+ FactMan, CapabilityExpr (UnderlyingMutex.getPointer (), false ));
927
+ if ((UnderlyingMutex.getInt () == UCK_Acquired && Entry) ||
928
+ (UnderlyingMutex.getInt () != UCK_Acquired && !Entry)) {
911
929
// If this scoped lock manages another mutex, and if the underlying
912
- // mutex is still held, then warn about the underlying mutex.
930
+ // mutex is still/not held, then warn about the underlying mutex.
913
931
Handler.handleMutexHeldEndOfScope (
914
- " mutex" , sx::toString (UnderlyingMutex), loc (), JoinLoc, LEK);
932
+ " mutex" , sx::toString (UnderlyingMutex.getPointer ()), loc (), JoinLoc,
933
+ LEK);
915
934
}
916
935
}
917
936
}
918
937
919
938
void handleLock (FactSet &FSet, FactManager &FactMan, const FactEntry &entry,
920
939
ThreadSafetyHandler &Handler,
921
940
StringRef DiagKind) const override {
922
- for (const auto * UnderlyingMutex : UnderlyingMutexes) {
923
- CapabilityExpr UnderCp (UnderlyingMutex, false );
941
+ for (const auto & UnderlyingMutex : UnderlyingMutexes) {
942
+ CapabilityExpr UnderCp (UnderlyingMutex. getPointer () , false );
924
943
925
- // We're relocking the underlying mutexes. Warn on double locking.
926
- if (FSet.findLock (FactMan, UnderCp)) {
927
- Handler.handleDoubleLock (DiagKind, UnderCp.toString (), entry.loc ());
928
- } else {
929
- FSet.removeLock (FactMan, !UnderCp);
930
- FSet.addLock (FactMan, llvm::make_unique<LockableFactEntry>(
931
- UnderCp, entry.kind (), entry.loc ()));
932
- }
944
+ if (UnderlyingMutex.getInt () == UCK_Acquired)
945
+ lock (FSet, FactMan, UnderCp, entry.kind (), entry.loc (), &Handler,
946
+ DiagKind);
947
+ else
948
+ unlock (FSet, FactMan, UnderCp, entry.loc (), &Handler, DiagKind);
933
949
}
934
950
}
935
951
@@ -938,32 +954,49 @@ class ScopedLockableFactEntry : public FactEntry {
938
954
bool FullyRemove, ThreadSafetyHandler &Handler,
939
955
StringRef DiagKind) const override {
940
956
assert (!Cp.negative () && " Managing object cannot be negative." );
941
- for (const auto *UnderlyingMutex : UnderlyingMutexes) {
942
- CapabilityExpr UnderCp (UnderlyingMutex, false );
943
- auto UnderEntry = llvm::make_unique<LockableFactEntry>(
944
- !UnderCp, LK_Exclusive, UnlockLoc);
945
-
946
- if (FullyRemove) {
947
- // We're destroying the managing object.
948
- // Remove the underlying mutex if it exists; but don't warn.
949
- if (FSet.findLock (FactMan, UnderCp)) {
950
- FSet.removeLock (FactMan, UnderCp);
951
- FSet.addLock (FactMan, std::move (UnderEntry));
952
- }
957
+ for (const auto &UnderlyingMutex : UnderlyingMutexes) {
958
+ CapabilityExpr UnderCp (UnderlyingMutex.getPointer (), false );
959
+
960
+ // Remove/lock the underlying mutex if it exists/is still unlocked; warn
961
+ // on double unlocking/locking if we're not destroying the scoped object.
962
+ ThreadSafetyHandler *TSHandler = FullyRemove ? nullptr : &Handler;
963
+ if (UnderlyingMutex.getInt () == UCK_Acquired) {
964
+ unlock (FSet, FactMan, UnderCp, UnlockLoc, TSHandler, DiagKind);
953
965
} else {
954
- // We're releasing the underlying mutex, but not destroying the
955
- // managing object. Warn on dual release.
956
- if (!FSet.findLock (FactMan, UnderCp)) {
957
- Handler.handleUnmatchedUnlock (DiagKind, UnderCp.toString (),
958
- UnlockLoc);
959
- }
960
- FSet.removeLock (FactMan, UnderCp);
961
- FSet.addLock (FactMan, std::move (UnderEntry));
966
+ LockKind kind = UnderlyingMutex.getInt () == UCK_ReleasedShared
967
+ ? LK_Shared
968
+ : LK_Exclusive;
969
+ lock (FSet, FactMan, UnderCp, kind, UnlockLoc, TSHandler, DiagKind);
962
970
}
963
971
}
964
972
if (FullyRemove)
965
973
FSet.removeLock (FactMan, Cp);
966
974
}
975
+
976
+ private:
977
+ void lock (FactSet &FSet, FactManager &FactMan, const CapabilityExpr &Cp,
978
+ LockKind kind, SourceLocation loc, ThreadSafetyHandler *Handler,
979
+ StringRef DiagKind) const {
980
+ if (!FSet.findLock (FactMan, Cp)) {
981
+ FSet.removeLock (FactMan, !Cp);
982
+ FSet.addLock (FactMan,
983
+ llvm::make_unique<LockableFactEntry>(Cp, kind, loc));
984
+ } else if (Handler) {
985
+ Handler->handleDoubleLock (DiagKind, Cp.toString (), loc);
986
+ }
987
+ }
988
+
989
+ void unlock (FactSet &FSet, FactManager &FactMan, const CapabilityExpr &Cp,
990
+ SourceLocation loc, ThreadSafetyHandler *Handler,
991
+ StringRef DiagKind) const {
992
+ if (FSet.findLock (FactMan, Cp)) {
993
+ FSet.removeLock (FactMan, Cp);
994
+ FSet.addLock (FactMan, llvm::make_unique<LockableFactEntry>(
995
+ !Cp, LK_Exclusive, loc));
996
+ } else if (Handler) {
997
+ Handler->handleUnmatchedUnlock (DiagKind, Cp.toString (), loc);
998
+ }
999
+ }
967
1000
};
968
1001
969
1002
// / Class which implements the core thread safety analysis routines.
@@ -1911,7 +1944,8 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
1911
1944
std::back_inserter (SharedLocksToAdd));
1912
1945
Analyzer->addLock (FSet,
1913
1946
llvm::make_unique<ScopedLockableFactEntry>(
1914
- Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd),
1947
+ Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd,
1948
+ ExclusiveLocksToRemove, SharedLocksToRemove),
1915
1949
CapDiagKind);
1916
1950
}
1917
1951
}
0 commit comments