1e5dd7070Spatrick //===- ThreadSafety.h -------------------------------------------*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick // 9e5dd7070Spatrick // 10e5dd7070Spatrick // A intra-procedural analysis for thread safety (e.g. deadlocks and race 11e5dd7070Spatrick // conditions), based off of an annotation system. 12e5dd7070Spatrick // 13e5dd7070Spatrick // See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking 14e5dd7070Spatrick // for more information. 15e5dd7070Spatrick // 16e5dd7070Spatrick //===----------------------------------------------------------------------===// 17e5dd7070Spatrick 18e5dd7070Spatrick #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H 19e5dd7070Spatrick #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H 20e5dd7070Spatrick 21e5dd7070Spatrick #include "clang/Basic/SourceLocation.h" 22e5dd7070Spatrick #include "llvm/ADT/StringRef.h" 23e5dd7070Spatrick 24e5dd7070Spatrick namespace clang { 25e5dd7070Spatrick 26e5dd7070Spatrick class AnalysisDeclContext; 27e5dd7070Spatrick class FunctionDecl; 28e5dd7070Spatrick class NamedDecl; 29e5dd7070Spatrick 30e5dd7070Spatrick namespace threadSafety { 31e5dd7070Spatrick 32e5dd7070Spatrick class BeforeSet; 33e5dd7070Spatrick 34e5dd7070Spatrick /// This enum distinguishes between different kinds of operations that may 35e5dd7070Spatrick /// need to be protected by locks. We use this enum in error handling. 36e5dd7070Spatrick enum ProtectedOperationKind { 37e5dd7070Spatrick /// Dereferencing a variable (e.g. p in *p = 5;) 38e5dd7070Spatrick POK_VarDereference, 39e5dd7070Spatrick 40e5dd7070Spatrick /// Reading or writing a variable (e.g. x in x = 5;) 41e5dd7070Spatrick POK_VarAccess, 42e5dd7070Spatrick 43e5dd7070Spatrick /// Making a function call (e.g. fool()) 44e5dd7070Spatrick POK_FunctionCall, 45e5dd7070Spatrick 46e5dd7070Spatrick /// Passing a guarded variable by reference. 47e5dd7070Spatrick POK_PassByRef, 48e5dd7070Spatrick 49e5dd7070Spatrick /// Passing a pt-guarded variable by reference. 50e5dd7070Spatrick POK_PtPassByRef 51e5dd7070Spatrick }; 52e5dd7070Spatrick 53e5dd7070Spatrick /// This enum distinguishes between different kinds of lock actions. For 54e5dd7070Spatrick /// example, it is an error to write a variable protected by shared version of a 55e5dd7070Spatrick /// mutex. 56e5dd7070Spatrick enum LockKind { 57e5dd7070Spatrick /// Shared/reader lock of a mutex. 58e5dd7070Spatrick LK_Shared, 59e5dd7070Spatrick 60e5dd7070Spatrick /// Exclusive/writer lock of a mutex. 61e5dd7070Spatrick LK_Exclusive, 62e5dd7070Spatrick 63e5dd7070Spatrick /// Can be either Shared or Exclusive. 64e5dd7070Spatrick LK_Generic 65e5dd7070Spatrick }; 66e5dd7070Spatrick 67e5dd7070Spatrick /// This enum distinguishes between different ways to access (read or write) a 68e5dd7070Spatrick /// variable. 69e5dd7070Spatrick enum AccessKind { 70e5dd7070Spatrick /// Reading a variable. 71e5dd7070Spatrick AK_Read, 72e5dd7070Spatrick 73e5dd7070Spatrick /// Writing a variable. 74e5dd7070Spatrick AK_Written 75e5dd7070Spatrick }; 76e5dd7070Spatrick 77e5dd7070Spatrick /// This enum distinguishes between different situations where we warn due to 78e5dd7070Spatrick /// inconsistent locking. 79e5dd7070Spatrick /// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all 80e5dd7070Spatrick /// loop iterations. 81e5dd7070Spatrick /// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all 82e5dd7070Spatrick /// predecessors of a CFGBlock. 83e5dd7070Spatrick /// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a 84e5dd7070Spatrick /// function. 85e5dd7070Spatrick enum LockErrorKind { 86e5dd7070Spatrick LEK_LockedSomeLoopIterations, 87e5dd7070Spatrick LEK_LockedSomePredecessors, 88e5dd7070Spatrick LEK_LockedAtEndOfFunction, 89e5dd7070Spatrick LEK_NotLockedAtEndOfFunction 90e5dd7070Spatrick }; 91e5dd7070Spatrick 92e5dd7070Spatrick /// Handler class for thread safety warnings. 93e5dd7070Spatrick class ThreadSafetyHandler { 94e5dd7070Spatrick public: 95e5dd7070Spatrick using Name = StringRef; 96e5dd7070Spatrick 97e5dd7070Spatrick ThreadSafetyHandler() = default; 98e5dd7070Spatrick virtual ~ThreadSafetyHandler(); 99e5dd7070Spatrick 100e5dd7070Spatrick /// Warn about lock expressions which fail to resolve to lockable objects. 101e5dd7070Spatrick /// \param Loc -- the SourceLocation of the unresolved expression. handleInvalidLockExp(SourceLocation Loc)102*12c85518Srobert virtual void handleInvalidLockExp(SourceLocation Loc) {} 103e5dd7070Spatrick 104e5dd7070Spatrick /// Warn about unlock function calls that do not have a prior matching lock 105e5dd7070Spatrick /// expression. 106e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 107e5dd7070Spatrick /// \param LockName -- A StringRef name for the lock expression, to be printed 108e5dd7070Spatrick /// in the error message. 109e5dd7070Spatrick /// \param Loc -- The SourceLocation of the Unlock 110ec727ea7Spatrick /// \param LocPreviousUnlock -- If valid, the location of a previous Unlock. handleUnmatchedUnlock(StringRef Kind,Name LockName,SourceLocation Loc,SourceLocation LocPreviousUnlock)111e5dd7070Spatrick virtual void handleUnmatchedUnlock(StringRef Kind, Name LockName, 112ec727ea7Spatrick SourceLocation Loc, 113ec727ea7Spatrick SourceLocation LocPreviousUnlock) {} 114e5dd7070Spatrick 115e5dd7070Spatrick /// Warn about an unlock function call that attempts to unlock a lock with 116e5dd7070Spatrick /// the incorrect lock kind. For instance, a shared lock being unlocked 117e5dd7070Spatrick /// exclusively, or vice versa. 118e5dd7070Spatrick /// \param LockName -- A StringRef name for the lock expression, to be printed 119e5dd7070Spatrick /// in the error message. 120e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 121e5dd7070Spatrick /// \param Expected -- the kind of lock expected. 122e5dd7070Spatrick /// \param Received -- the kind of lock received. 123e5dd7070Spatrick /// \param LocLocked -- The SourceLocation of the Lock. 124e5dd7070Spatrick /// \param LocUnlock -- The SourceLocation of the Unlock. handleIncorrectUnlockKind(StringRef Kind,Name LockName,LockKind Expected,LockKind Received,SourceLocation LocLocked,SourceLocation LocUnlock)125e5dd7070Spatrick virtual void handleIncorrectUnlockKind(StringRef Kind, Name LockName, 126e5dd7070Spatrick LockKind Expected, LockKind Received, 127e5dd7070Spatrick SourceLocation LocLocked, 128e5dd7070Spatrick SourceLocation LocUnlock) {} 129e5dd7070Spatrick 130e5dd7070Spatrick /// Warn about lock function calls for locks which are already held. 131e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 132e5dd7070Spatrick /// \param LockName -- A StringRef name for the lock expression, to be printed 133e5dd7070Spatrick /// in the error message. 134e5dd7070Spatrick /// \param LocLocked -- The location of the first lock expression. 135e5dd7070Spatrick /// \param LocDoubleLock -- The location of the second lock expression. handleDoubleLock(StringRef Kind,Name LockName,SourceLocation LocLocked,SourceLocation LocDoubleLock)136e5dd7070Spatrick virtual void handleDoubleLock(StringRef Kind, Name LockName, 137e5dd7070Spatrick SourceLocation LocLocked, 138e5dd7070Spatrick SourceLocation LocDoubleLock) {} 139e5dd7070Spatrick 140e5dd7070Spatrick /// Warn about situations where a mutex is sometimes held and sometimes not. 141e5dd7070Spatrick /// The three situations are: 142e5dd7070Spatrick /// 1. a mutex is locked on an "if" branch but not the "else" branch, 143e5dd7070Spatrick /// 2, or a mutex is only held at the start of some loop iterations, 144e5dd7070Spatrick /// 3. or when a mutex is locked but not unlocked inside a function. 145e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 146e5dd7070Spatrick /// \param LockName -- A StringRef name for the lock expression, to be printed 147e5dd7070Spatrick /// in the error message. 148e5dd7070Spatrick /// \param LocLocked -- The location of the lock expression where the mutex is 149e5dd7070Spatrick /// locked 150e5dd7070Spatrick /// \param LocEndOfScope -- The location of the end of the scope where the 151e5dd7070Spatrick /// mutex is no longer held 152e5dd7070Spatrick /// \param LEK -- which of the three above cases we should warn for handleMutexHeldEndOfScope(StringRef Kind,Name LockName,SourceLocation LocLocked,SourceLocation LocEndOfScope,LockErrorKind LEK)153e5dd7070Spatrick virtual void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, 154e5dd7070Spatrick SourceLocation LocLocked, 155e5dd7070Spatrick SourceLocation LocEndOfScope, 156e5dd7070Spatrick LockErrorKind LEK) {} 157e5dd7070Spatrick 158e5dd7070Spatrick /// Warn when a mutex is held exclusively and shared at the same point. For 159e5dd7070Spatrick /// example, if a mutex is locked exclusively during an if branch and shared 160e5dd7070Spatrick /// during the else branch. 161e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 162e5dd7070Spatrick /// \param LockName -- A StringRef name for the lock expression, to be printed 163e5dd7070Spatrick /// in the error message. 164e5dd7070Spatrick /// \param Loc1 -- The location of the first lock expression. 165e5dd7070Spatrick /// \param Loc2 -- The location of the second lock expression. handleExclusiveAndShared(StringRef Kind,Name LockName,SourceLocation Loc1,SourceLocation Loc2)166e5dd7070Spatrick virtual void handleExclusiveAndShared(StringRef Kind, Name LockName, 167e5dd7070Spatrick SourceLocation Loc1, 168e5dd7070Spatrick SourceLocation Loc2) {} 169e5dd7070Spatrick 170e5dd7070Spatrick /// Warn when a protected operation occurs while no locks are held. 171e5dd7070Spatrick /// \param D -- The decl for the protected variable or function 172e5dd7070Spatrick /// \param POK -- The kind of protected operation (e.g. variable access) 173e5dd7070Spatrick /// \param AK -- The kind of access (i.e. read or write) that occurred 174e5dd7070Spatrick /// \param Loc -- The location of the protected operation. handleNoMutexHeld(const NamedDecl * D,ProtectedOperationKind POK,AccessKind AK,SourceLocation Loc)175*12c85518Srobert virtual void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK, 176*12c85518Srobert AccessKind AK, SourceLocation Loc) {} 177e5dd7070Spatrick 178e5dd7070Spatrick /// Warn when a protected operation occurs while the specific mutex protecting 179e5dd7070Spatrick /// the operation is not locked. 180e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 181e5dd7070Spatrick /// \param D -- The decl for the protected variable or function 182e5dd7070Spatrick /// \param POK -- The kind of protected operation (e.g. variable access) 183e5dd7070Spatrick /// \param LockName -- A StringRef name for the lock expression, to be printed 184e5dd7070Spatrick /// in the error message. 185e5dd7070Spatrick /// \param LK -- The kind of access (i.e. read or write) that occurred 186e5dd7070Spatrick /// \param Loc -- The location of the protected operation. 187e5dd7070Spatrick virtual void handleMutexNotHeld(StringRef Kind, const NamedDecl *D, 188e5dd7070Spatrick ProtectedOperationKind POK, Name LockName, 189e5dd7070Spatrick LockKind LK, SourceLocation Loc, 190e5dd7070Spatrick Name *PossibleMatch = nullptr) {} 191e5dd7070Spatrick 192e5dd7070Spatrick /// Warn when acquiring a lock that the negative capability is not held. 193e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 194e5dd7070Spatrick /// \param LockName -- The name for the lock expression, to be printed in the 195e5dd7070Spatrick /// diagnostic. 196e5dd7070Spatrick /// \param Neg -- The name of the negative capability to be printed in the 197e5dd7070Spatrick /// diagnostic. 198e5dd7070Spatrick /// \param Loc -- The location of the protected operation. handleNegativeNotHeld(StringRef Kind,Name LockName,Name Neg,SourceLocation Loc)199e5dd7070Spatrick virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, 200e5dd7070Spatrick SourceLocation Loc) {} 201e5dd7070Spatrick 202a9ac8606Spatrick /// Warn when calling a function that a negative capability is not held. 203a9ac8606Spatrick /// \param D -- The decl for the function requiring the negative capability. 204a9ac8606Spatrick /// \param LockName -- The name for the lock expression, to be printed in the 205a9ac8606Spatrick /// diagnostic. 206a9ac8606Spatrick /// \param Loc -- The location of the protected operation. handleNegativeNotHeld(const NamedDecl * D,Name LockName,SourceLocation Loc)207a9ac8606Spatrick virtual void handleNegativeNotHeld(const NamedDecl *D, Name LockName, 208a9ac8606Spatrick SourceLocation Loc) {} 209a9ac8606Spatrick 210e5dd7070Spatrick /// Warn when a function is called while an excluded mutex is locked. For 211e5dd7070Spatrick /// example, the mutex may be locked inside the function. 212e5dd7070Spatrick /// \param Kind -- the capability's name parameter (role, mutex, etc). 213e5dd7070Spatrick /// \param FunName -- The name of the function 214e5dd7070Spatrick /// \param LockName -- A StringRef name for the lock expression, to be printed 215e5dd7070Spatrick /// in the error message. 216e5dd7070Spatrick /// \param Loc -- The location of the function call. handleFunExcludesLock(StringRef Kind,Name FunName,Name LockName,SourceLocation Loc)217e5dd7070Spatrick virtual void handleFunExcludesLock(StringRef Kind, Name FunName, 218e5dd7070Spatrick Name LockName, SourceLocation Loc) {} 219e5dd7070Spatrick 220e5dd7070Spatrick /// Warn that L1 cannot be acquired before L2. handleLockAcquiredBefore(StringRef Kind,Name L1Name,Name L2Name,SourceLocation Loc)221e5dd7070Spatrick virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name, 222e5dd7070Spatrick Name L2Name, SourceLocation Loc) {} 223e5dd7070Spatrick 224e5dd7070Spatrick /// Warn that there is a cycle in acquired_before/after dependencies. handleBeforeAfterCycle(Name L1Name,SourceLocation Loc)225e5dd7070Spatrick virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {} 226e5dd7070Spatrick 227e5dd7070Spatrick /// Called by the analysis when starting analysis of a function. 228e5dd7070Spatrick /// Used to issue suggestions for changes to annotations. enterFunction(const FunctionDecl * FD)229e5dd7070Spatrick virtual void enterFunction(const FunctionDecl *FD) {} 230e5dd7070Spatrick 231e5dd7070Spatrick /// Called by the analysis when finishing analysis of a function. leaveFunction(const FunctionDecl * FD)232e5dd7070Spatrick virtual void leaveFunction(const FunctionDecl *FD) {} 233e5dd7070Spatrick issueBetaWarnings()234e5dd7070Spatrick bool issueBetaWarnings() { return IssueBetaWarnings; } setIssueBetaWarnings(bool b)235e5dd7070Spatrick void setIssueBetaWarnings(bool b) { IssueBetaWarnings = b; } 236e5dd7070Spatrick 237e5dd7070Spatrick private: 238e5dd7070Spatrick bool IssueBetaWarnings = false; 239e5dd7070Spatrick }; 240e5dd7070Spatrick 241e5dd7070Spatrick /// Check a function's CFG for thread-safety violations. 242e5dd7070Spatrick /// 243e5dd7070Spatrick /// We traverse the blocks in the CFG, compute the set of mutexes that are held 244e5dd7070Spatrick /// at the end of each block, and issue warnings for thread safety violations. 245e5dd7070Spatrick /// Each block in the CFG is traversed exactly once. 246e5dd7070Spatrick void runThreadSafetyAnalysis(AnalysisDeclContext &AC, 247e5dd7070Spatrick ThreadSafetyHandler &Handler, 248e5dd7070Spatrick BeforeSet **Bset); 249e5dd7070Spatrick 250e5dd7070Spatrick void threadSafetyCleanup(BeforeSet *Cache); 251e5dd7070Spatrick 252e5dd7070Spatrick /// Helper function that returns a LockKind required for the given level 253e5dd7070Spatrick /// of access. 254e5dd7070Spatrick LockKind getLockKindFromAccessKind(AccessKind AK); 255e5dd7070Spatrick 256e5dd7070Spatrick } // namespace threadSafety 257e5dd7070Spatrick } // namespace clang 258e5dd7070Spatrick 259e5dd7070Spatrick #endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H 260