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