xref: /openbsd-src/gnu/llvm/clang/include/clang/Analysis/Analyses/ThreadSafety.h (revision 12c855180aad702bbcca06e0398d774beeafb155)
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